Metrics
Module for collecting application metrics using Micrometer.
It creates a PrometheusMeterRegistry, registers it in the dependency container as a MeterRegistry, and exposes the collected values in the Prometheus format through the system HTTP server.
This lets you collect application, JVM, process, and built-in integration metrics in one place and scrape them with an external observability system.
Publishing metrics requires the system HTTP server, which exposes them in the Prometheus format.
Module metrics are disabled by default
TelemetryConfig.MetricsConfig#enabled returns false, and every module inherits that default.
An application that only connects MetricsModule starts fine and answers /metrics with 200,
but the response contains only JVM, process, and kora.up values — no http_server_*, http_client_*,
db_* or any other component metric. Enable metrics explicitly per module with
<module>.telemetry.metrics.enabled = true, see Module metrics.
For a step-by-step walkthrough before the reference details, see Observability.
Dependency¶
Dependency build.gradle:
Module:
Dependency build.gradle.kts:
Module:
MetricsModule lives in the io.koraframework.micrometer.module package.
It only provides the registry and the scrape endpoint contract — the metric values themselves are produced by the modules you connect
(HTTP server, HTTP client, Database, Kafka and so on).
Configuration¶
The module itself has no configuration section: in Kora 2.0 there is no global metrics { } block.
Everything is configured in two places — the path and port of the scrape endpoint on the system server,
and a telemetry.metrics block inside each module that reports metrics.
Example of the system HTTP server path configuration described in the SystemHttpServerConfig class (default values are specified):
- Port of the system
HTTPserver that serves the metrics endpoint (default:8085). - Path for retrieving metrics in the
Prometheusformat (default:"/metrics").
Module metrics¶
Each metric-collecting module exposes a telemetry.metrics block described in TelemetryConfig.MetricsConfig,
letting you turn metrics on, tune histogram buckets, and attach extra tags for that module only.
The example below uses the HTTP server module as the host, but the same telemetry.metrics fields apply verbatim to
HTTP client, Database, Kafka, gRPC server,
gRPC client, Scheduling, Cache, Resilience,
and every other integration that reports metrics:
httpServer {
telemetry {
metrics {
enabled = true //(1)!
slo = ["1ms", "10ms", "50ms", "100ms", "200ms", "500ms", "1s", "2s", "5s", "10s", "20s", "30s", "60s", "90s"] //(2)!
tags { //(3)!
"key1" = "value1"
"key2" = "value2"
}
}
}
}
- Enables metric collection for the module (default:
false) - SLO histogram buckets for
Timermetrics, a list of durations (default:TelemetryConfig.MetricsConfig#DEFAULT_SLO, listed in Personalization) - Extra common tags added to every metric the module reports (default:
{})
httpServer:
telemetry:
metrics:
enabled: true #(1)!
slo: [ "1ms", "10ms", "50ms", "100ms", "200ms", "500ms", "1s", "2s", "5s", "10s", "20s", "30s", "60s", "90s" ] #(2)!
tags: #(3)!
key1: value1
key2: value2
- Enables metric collection for the module (default:
false) - SLO histogram buckets for
Timermetrics, a list of durations (default:TelemetryConfig.MetricsConfig#DEFAULT_SLO, listed in Personalization) - Extra common tags added to every metric the module reports (default:
{})
slo values are durations: a string carries its unit ("1ms", "250ms", "1s", PT1S), a bare number is read as milliseconds,
so slo = [1, 10, 50] and slo = ["1ms", "10ms", "50ms"] are the same list.
Leaving enabled = false (the default) means the module's telemetry uses a Noop metrics factory: no Meter is created and nothing is registered in the registry.
That is also the way to silence a noisy integration after you have enabled metrics globally.
Metrics are only produced when both conditions hold: MetricsModule is connected (so a MeterRegistry exists in the container)
and the module's telemetry.metrics.enabled is true. If either is missing, the module falls back to a no-op telemetry implementation.
Configuration paths¶
The telemetry.metrics block is nested under the module's own configuration section:
| Module | Configuration path |
|---|---|
| HTTP server (public) | httpServer.telemetry.metrics |
| HTTP server (system) | httpServer.system.telemetry.metrics |
| HTTP client | httpClient.telemetry.metrics and the client's own @HttpClient configuration path |
| JDBC database | jdbc.telemetry.metrics |
| Cassandra database | cassandra.telemetry.metrics |
| gRPC server | grpcServer.telemetry.metrics |
| gRPC client | grpcClient.<ServiceName>.telemetry.metrics |
| Scheduling | scheduling.telemetry.metrics |
| Resilience | resilient.telemetry.{circuitBreaker,retry,timeout,fallback,rateLimiter}.metrics |
| Kafka | the consumer's or publisher's own configuration path plus .telemetry.metrics |
| Cache | the cache's @Cache configuration path plus .telemetry.metrics |
| S3 client | s3client.aws.telemetry.metrics |
Redis (Lettuce) |
lettuce.telemetry.metrics |
| Camunda 7 BPMN | camunda.engine.bpmn.telemetry.metrics |
| Camunda 7 REST | camunda.rest.telemetry.metrics |
| Camunda 8 worker | zeebe.worker.telemetry.metrics |
Some modules add their own keys next to enabled / slo / tags:
- Database —
driverMetrics(default:true) registers theHikariCPpool metrics of the connection pool in the same registry. - Kafka —
driverMetrics(default:false) registers the nativeKafkaclient metrics through Micrometer'sKafkaClientMetricsbinder, under thekafka.*name prefix. - Camunda 7 BPMN —
engineMetrics(default:false) enables theCamundaengine's own metrics.
Metric collection parameters are also described in the modules that collect metrics: HTTP server, HTTP client, gRPC server, gRPC client, Scheduling, Cache, and other integrations.
Usage¶
Kora follows the notation described in the Prometheus specification.
After the module is connected, PrometheusMeterRegistry is created, registered in Metrics.globalRegistry, and used by all components that collect metrics.
When the application stops, this registry is removed from Metrics.globalRegistry and closed.
The registry is provided by the PrometheusMeterRegistryWrapper component, which is a Root component and implements Wrapped<MeterRegistry>,
so user code injects the MeterRegistry contract:
The registry automatically gets standard Micrometer binders: ClassLoaderMetrics, JvmMemoryMetrics, JvmGcMetrics, ProcessorMetrics, JvmThreadMetrics, FileDescriptorMetrics, UptimeMetrics.
These are bound when the registry is created and do not depend on any telemetry.metrics.enabled flag.
Kora also registers the kora.up metric with value 1 and the version tag.
Kora additionally bridges the Micrometer registry to an OpenTelemetry MeterProvider (MicrometerMeterProvider from io.opentelemetry.contrib.metrics.micrometer), so libraries instrumented with the OpenTelemetry metrics API publish through the same registry.
The bridge is a @DefaultComponent and accepts an optional CallbackRegistrar component if you need to control how asynchronous instruments are polled.
A runnable baseline that wires MetricsModule alongside HoconConfigModule, LogbackModule, JdbcDatabaseModule, UndertowPublicHttpServerModule, and the OpenTelemetry tracing exporter is available in the kora-java-telemetry example.
Prometheus export¶
Metrics are exposed in the Prometheus text format by the system HTTP server on httpServer.system.metricsPath (default /metrics) served at httpServer.system.port (default 8085):
Point your Prometheus scrape target (or any compatible collector) at the same host, port, and path.
The endpoint always answers 200. What it returns depends on what is bound in the container:
MetricsModuleconnected — thePrometheustext exposition of the registry snapshot.MetricsModulenot connected — the body# Metric Scraper disabled, because noMetricsScrapercomponent exists.- A custom
MeterRegistrythat is not aPrometheusMeterRegistry— an empty body, because that registry cannot be scraped in thePrometheusformat. Provide your ownMetricsScraperimplementation in that case: it overrides the@DefaultComponentsupplied byMetricsModule.
MetricsScraper is a single-method contract from the io.koraframework.telemetry.common package:
Custom metric¶
For a custom metric, it is better to create a separate component, inject MeterRegistry, and reuse created Meter instances.
Do not create a new metric on every method call: if the tag set depends on the operation, use a key with limited cardinality and cache the metric in ConcurrentHashMap.
The register(...) call is needed for initial metric registration in MeterRegistry; on the hot path, prefer using an already created Timer / Counter / Gauge and only call record(...) or increment(...).
Kora uses the same approach for its internal metrics.
For example, a duration metric for an external operation:
@Component
public final class ExternalOperationMetrics {
private record Key(String operation, String status) {}
private final MeterRegistry meterRegistry;
private final ConcurrentHashMap<Key, Timer> timers = new ConcurrentHashMap<>();
public ExternalOperationMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
public void record(String operation, String status, long durationNanos) {
var key = new Key(operation, status);
var timer = this.timers.computeIfAbsent(key, k -> Timer.builder("external.operation.duration")
.tag("operation", k.operation())
.tag("status", k.status())
.register(this.meterRegistry));
timer.record(durationNanos, TimeUnit.NANOSECONDS);
}
}
@Component
class ExternalOperationMetrics(
private val meterRegistry: MeterRegistry
) {
private data class Key(
val operation: String,
val status: String
)
private val timers = ConcurrentHashMap<Key, Timer>()
fun record(operation: String, status: String, durationNanos: Long) {
val key = Key(operation, status)
val timer = timers.computeIfAbsent(key) {
Timer.builder("external.operation.duration")
.tag("operation", it.operation)
.tag("status", it.status)
.register(meterRegistry)
}
timer.record(durationNanos, TimeUnit.NANOSECONDS)
}
}
Tag values must have a limited number of variants. Do not use user identifiers, request numbers, full error text, or other high-cardinality values as tags.
Personalization¶
To change PrometheusMeterRegistry configuration, add a PrometheusMeterRegistryInitializer to the container.
The initializer receives the created registry before standard system metrics are registered, so it can add common tags, MeterFilter, renaming rules, or custom PrometheusMeterRegistry settings.
All initializers found in the container are applied in sequence, each receiving the result of the previous one.
Important, PrometheusMeterRegistryInitializer is applied only once when the application is initialized.
For example, we want to add a common tag for all metrics:
Standard metrics also have their own settings, for example the slo histogram buckets for Timer metrics, configured per module under telemetry.metrics.
When slo is not overridden, TelemetryConfig.MetricsConfig#DEFAULT_SLO is used — 14 buckets:
1ms, 10ms, 50ms, 100ms, 200ms, 500ms, 1s, 2s, 5s, 10s, 20s, 30s, 60s, 90s
The array is declared in io.koraframework.telemetry.common.TelemetryConfig.MetricsConfig and shared by every module that builds a Timer.
Metric factories¶
The names and tags of framework metrics are produced by per-module metric factories, one Default<Module>MetricsFactory class per integration
(package <module>.telemetry.impl). Each module's telemetry factory accepts that class as an optional dependency,
so supplying your own subclass as a container component replaces the default one:
@Component
public final class TenantHttpServerMetricsFactory extends DefaultHttpServerMetricsFactory { //(1)!
@Override
public DefaultHttpServerMetrics create(DefaultHttpServerTelemetry.TelemetryContext context) {
return new TenantHttpServerMetrics(context);
}
private static final class TenantHttpServerMetrics extends DefaultHttpServerMetrics {
private TenantHttpServerMetrics(DefaultHttpServerTelemetry.TelemetryContext context) {
super(context);
}
@Override
protected Timer.Builder createMetricServerDuration(DurationKey metricKey, //(2)!
HttpServerRequest request,
HttpServerResponse response,
@Nullable Throwable throwable) {
return super.createMetricServerDuration(metricKey, request, response, throwable)
.tag("tenant", "default");
}
}
}
- The factory is picked up by
HttpServerModule#defaultHttpServerTelemetryFactoryin place of the built-inDefaultHttpServerMetricsFactory - Only static tags may be added in the builder — a tag whose value varies per request must be part of the metric key, otherwise different tag sets collide on one
Meter
@Component
class TenantHttpServerMetricsFactory : DefaultHttpServerMetricsFactory() { //(1)!
override fun create(context: DefaultHttpServerTelemetry.TelemetryContext): DefaultHttpServerMetrics {
return TenantHttpServerMetrics(context)
}
private class TenantHttpServerMetrics(
context: DefaultHttpServerTelemetry.TelemetryContext
) : DefaultHttpServerMetrics(context) {
override fun createMetricServerDuration( //(2)!
metricKey: DurationKey,
request: HttpServerRequest,
response: HttpServerResponse,
throwable: Throwable?
): Timer.Builder {
return super.createMetricServerDuration(metricKey, request, response, throwable)
.tag("tenant", "default")
}
}
}
- The factory is picked up by
HttpServerModule#defaultHttpServerTelemetryFactoryin place of the built-inDefaultHttpServerMetricsFactory - Only static tags may be added in the builder — a tag whose value varies per request must be part of the metric key, otherwise different tag sets collide on one
Meter
The same pattern applies to every integration, the class name follows the module:
DefaultHttpClientMetricsFactory, DefaultDatabaseMetricsFactory, DefaultKafkaConsumerMetricsFactory, DefaultKafkaPublisherMetricsFactory,
DefaultGrpcServerMetricsFactory, DefaultGrpcClientMetricsFactory, DefaultSoapClientMetricsFactory, DefaultSchedulingMetricsFactory,
DefaultCaffeineCacheMetricsFactory, DefaultRedisCacheMetricsFactory, DefaultCircuitBreakerMetricsFactory, DefaultRetryMetricsFactory,
DefaultTimeoutMetricsFactory, DefaultFallbackMetricsFactory, DefaultRateLimiterMetricsFactory, DefaultAwsS3ClientMetricsFactory,
DefaultJmsConsumerMetricsFactory.
When a tag has to depend on the current request, add it to the metric key instead of the builder:
every factory exposes create<Metric>Key(...) methods and key records with a withExtraTags(Tags) copy method for exactly that purpose.
If the extra tags are the same for every metric of a module, do not write a factory at all — use the telemetry.metrics.tags configuration key.
Standard¶
All Kora metrics follow the OpenTelemetry semantic conventions for names and tags,
and each module uses exactly one naming scheme — there is no configurable specification version.
Tag keys come from the io.opentelemetry.semconv attribute constants, so for example an HTTP server metric carries
http.request.method, http.route, url.scheme, server.address and error.type.
The Prometheus exposition names are derived from the Micrometer name by the Prometheus naming convention:
.is replaced with_;- a
Timergets the_secondssuffix, and the histogram is exposed as_bucket/_count/_sumseries plus a separate_maxgauge; - a
Countergets its base unit and the_totalsuffix (metrics built withBaseUnits.OPERATIONStherefore end with_operations_total); - a
Gaugegets its base unit as the suffix, if the metric declares one.
The error.type tag is always present on metrics that can fail — it holds the canonical exception class name, or an empty string on success.
Metrics reference¶
Micrometer metric types used:
- Timer — operation duration with count, sum, max, and histogram bucket support
- Counter — monotonically increasing counter
- Gauge — current metric value
Every metric listed below additionally carries the tags configured in that module's telemetry.metrics.tags.
HTTP server¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
http.server.request.duration |
http_server_request_duration_seconds / _count / _sum / _bucket / _max |
Timer | HTTP server request processing duration |
server.name, server.port, http.request.method, http.route, url.scheme, server.address, error.type |
http.server.active_requests |
http_server_active_requests |
Gauge | Number of active HTTP requests |
server.name, server.port, http.request.method, http.route, url.scheme, server.address |
server.name distinguishes the public server (kora-undertow) from the system one (kora-undertow-system); a request that matched no route reports http.route as UNKNOWN_ROUTE.
See HTTP server module documentation for more details.
HTTP client¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
http.client.request.duration |
http_client_request_duration_seconds / _count / _sum / _bucket / _max |
Timer | HTTP client request duration |
http.request.method, http.response.status_code, server.address, url.scheme, http.route, error.type, system.config, system.name.simple, system.name.canonical |
system.config is the client's configuration path, system.name.simple and system.name.canonical are the simple and canonical names of the declarative client interface.
See HTTP client module documentation for more details.
Database¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
db.client.operation.duration |
db_client_operation_duration_seconds / _count / _sum / _bucket / _max |
Timer | Database operation/query duration | db.client.connection.pool.name, db.system.name, db.query.text, db.operation.name, error.type |
db.system.name is taken from the connection string for JDBC (postgresql, mysql, ...) and is cassandra for Cassandra.
db.query.text holds the query identifier, not the raw SQL text.
With telemetry.metrics.driverMetrics = true (the default), the connection pool also registers its own metrics in the same registry:
HikariCP pool metrics for JDBC, and the DataStax driver metrics selected by cassandra.telemetry.metrics for Cassandra.
See Database module documentation for more details.
Kafka¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
messaging.process.duration |
messaging_process_duration_seconds / _count / _sum / _bucket / _max |
Timer | Single message processing duration | messaging.system, messaging.client.id, messaging.consumer.group.name, messaging.destination.name, messaging.destination.partition.id, error.type, system.config, system.name.simple, system.name.canonical |
messaging.process.batch.duration |
messaging_process_batch_duration_seconds / _count / _sum / _bucket / _max |
Timer | Message batch processing duration | messaging.system, messaging.client.id, messaging.consumer.group.name, error.type, system.config, system.name.simple, system.name.canonical |
messaging.kafka.consumer.lag |
messaging_kafka_consumer_lag |
Gauge | Consumer lag per partition | messaging.system, messaging.client.id, messaging.consumer.group.name, messaging.destination.name, messaging.destination.partition.id, system.config, system.name.simple, system.name.canonical |
messaging.client.operation.duration |
messaging_client_operation_duration_seconds / _count / _sum / _bucket / _max |
Timer | Message send duration | messaging.system, messaging.client.id, messaging.operation.type, messaging.destination.name, messaging.destination.partition.id, error.type, system.config, system.name.simple, system.name.canonical |
messaging.client.sent.messages |
messaging_client_sent_messages_total |
Counter | Number of sent messages | messaging.system, messaging.client.id, messaging.operation.type, messaging.destination.name, messaging.destination.partition.id, error.type, system.config, system.name.simple, system.name.canonical |
messaging.system is always kafka; messaging.operation.type on the publisher side is send.
See Kafka module documentation for more details.
gRPC server¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
rpc.server.duration |
rpc_server_duration_seconds / _count / _sum / _bucket / _max |
Timer | gRPC server call processing duration | server.name, server.port, rpc.system, rpc.service, rpc.method, rpc.grpc.status_code |
See gRPC server module documentation for more details.
gRPC client¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
rpc.client.duration |
rpc_client_duration_seconds / _count / _sum / _bucket / _max |
Timer | gRPC client call duration | rpc.system, rpc.service, rpc.method, rpc.grpc.status_code, server.address, server.port, error.type |
rpc.system is grpc for both the gRPC server and the gRPC client.
See gRPC client module documentation for more details.
SOAP client¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
rpc.client.duration |
rpc_client_duration_seconds / _count / _sum / _bucket / _max |
Timer | SOAP client call duration | rpc.system, rpc.service, rpc.method, server.address, server.port, http.response.status_code, error.type, fault.code, system.config, system.name.simple, system.name.canonical |
rpc.system is soap; fault.code holds the SOAP fault code and is empty when the call did not return a fault.
See SOAP client module documentation for more details.
Scheduling¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
scheduling.job.duration |
scheduling_job_duration_seconds / _count / _sum / _bucket / _max |
Timer | Scheduled job execution duration | code.function.name, system.name.simple, system.name.canonical, error.type, and system.config when the job declares a configuration path |
See Scheduling module documentation for more details.
Cache¶
Distributed Redis caches report their own operation metrics:
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
cache.operation.duration |
cache_operation_duration_seconds / _count / _sum / _bucket / _max |
Timer | Cache operation duration (GET, PUT, INVALIDATE, and others) |
origin, operation, error.type, system.config, system.name.simple, system.name.canonical |
cache.ratio |
cache_ratio_total |
Counter | Cache hit/miss counter | origin, operation, type, system.config, system.name.simple, system.name.canonical |
origin is redis, operation is the Cache contract operation name, and type on cache.ratio is hit or miss.
Caffeine caches do not report cache.operation.duration and cache.ratio — their telemetry delegates to the standard Micrometer cache binders,
which are attached to the underlying cache when telemetry.metrics.enabled = true:
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
cache.gets |
cache_gets_total |
Counter | Number of cache lookups | cache, result (hit / miss) |
cache.puts |
cache_puts_total |
Counter | Number of cache writes | cache |
cache.evictions |
cache_evictions_total |
Counter | Number of evicted entries | cache |
cache.eviction.weight |
cache_eviction_weight_total |
Counter | Total weight of evicted entries | cache |
cache.loads |
cache_loads_seconds / _count / _sum / _max |
Timer | Cache value load duration | cache, result (success / failure) |
cache.size |
cache_size |
Gauge | Current cache size | cache |
All Caffeine metrics carry the cache tag holding the cache name plus the tags from telemetry.metrics.tags.
See Cache module documentation for more details.
Redis / Lettuce¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
lettuce.command.completion.duration |
lettuce_command_completion_duration_seconds / _count / _sum / _bucket / _max |
Timer | Redis command completion duration | type, remote, command, error.type |
lettuce.command.firstresponse.duration |
lettuce_command_firstresponse_duration_seconds / _count / _sum / _bucket / _max |
Timer | Redis command first response duration | type, remote, command, error.type |
type distinguishes the client kind, remote is the address of the Redis node, command is the Redis command name.
On these two metrics error.type holds the Redis error text rather than an exception class name.
Resilience¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
resilient.circuitbreaker.state |
resilient_circuitbreaker_state |
Gauge | Circuit breaker state (0=CLOSED, 1=HALF_OPEN, 2=OPEN) | name |
resilient.circuitbreaker.transition |
resilient_circuitbreaker_transition_operations_total |
Counter | Transitions into OPEN and HALF_OPEN |
name, state |
resilient.circuitbreaker.call.acquire |
resilient_circuitbreaker_call_acquire_operations_total |
Counter | Calls admitted in HALF_OPEN and calls rejected in OPEN |
name, state, status |
resilient.circuitbreaker.call.result |
resilient_circuitbreaker_call_result_operations_total |
Counter | Call outcomes registered by the circuit breaker | name, state, status |
resilient.retry.attempts |
resilient_retry_attempts_operations_total |
Counter | Number of retry attempts | name |
resilient.retry.exhausted |
resilient_retry_exhausted_operations_total |
Counter | Number of exhausted retries | name, reason |
resilient.timeout.exhausted |
resilient_timeout_exhausted_operations_total |
Counter | Number of timeouts | name |
resilient.fallback.attempts |
resilient_fallback_attempts_operations_total |
Counter | Number of fallback invocations | name, type |
resilient.ratelimiter.acquire |
resilient_ratelimiter_acquire_operations_total |
Counter | Rate limiter permit acquisitions | name, status |
Tag values: status is PERMITTED / REJECTED / DISABLED on call.acquire and SUCCESS / FAILURE / IGNORED_FAILURE / FALLBACK on call.result;
reason is EXHAUSTED_ATTEMPTS or EXHAUSTED_BUDGET; the rate limiter's status is acquired or rejected; the fallback's type is executed.
See Resilience module documentation for more details.
JMS¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
messaging.receive.duration |
messaging_receive_duration_seconds / _count / _sum / _bucket / _max |
Timer | JMS message receive duration | messaging.system, messaging.destination.name, error.type |
messaging.system is always jms.
S3 client¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
rpc.client.duration |
rpc_client_duration_seconds / _count / _sum / _bucket / _max |
Timer | S3 client operation duration | rpc.system, rpc.method, aws.s3.bucket, error.type, system.path, system.name.simple, system.name.canonical |
rpc.system is s3-aws for the AWS based client. rpc.method is the S3 operation name and system.path is the client's configuration path.
See S3 client module documentation for more details.
Camunda 7 BPMN¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
camunda.engine.delegate.duration |
camunda_engine_delegate_duration_seconds / _count / _sum / _bucket / _max |
Timer | Camunda BPMN Java delegate execution duration | delegate, error.type |
The engine's own metrics are published separately and require camunda.engine.bpmn.telemetry.metrics.engineMetrics = true.
See Camunda 7 BPMN module documentation for more details.
Camunda REST¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
camunda.rest.request.duration |
camunda_rest_request_duration_seconds / _count / _sum / _bucket / _max |
Timer | Camunda REST request duration |
http.request.method, http.response.status_code, http.route, url.scheme, server.address, http.response.result_code, error.type |
camunda.rest.active_requests |
camunda_rest_active_requests |
Gauge | Number of active Camunda REST requests | http.request.method, http.route, url.scheme, server.address |
See Camunda 7 REST module documentation for more details.
Camunda 8 worker¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
zeebe.worker.handler.duration |
zeebe_worker_handler_duration_seconds / _count / _sum / _bucket / _max |
Timer | Zeebe Worker job handler duration |
job.name, job.type, error.type |
The Camunda client additionally publishes its own worker job metrics into the same registry, tagged with the job type.
See Camunda 8 worker module documentation for more details.
System¶
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
kora.up |
kora_up |
Gauge | Framework status indicator (value = 1) | version |
JVM¶
Standard JVM and process metrics are collected automatically by the Micrometer binders bound to the registry at startup.
They do not depend on any module's telemetry.metrics.enabled setting:
| Metric | Prometheus | Type | Description | Tags |
|---|---|---|---|---|
jvm.memory.used |
jvm_memory_used_bytes |
Gauge | Used memory | area, id |
jvm.memory.committed |
jvm_memory_committed_bytes |
Gauge | Committed JVM memory | area, id |
jvm.memory.max |
jvm_memory_max_bytes |
Gauge | Max available memory | area, id |
jvm.buffer.count |
jvm_buffer_count_buffers |
Gauge | Number of buffers in the pool | id |
jvm.buffer.memory.used |
jvm_buffer_memory_used_bytes |
Gauge | Memory used by buffers | id |
jvm.buffer.total.capacity |
jvm_buffer_total_capacity_bytes |
Gauge | Total buffer pool capacity | id |
jvm.gc.pause |
jvm_gc_pause_seconds / _count / _sum / _max |
Timer | GC pause duration | gc, action, cause |
jvm.gc.concurrent.phase.time |
jvm_gc_concurrent_phase_time_seconds / _count / _sum / _max |
Timer | Concurrent GC phase duration | gc, action, cause |
jvm.gc.memory.allocated |
jvm_gc_memory_allocated_bytes_total |
Counter | Allocated memory size | — |
jvm.gc.memory.promoted |
jvm_gc_memory_promoted_bytes_total |
Counter | Memory promoted to old gen (generational collectors only) | — |
jvm.gc.max.data.size |
jvm_gc_max_data_size_bytes |
Gauge | Max old gen size | — |
jvm.gc.live.data.size |
jvm_gc_live_data_size_bytes |
Gauge | Old gen size after full GC | — |
jvm.threads.live |
jvm_threads_live_threads |
Gauge | Number of live threads | — |
jvm.threads.daemon |
jvm_threads_daemon_threads |
Gauge | Number of daemon threads | — |
jvm.threads.peak |
jvm_threads_peak_threads |
Gauge | Peak thread count | — |
jvm.threads.started |
jvm_threads_started_threads_total |
Counter | Number of started threads | — |
jvm.threads.states |
jvm_threads_states_threads |
Gauge | Thread count by state | state |
jvm.classes.loaded |
jvm_classes_loaded_classes |
Gauge | Number of currently loaded classes | — |
jvm.classes.loaded.count |
jvm_classes_loaded_count_classes_total |
Counter | Number of classes loaded since start | — |
jvm.classes.unloaded |
jvm_classes_unloaded_classes_total |
Counter | Number of unloaded classes | — |
process.cpu.usage |
process_cpu_usage |
Gauge | Process CPU usage | — |
system.cpu.usage |
system_cpu_usage |
Gauge | System CPU usage | — |
system.cpu.count |
system_cpu_count |
Gauge | Number of available processors | — |
system.load.average.1m |
system_load_average_1m |
Gauge | System load average over one minute | — |
process.files.open |
process_files_open_files |
Gauge | Number of open file descriptors | — |
process.files.max |
process_files_max_files |
Gauge | Max file descriptors | — |
process.uptime |
process_uptime_seconds |
Gauge | Process uptime | — |
process.start.time |
process_start_time_seconds |
Gauge | Process start time since the Unix epoch | — |
Some of these are registered only when the running JVM and operating system expose the corresponding MXBean value, so the exact set of series in a scrape depends on the platform.