-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement metrics endpoint in metrics lib (#42)
* Implement metrics endpoint in metrics lib * Add tests for metrics endpoint * Update METRICS.md * Add tests for metrics endpoint
- Loading branch information
1 parent
acd3834
commit a724899
Showing
7 changed files
with
186 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package kotlet.metrics | ||
|
||
import io.prometheus.metrics.config.PrometheusProperties | ||
import io.prometheus.metrics.model.registry.PrometheusRegistry | ||
import kotlet.Routing | ||
import kotlet.prometheus.PrometheusScrapeEndpointHandler | ||
|
||
/** | ||
* Install a scrape endpoint for Prometheus metrics. | ||
*/ | ||
fun Routing.installMetricsScrape(configure: MetricsScrapeConfigBuilder.() -> Unit = {}) { | ||
val builder = MetricsScrapeConfigBuilder() | ||
builder.configure() | ||
val config = builder.build() | ||
|
||
get(config.path, PrometheusScrapeEndpointHandler(config.config, config.registry)) | ||
} | ||
|
||
/** | ||
* Configuration for the scrape endpoint. | ||
*/ | ||
internal data class MetricsScrapeConfig( | ||
val path: String, | ||
val registry: PrometheusRegistry, | ||
val config: PrometheusProperties | ||
) | ||
|
||
/** | ||
* Builder for [MetricsScrapeConfig]. | ||
*/ | ||
class MetricsScrapeConfigBuilder internal constructor() { | ||
/** | ||
* Path to the scrape endpoint | ||
* Default: /metrics | ||
*/ | ||
var path: String = "/metrics" | ||
|
||
/** | ||
* Prometheus registry to scrape metrics from | ||
* Default: [PrometheusRegistry.defaultRegistry] | ||
*/ | ||
var registry: PrometheusRegistry = PrometheusRegistry.defaultRegistry | ||
|
||
/** | ||
* Prometheus configuration | ||
* Default: [PrometheusProperties.get] | ||
*/ | ||
var config: PrometheusProperties = PrometheusProperties.get() | ||
|
||
internal fun build(): MetricsScrapeConfig { | ||
return MetricsScrapeConfig( | ||
path = path, | ||
registry = registry, | ||
config = config, | ||
) | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
metrics/src/main/kotlin/kotlet/prometheus/PrometheusScrapeEndpointHandler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package kotlet.prometheus | ||
|
||
import io.prometheus.metrics.config.PrometheusProperties | ||
import io.prometheus.metrics.exporter.common.PrometheusScrapeHandler | ||
import io.prometheus.metrics.exporter.servlet.jakarta.HttpExchangeAdapter | ||
import io.prometheus.metrics.model.registry.PrometheusRegistry | ||
import kotlet.Handler | ||
import kotlet.HttpCall | ||
|
||
/** | ||
* Handler for Prometheus scrape endpoint. | ||
*/ | ||
internal class PrometheusScrapeEndpointHandler( | ||
config: PrometheusProperties, | ||
registry: PrometheusRegistry | ||
) : Handler { | ||
private val scrapeHandler = PrometheusScrapeHandler(config, registry) | ||
|
||
override fun invoke(call: HttpCall) { | ||
scrapeHandler.handleRequest(HttpExchangeAdapter(call.rawRequest, call.rawResponse)) | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
metrics/src/test/kotlin/kotlet/metrics/MetricsScrapeUnitTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package kotlet.metrics | ||
|
||
import io.prometheus.metrics.model.registry.PrometheusRegistry | ||
import kotlet.HttpMethod | ||
import kotlet.Kotlet | ||
import kotlet.mocks.Mocks | ||
import kotlet.prometheus.PrometheusMetricsCollector | ||
import java.time.Clock | ||
import java.time.Instant | ||
import java.time.ZoneId | ||
import kotlin.test.Test | ||
import kotlin.test.assertEquals | ||
|
||
class MetricsScrapeUnitTest { | ||
@Test | ||
fun testEndpoint() { | ||
val clock = Clock.fixed(Instant.now(), ZoneId.of("UTC")) | ||
val collector = PrometheusMetricsCollector(PrometheusRegistry.defaultRegistry, clock) | ||
|
||
val route = Kotlet.routing { | ||
installMetrics(collector) | ||
|
||
get("/", {}) | ||
|
||
installMetricsScrape { | ||
path = "/metrics" | ||
} | ||
} | ||
|
||
val servlet = Kotlet.servlet(listOf(route)) | ||
|
||
val getCall = Mocks.httpCall( | ||
method = HttpMethod.GET, | ||
routePath = "/" | ||
) | ||
servlet.service(getCall.rawRequest, getCall.rawResponse) | ||
|
||
val metricsCall = Mocks.httpCall( | ||
method = HttpMethod.GET, | ||
routePath = "/metrics" | ||
) | ||
servlet.service(metricsCall.rawRequest, metricsCall.rawResponse) | ||
|
||
val body = metricsCall.responseData.toString(Charsets.UTF_8) | ||
val expected = """ | ||
# HELP kotlet_http_requests_total Total number of HTTP requests | ||
# TYPE kotlet_http_requests_total counter | ||
kotlet_http_requests_total{method="GET",path="/",status="200"} 1.0 | ||
# HELP kotlet_http_requests_duration_seconds Duration of HTTP requests in seconds | ||
# TYPE kotlet_http_requests_duration_seconds summary | ||
kotlet_http_requests_duration_seconds{method="GET",path="/",status="200",quantile="0.5"} 0.0 | ||
kotlet_http_requests_duration_seconds{method="GET",path="/",status="200",quantile="0.9"} 0.0 | ||
kotlet_http_requests_duration_seconds{method="GET",path="/",status="200",quantile="0.95"} 0.0 | ||
kotlet_http_requests_duration_seconds{method="GET",path="/",status="200",quantile="0.99"} 0.0 | ||
kotlet_http_requests_duration_seconds_count{method="GET",path="/",status="200"} 1 | ||
kotlet_http_requests_duration_seconds_sum{method="GET",path="/",status="200"} 0.0 | ||
""".trimIndent() | ||
|
||
assertEquals(expected, body) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters