Interface MetricsRecorder
- All Known Implementing Classes:
MicrometerMetricsRecorder,NoOpMetricsRecorder
- Functional Interface:
- This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
juneau-rest-server.
One record(...) call fires after every @RestOp handler invocation — including
exception paths. Bridge implementations translate the event into the format their downstream
registry expects (Micrometer io.micrometer.core.instrument.Timer, OpenTelemetry
metric instruments, Dropwizard MetricRegistry, etc.).
Off-by-default contract
juneau-rest-server resolves the MetricsRecorder via
RestContext.getBeanStore().getBean(MetricsRecorder.class). When no bean is supplied,
NoOpMetricsRecorder.INSTANCE is used and the framework never allocates a downstream
registry, never reaches Micrometer / OpenTelemetry on its own, and never adds any per-request
cost beyond a single static-field read. To opt in, the consumer registers a MetricsRecorder
bean — typically via @Bean MetricsRecorder on the resource or its parent.
Usage
Threading
Implementations must be thread-safe — the same MetricsRecorder bean is invoked
concurrently from every request thread for the lifetime of the RestContext. The framework
calls record(...) synchronously inside the request thread immediately after the response
status is known, so implementations should keep the call cheap (constant-time tag computation,
non-blocking registry writes).
Event ordering
For a given @RestOp invocation, record(...) fires exactly once after the operation
completes — whether the handler returned normally, threw a BasicHttpException, or
triggered an internal-server-error. The elapsed parameter measures wall-clock time spent
inside the framework's per-op invocation boundary (from just before parameter resolution to just
after the handler returns or throws). It does not include response serialization performed
later in the request pipeline.
See Also:
- Since:
- 10.0.0
-
Method Summary
-
Method Details
-
record
void record(String opName, String httpMethod, String uriTemplate, int statusCode, Duration elapsed, Throwable error, String metricName, String metricTags) Records one per-request metric event.- Parameters:
opName- The fully-qualified@RestOpmethod name (e.g."com.example.OrderResource.create(java.lang.String,com.example.Order)"). Nevernull ; never blank.httpMethod- The uppercased HTTP method of the request (e.g."GET","POST"). Nevernull ; never blank.uriTemplate- The@RestOppath template (e.g."/users/{id}"), not the raw concrete URI. Bridges should use this as theuritag to keep cardinality bounded. May be empty for resource-level operations that match/*; nevernull .statusCode- The HTTP response status code (e.g.200,404,500). If the handler threw before the status was set, this is the framework's inferred status (typically500for an unmapped exception, or the exception's status for aBasicHttpException).elapsed- Wall-clock duration of the@RestOpinvocation. Nevernull ; never negative.error- The exception thrown by the handler, ornull if the call completed normally. Bridges typically derive anexceptiontag from the throwable's simple class name, or"None"when null (mirrors Spring Boot'sWebMvcMetricsFilterconvention).metricName- Per-op metric name override fromRestOp.metricName(). Empty string (default) means the implementation should use its own default name derivation. Nevernull .metricTags- Per-op additional metric tags fromRestOp.metricTags(). Format: comma-separatedkey=valuepairs (e.g."team=payments,region=us-east"). Empty string (default) means no additional tags. Nevernull .
-
record
Records one custom (non-request) observation event.Unlike
record(String, String, String, int, Duration, Throwable, String, String), this entry point is not tied to an HTTP request — it is the substrate for the explicit programmatic observation API (Observations) so application code can time an arbitrary block of work. Bridge implementations record a timer namedmetricNamecarryingmetricTags(plus anexceptiontag derived fromerror).The default implementation does nothing — a bridge that does not override it simply does not record custom observations, and the no-backend path stays zero-allocation. The shipped Micrometer bridge overrides it.
- Parameters:
metricName- The timer name (e.g."order.load"). Nevernull ; never blank.metricTags- Additional tags as comma-separatedkey=valuepairs (e.g."team=payments,region=us-east"). Empty string means no additional tags. Nevernull .elapsed- Wall-clock duration of the observed block. Nevernull ; never negative.error- The exception thrown by the observed block, ornull if it completed normally.
-