Skip to content

Commit 5ecf892

Browse files
authored
(docs): add document for JMS instrumentation (#6138)
Relates to #5988 Signed-off-by: Alexey Elin <[email protected]>
1 parent 348bb14 commit 5ecf892

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

docs/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
** xref:reference/httpcomponents.adoc[HttpComponents Client]
4545
** xref:reference/java-httpclient.adoc[Java HttpClient]
4646
** xref:reference/jetty.adoc[Jetty and Jersey]
47+
** xref:reference/jms.adoc[JMS]
4748
** xref:reference/jvm.adoc[JVM]
4849
** xref:reference/kafka.adoc[Kafka]
4950
** xref:reference/logging.adoc[Logging]
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
= JMS Instrumentation
2+
3+
Micrometer provides JMS instrumentation.
4+
5+
== Installing
6+
7+
It is recommended to use the BOM provided by Micrometer (or your framework if any), you can see how to configure it xref:../installing.adoc[here]. The examples below assume you are using a BOM.
8+
9+
=== Gradle
10+
11+
After the BOM is xref:../installing.adoc[configured], add the following dependency:
12+
13+
[source,groovy]
14+
----
15+
implementation 'io.micrometer:micrometer-jakarta9'
16+
----
17+
18+
NOTE: The version is not needed for this dependency since it is defined by the BOM.
19+
20+
=== Maven
21+
22+
After the BOM is xref:../installing.adoc[configured], add the following dependency:
23+
24+
[source,xml]
25+
----
26+
<dependency>
27+
<groupId>io.micrometer</groupId>
28+
<artifactId>micrometer-jakarta9</artifactId>
29+
</dependency>
30+
----
31+
32+
NOTE: The version is not needed for this dependency since it is defined by the BOM.
33+
34+
== Usage
35+
36+
Here is how an existing JMS `Session` instance can be instrumented for observability:
37+
38+
[source,java]
39+
----
40+
import io.micrometer.jakarta9.instrument.jms.JmsInstrumentation;
41+
42+
Session original = ...
43+
ObservationRegistry registry = ...
44+
Session session = JmsInstrumentation.instrumentSession(original, registry);
45+
46+
Topic topic = session.createTopic("micrometer.test.topic");
47+
MessageProducer producer = session.createProducer(topic);
48+
// this operation will create a "jms.message.publish" observation
49+
producer.send(session.createMessage("test message content"));
50+
51+
MessageConsumer consumer = session.createConsumer(topic);
52+
// when a message is processed by the listener,
53+
// a "jms.message.process" observation is created
54+
consumer.setMessageListener(message -> consumeMessage(message));
55+
----
56+
57+
== Observations
58+
59+
This instrumentation will create 2 types of observations:
60+
61+
* `"jms.message.publish"` when a JMS message is sent to the broker via `send`* method calls on `MessageProducer`.
62+
* `"jms.message.process"` when a JMS message is processed via `MessageConsumer.setMessageListener`.
63+
64+
By default, both observations share the same set of possible `KeyValues`:
65+
66+
.Low cardinality Keys
67+
[cols="a,a"]
68+
|===
69+
|Name | Description
70+
|`error` |Class name of the exception thrown during the messaging operation (or "none").
71+
|`exception` |Duplicates the `error` key.
72+
|`messaging.destination.temporary`|Whether the destination (queue or topic) is temporary.
73+
|`messaging.operation`|Name of the JMS operation being performed (values: `"publish"` or `"process"`).
74+
|===
75+
76+
.High cardinality Keys
77+
[cols="a,a"]
78+
|===
79+
|Name | Description
80+
|`messaging.message.conversation_id` |The correlation ID of the JMS message.
81+
|`messaging.destination.name` |The name of the destination the current message was sent to.
82+
|`messaging.message.id` |Value used by the messaging system as an identifier for the message.
83+
|===
84+
85+
86+
=== `messaging.destination.name` as a low-cardinality key
87+
88+
Initially the `messaging.destination.name` key was classified as a high-cardinality key because
89+
a `TemporaryQueue` can be a destination. But `TemporaryQueue` has a great number of possible values of
90+
names.
91+
92+
However, many applications don't use `TemporaryQueue`s. In such cases it might be helpful to treat the key as
93+
low-cardinality key (e.g. to retrieve its values via Spring Boot Actuator).
94+
95+
To achieve this you need to use the below `HighToLowCardinalityObservationFilter`
96+
97+
[source,java]
98+
----
99+
final class HighToLowCardinalityObservationFilter implements ObservationFilter {
100+
private final String key;
101+
102+
HighToLowCardinalityObservationFilter(String key) {
103+
this.key = key;
104+
}
105+
106+
@Override
107+
public Observation.Context map(Observation.Context context) {
108+
Optional.ofNullable(context.getHighCardinalityKeyValue(this.key))
109+
.ifPresent(keyValue -> {
110+
context.removeHighCardinalityKeyValue(keyValue.getKey());
111+
context.addLowCardinalityKeyValue(keyValue);
112+
});
113+
return context;
114+
}
115+
}
116+
----
117+
118+
Registration of the filter:
119+
[source,java]
120+
----
121+
ObservationRegistry registry = observationRegistry();
122+
registry.observationConfig().observationFilter(new HighToLowCardinalityObservationFilter("jms.message.process.messaging.destination.name"));
123+
----

0 commit comments

Comments
 (0)