Skip to content

Commit 9ba5c32

Browse files
authored
Merge pull request #10 from navikt/influxdb
Influxdb
2 parents f100d63 + d67b8fb commit 9ba5c32

File tree

8 files changed

+248
-1
lines changed

8 files changed

+248
-1
lines changed
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
plugins {
2+
`maven-publish`
3+
`java-library`
4+
kotlin("jvm")
5+
}
6+
7+
repositories {
8+
jcenter()
9+
mavenCentral()
10+
mavenLocal()
11+
}
12+
13+
publishing {
14+
repositories {
15+
maven {
16+
url = uri("https://maven.pkg.github.com/navikt/dittnav-common-lib")
17+
credentials {
18+
username = "x-access-token"
19+
password = System.getenv("GITHUB_TOKEN")
20+
}
21+
}
22+
}
23+
publications {
24+
create<MavenPublication>("gpr") {
25+
from(components["java"])
26+
}
27+
}
28+
}
29+
30+
dependencies {
31+
api(kotlin("stdlib-jdk8"))
32+
implementation(Influxdb.java)
33+
implementation(Kotlinx.coroutines)
34+
implementation(Logback.classic)
35+
implementation(Logstash.logbackEncoder)
36+
testImplementation(kotlin("test-junit5"))
37+
testImplementation(Junit.api)
38+
testImplementation(Junit.engine)
39+
testImplementation(Kluent.kluent)
40+
testImplementation(Mockk.mockk)
41+
}
42+
43+
tasks {
44+
compileKotlin {
45+
kotlinOptions.jvmTarget = "13"
46+
}
47+
compileTestKotlin {
48+
kotlinOptions.jvmTarget = "13"
49+
}
50+
51+
withType<Test> {
52+
useJUnitPlatform()
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package no.nav.personbruker.dittnav.common.metrics
2+
3+
interface MetricsReporter {
4+
suspend fun registerDataPoint(measurementName: String, fields: Map<String, Any>, tags: Map<String, String>)
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package no.nav.personbruker.dittnav.common.metrics
2+
3+
import org.slf4j.LoggerFactory
4+
5+
6+
class StubMetricsReporter : MetricsReporter {
7+
8+
val log = LoggerFactory.getLogger(StubMetricsReporter::class.java)
9+
10+
override suspend fun registerDataPoint(measurementName: String, fields: Map<String, Any>, tags: Map<String, String>) {
11+
log.debug("Data point: { measurement: $measurementName, fields: $fields, tags: $tags }")
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package no.nav.personbruker.dittnav.common.metrics.influxdb
2+
3+
import kotlinx.coroutines.Dispatchers
4+
import kotlinx.coroutines.withContext
5+
import org.influxdb.InfluxDB
6+
import org.influxdb.InfluxDBFactory
7+
import org.influxdb.dto.Point
8+
import org.slf4j.LoggerFactory
9+
10+
internal class DataPointRelay(private val influxDB: InfluxDB) {
11+
12+
private val log = LoggerFactory.getLogger(DataPointRelay::class.java)
13+
14+
suspend fun submitDataPoint(point: Point) = withContext(Dispatchers.IO) {
15+
try {
16+
influxDB.write(point)
17+
} catch (e: Exception) {
18+
log.warn("Klarte ikke skrive event til InfluxDB.", e)
19+
}
20+
}
21+
}
22+
23+
internal object DataPointRelayFactory {
24+
25+
internal fun createDataPointRelay(influxConfig: InfluxConfig): DataPointRelay {
26+
val influxDb = InfluxDBFactory.connect(
27+
"https://${influxConfig.hostName}:${influxConfig.hostPort}",
28+
influxConfig.userName,
29+
influxConfig.password
30+
)
31+
32+
influxDb.setDatabase(influxConfig.databaseName)
33+
34+
influxDb.setRetentionPolicy(influxConfig.retentionPolicyName)
35+
36+
if (influxConfig.enableEventBatching) {
37+
influxDb.enableBatch()
38+
} else {
39+
influxDb.disableBatch()
40+
}
41+
42+
return DataPointRelay(influxDb)
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package no.nav.personbruker.dittnav.common.metrics.influxdb
2+
3+
data class InfluxConfig (
4+
val hostName: String,
5+
val userName: String,
6+
val password: String,
7+
val hostPort: Int,
8+
val databaseName: String,
9+
val retentionPolicyName: String,
10+
val applicationName: String,
11+
val clusterName: String,
12+
val namespace: String,
13+
val enableEventBatching: Boolean = true,
14+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package no.nav.personbruker.dittnav.common.metrics.influxdb
2+
3+
import no.nav.personbruker.dittnav.common.metrics.MetricsReporter
4+
import org.influxdb.dto.Point
5+
import java.util.concurrent.TimeUnit
6+
7+
class InfluxMetricsReporter internal constructor(influxConfig: InfluxConfig, private val dataPointRelay: DataPointRelay) : MetricsReporter {
8+
9+
constructor(influxConfig: InfluxConfig) : this(influxConfig, DataPointRelayFactory.createDataPointRelay(influxConfig))
10+
11+
override suspend fun registerDataPoint(measurementName: String, fields: Map<String, Any>, tags: Map<String, String>) {
12+
val point = Point.measurement(measurementName)
13+
.time(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
14+
.tag(tags)
15+
.tag(DEFAULT_TAGS)
16+
.fields(fields)
17+
.build()
18+
19+
dataPointRelay.submitDataPoint(point)
20+
}
21+
22+
private val DEFAULT_TAGS = listOf(
23+
"application" to influxConfig.applicationName,
24+
"cluster" to influxConfig.clusterName,
25+
"namespace" to influxConfig.namespace
26+
).toMap()
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package no.nav.personbruker.dittnav.common.metrics.influxdb
2+
3+
import io.mockk.coEvery
4+
import io.mockk.mockk
5+
import io.mockk.slot
6+
import kotlinx.coroutines.runBlocking
7+
import org.amshove.kluent.*
8+
import org.influxdb.dto.Point
9+
import org.junit.jupiter.api.Test
10+
import java.util.concurrent.TimeUnit
11+
12+
internal class InfluxMetricsReporterTest {
13+
val dataPointRelay: DataPointRelay = mockk()
14+
15+
val databaseName = "testdb"
16+
val retentionPolicyName = "retention"
17+
val application = "testApp"
18+
val cluster = "test"
19+
val namespace = "test1"
20+
21+
val influxConfig = InfluxConfig(
22+
"",
23+
"",
24+
"",
25+
0,
26+
databaseName,
27+
retentionPolicyName,
28+
application,
29+
cluster,
30+
namespace
31+
)
32+
33+
val metricsReporter = InfluxMetricsReporter(influxConfig, dataPointRelay)
34+
35+
@Test
36+
fun `Should construct a data point and add time of measurement and application-global tags`() {
37+
38+
val pointSlot = slot<Point>()
39+
40+
val measurementName = "INVENTORY"
41+
42+
val fieldName = "value"
43+
val fieldVal = 123
44+
45+
val tagName = "type"
46+
val tagVal = "APPLE"
47+
48+
coEvery { dataPointRelay.submitDataPoint(capture(pointSlot)) } returns Unit
49+
50+
val fields = mapOf(fieldName to fieldVal)
51+
val tags = mapOf(tagName to tagVal)
52+
53+
val start = System.currentTimeMillis()
54+
55+
runBlocking {
56+
metricsReporter.registerDataPoint(measurementName, fields, tags)
57+
}
58+
59+
val point = pointSlot.captured
60+
61+
val resultMeasurement: String = point.getPrivateField("measurement")
62+
val resultFields: Map<String, Any> = point.getPrivateField("fields")
63+
val resultTags: Map<String, String> = point.getPrivateField("tags")
64+
val resultTime: Long = point.getPrivateField("time")
65+
val resultPrecision: TimeUnit = point.getPrivateField("precision")
66+
67+
val end = System.currentTimeMillis()
68+
69+
70+
resultMeasurement `should be equal to` measurementName
71+
resultFields `should be equal to` fields
72+
resultTags.values `should contain same` listOf(application, cluster, namespace, tagVal)
73+
resultTime `should be greater or equal to` start
74+
resultTime `should be less or equal to` end
75+
resultPrecision `should be equal to` TimeUnit.MILLISECONDS
76+
}
77+
78+
private inline fun <reified T: Any> Point.getPrivateField(fieldName: String): T {
79+
return this::class.java.getDeclaredField(fieldName).let {
80+
it.isAccessible = true
81+
val field = it.get(this)
82+
83+
if (field is T) {
84+
field
85+
} else {
86+
throw TypeCastException("Could not fetch private field '$fieldName' as ${T::class.simpleName}")
87+
}
88+
}
89+
}
90+
}

settings.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
rootProject.name = "dittnav-common-lib"
22
include("dittnav-common-logging")
33
include("dittnav-common-influx")
4+
include("dittnav-common-influxdb")
45
include("dittnav-common-security-authenticated-user")
5-
include("dittnav-common-test")
66
include("dittnav-common-utils")
77
include("dittnav-common-evicting-cache")

0 commit comments

Comments
 (0)