Metrics
The Wow framework integrates Reactor and Micrometer metrics for its core reactive components.
Installation
implementation("io.micrometer:micrometer-core")implementation 'io.micrometer:micrometer-core'<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>Automatic Metrics Collection
The Wow framework automatically collects metrics for the following components:
The names below are Reactor publisher base names. Reactor creates meters such as <base>.subscribed, <base>.requested, <base>.onNext.delay, and <base>.flow.duration according to the publisher type.
Command Metrics
wow.command.sendwow.command.receivewow.command.handle
Event Bus Metrics
wow.event.sendwow.event.receivewow.event.handlewow.state.sendwow.state.receive
Event Store Metrics
wow.eventstore.append: Event append count and latencywow.eventstore.load: Event load count and latencywow.eventstore.lastwow.eventstore.exists.request.idwow.eventstore.scanAggregateId
Snapshot Metrics
wow.snapshot.save: Snapshot save count and latencywow.snapshot.load: Snapshot load count and latencywow.snapshot.getVersionwow.snapshot.checkpoint.savewow.snapshot.checkpoint.loadwow.snapshot.eventwow.snapshot.handle
Handler Metrics
wow.projection.handlewow.saga.handlewow.dispatcher
Metrics Tags
Tags depend on the operation. Wow-defined tags are:
source: Original decorated component typeaggregate: Aggregate name, or a canonical sorted aggregate list for receive publisherscommand: Command name on command send/handle publishersevent: Event name on event handlersprocessor: Processor name on handler publisherssubscriber: Subscriber identity on receive publishers; the Reactor context value overrides the subscription receiver groupdispatcher: Dispatcher name on dispatcher publishers
Reactor adds tags such as type, status, and exception depending on the generated meter. Internal dispatcher routing keys are intentionally not exported as tags because they multiply time-series cardinality. A bounded-context tag is not currently emitted.
Storage Routing Ownership
When aggregate-specific storage routing is enabled, event-store and snapshot-store metrics are recorded only by the selected leaf backend. RoutingEventStore and RoutingSnapshotStore are metric-transparent, so one storage operation produces one set of meters and the source tag identifies the physical backend such as MongoEventStore or RedisEventStore.
Dashboards that previously selected source=RoutingEventStore or source=RoutingSnapshotStore must switch to the physical backend source. Queries that aggregate across source no longer double-count routed operations.
Custom Metrics
Manual Metrics Collection
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Timer
@Service
class OrderService(
private val meterRegistry: MeterRegistry,
private val commandGateway: CommandGateway
) {
private val orderCreationTimer = Timer.builder("wow.business.order.creation")
.description("Order creation duration")
.register(meterRegistry)
fun createOrder(request: CreateOrderRequest): Mono<OrderSummary> {
return Mono.fromCallable {
Timer.Sample.start(meterRegistry)
}.flatMap { sample ->
commandGateway.sendAndWait(createOrderCommand, CommandWait.processed(createOrderCommand.commandId))
.doOnSuccess { result ->
sample.stop(orderCreationTimer)
// Business success metrics
meterRegistry.counter("wow.business.order.created").increment()
}
.doOnError { error ->
sample.stop(orderCreationTimer)
// Business failure metrics
meterRegistry.counter("wow.business.order.failed").increment()
}
}
}
}Reactive Stream Metrics
fun <T> Flux<T>.tagMetrics(operation: String): Flux<T> {
return this.name(operation)
.metrics()
}
fun <T> Mono<T>.tagMetrics(operation: String): Mono<T> {
return this.name(operation)
.metrics()
}Configuration
Micrometer Configuration
management:
metrics:
export:
prometheus:
enabled: true
tags:
application: ${spring.application.name}Wow Metrics Configuration
Wow framework metrics collection is enabled by default and can be controlled as follows:
wow:
metrics:
enabled: true # Enabled by defaultWow's current Reactor decorators write to Micrometer's global registry. Keep Spring Boot's global-registry bridge enabled so application registries receive these meters. Explicit application-registry injection is planned for a future metrics integration revision.
Monitoring Dashboard
Prometheus + Grafana
Use Prometheus to collect metrics and Grafana to create dashboards:
# Prometheus configuration
scrape_configs:
- job_name: 'wow-application'
static_configs:
- targets: ['localhost:8080']
metrics_path: '/actuator/prometheus'Common Queries
Exporter naming depends on the registry. Inspect /actuator/metrics or the target registry first, then build queries from the generated Reactor suffixes such as flow.duration and onNext.delay.
Performance Impact
- Lightweight: Metrics collection uses efficient counters and histograms
- Asynchronous: Does not block business logic execution
- Configurable: Can enable or disable specific metrics as needed
Best Practices
- Choose appropriate metrics: Only collect metrics that are truly needed
- Set reasonable tags: Avoid performance issues caused by too many tags
- Monitoring alerts: Set alert thresholds for critical business metrics
- Regular review: Regularly review and clean up metrics that are no longer needed
Troubleshooting
Metrics Not Showing
Check:
- Whether Micrometer dependencies are correctly added
- Whether the MeterRegistry Bean is correctly configured and connected to Micrometer's global registry
- Whether
/actuator/metricsendpoint is accessible
Performance Issues
If metrics collection affects performance:
- Reduce the number of metrics collected
- Use sampling rates instead of full collection
- Consider asynchronous metrics collection