Skip to content

Commit 12d451c

Browse files
committed
Merge branch '1.15.x' into 1.16.x
2 parents 232114c + b2c9cd6 commit 12d451c

3 files changed

Lines changed: 79 additions & 4 deletions

File tree

.circleci/config.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,29 @@ executors:
1414
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2g -XX:+HeapDumpOnOutOfMemoryError" -Dorg.gradle.workers.max=2'
1515
resource_class: medium+
1616
docker:
17-
- image: cimg/openjdk:21.0.8
17+
- image: cimg/openjdk:21.0.9
1818
circle-jdk17-executor:
1919
working_directory: ~/micrometer
2020
environment:
2121
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2g -XX:+HeapDumpOnOutOfMemoryError" -Dorg.gradle.workers.max=2'
2222
resource_class: medium+
2323
docker:
24-
- image: cimg/openjdk:17.0.16
24+
- image: cimg/openjdk:17.0.17
2525
circle-jdk11-executor:
2626
working_directory: ~/micrometer
2727
environment:
2828
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2g -XX:+HeapDumpOnOutOfMemoryError" -Dorg.gradle.workers.max=2'
2929
resource_class: medium+
3030
docker:
31-
- image: cimg/openjdk:11.0.28
31+
- image: cimg/openjdk:11.0.29
3232
# JCStress spawns multiple test JVMs; use larger instance to avoid daemon OOM
3333
concurrency-tests-executor:
3434
working_directory: ~/micrometer
3535
environment:
3636
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2g -XX:+HeapDumpOnOutOfMemoryError" -Dorg.gradle.workers.max=2'
3737
resource_class: large
3838
docker:
39-
- image: cimg/openjdk:21.0.8
39+
- image: cimg/openjdk:21.0.9
4040
machine-executor:
4141
working_directory: ~/micrometer
4242
machine:

docs/modules/ROOT/pages/observation/components.adoc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ In this section we will describe main components related to Micrometer Observati
55

66
* <<micrometer-observation-context, Observation Context>>
77
* <<micrometer-observation-handler, Observation Handler>>
8+
* <<micrometer-observation-default-meter-handler, DefaultMeterObservationHandler>>
89
* <<micrometer-observation-events, Signaling Errors and Arbitrary Events>>
910
* <<micrometer-observation-convention-example, Observation Convention>>
1011
* <<micrometer-observation-predicates-filters, Observation Predicates and Filters>>
@@ -119,6 +120,34 @@ You can also take full control of the scoping mechanism:
119120
include::{include-java}/observation/ObservationHandlerTests.java[tags=manual_scoping,indent=0]
120121
-----
121122

123+
[[micrometer-observation-default-meter-handler]]
124+
=== DefaultMeterObservationHandler
125+
126+
Micrometer provides `DefaultMeterObservationHandler`, an `ObservationHandler` implementation that automatically creates metrics from Observations.
127+
When registered on an `ObservationRegistry`, it translates Observation lifecycle events into the following meter types:
128+
129+
* **Timer** (`<observation-name>`) -- Created on `stop`. Records the duration between `start` and `stop`. Tagged with all low cardinality key values and an `error` tag (set to the exception class name if an error was recorded, or `none` otherwise).
130+
* **LongTaskTimer** (`<observation-name>.active`) -- Created on `start`. Tracks the duration of in-progress observations. Stopped when the observation is stopped. Only tagged with low cardinality key values that are available at the time of `start`.
131+
* **Counter** (`<observation-name>.<event-name>`) -- Incremented when an event is signaled via `Observation.event(Event)`. Tagged with all low cardinality key values available at the time of the event.
132+
133+
NOTE: Only low cardinality key values are used as meter tags. High cardinality key values are not included in meters because they can cause a cardinality explosion in the metrics backend.
134+
135+
WARNING: Since the `LongTaskTimer` is created in the `onStart` method, it can only contain tags that are available by that time. Any low cardinality key values added after calling `start` on the `Observation` will not be included as tags on the `LongTaskTimer`.
136+
137+
The following example shows how to register `DefaultMeterObservationHandler` and the metrics it creates:
138+
139+
[source,java,subs=+attributes]
140+
-----
141+
include::{include-java}/observation/ObservationHandlerTests.java[tags=default_meter_handler,indent=0]
142+
-----
143+
144+
If you do not need the `LongTaskTimer` (for example, to reduce the number of created meters), you can disable it using `IgnoredMeters`:
145+
146+
[source,java,subs=+attributes]
147+
-----
148+
include::{include-java}/observation/ObservationHandlerTests.java[tags=default_meter_handler_ignore_ltt,indent=0]
149+
-----
150+
122151
[[micrometer-observation-events]]
123152
== Signaling Errors and Arbitrary Events
124153

docs/src/test/java/io/micrometer/docs/observation/ObservationHandlerTests.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,52 @@ void manual_scoping() {
109109
// end::manual_scoping[]
110110
}
111111

112+
@Test
113+
void default_meter_observation_handler() {
114+
// tag::default_meter_handler[]
115+
MeterRegistry meterRegistry = new SimpleMeterRegistry();
116+
ObservationRegistry registry = ObservationRegistry.create();
117+
// Register DefaultMeterObservationHandler to create metrics from observations
118+
registry.observationConfig().observationHandler(new DefaultMeterObservationHandler(meterRegistry));
119+
120+
// Perform an observation
121+
Observation observation = Observation.createNotStarted("my.operation", registry)
122+
.lowCardinalityKeyValue("region", "us-east-1");
123+
observation.start(); // LongTaskTimer "my.operation.active" starts here
124+
observation.event(Observation.Event.of("my.event")); // Counter
125+
// "my.operation.my.event"
126+
// incremented
127+
observation.stop(); // Timer "my.operation" and LongTaskTimer stop
128+
129+
// Verify metrics were created:
130+
// Timer: my.operation (with tags: region=us-east-1, error=none)
131+
assertThat(meterRegistry.get("my.operation").timer().count()).isEqualTo(1);
132+
// Counter: my.operation.my.event (with tags: region=us-east-1)
133+
assertThat(meterRegistry.get("my.operation.my.event").counter().count()).isEqualTo(1);
134+
// end::default_meter_handler[]
135+
}
136+
137+
@Test
138+
void default_meter_observation_handler_ignore_long_task_timer() {
139+
// tag::default_meter_handler_ignore_ltt[]
140+
MeterRegistry meterRegistry = new SimpleMeterRegistry();
141+
ObservationRegistry registry = ObservationRegistry.create();
142+
// You can disable the LongTaskTimer if you don't need it
143+
registry.observationConfig()
144+
.observationHandler(new DefaultMeterObservationHandler(meterRegistry,
145+
DefaultMeterObservationHandler.IgnoredMeters.LONG_TASK_TIMER));
146+
147+
Observation.createNotStarted("my.operation", registry)
148+
.lowCardinalityKeyValue("region", "us-east-1")
149+
.start()
150+
.stop();
151+
152+
// Timer is created, but no LongTaskTimer
153+
assertThat(meterRegistry.get("my.operation").timer().count()).isEqualTo(1);
154+
assertThat(meterRegistry.find("my.operation.active").longTaskTimer()).isNull();
155+
// end::default_meter_handler_ignore_ltt[]
156+
}
157+
112158
@Test
113159
void error_and_event() {
114160
// tag::error_and_event[]

0 commit comments

Comments
 (0)