Skip to content

Commit f9fce23

Browse files
aelsammakaaron-613TamimiGitHub
authored
SOL-115142: Added HowToImplementTracingManualInstrumentation (#38)
* SOL-115142: Created HowToImplementTracingManualInstrumentation * Updated build.gradle * update Java OTEL to 1.0.0 since it's been released * Updated PS+ Java to 1.7.0 and Java OTEL to 1.0.0 * updated semconv JAR version, update pom to pull latest, updated java class imports * added hopefully helpful comment * Addressed PR comments --------- Co-authored-by: aaron-613 <[email protected]> Co-authored-by: Tamimi Ahmad <[email protected]>
1 parent 8460b4a commit f9fce23

File tree

3 files changed

+210
-4
lines changed

3 files changed

+210
-4
lines changed

build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ dependencies {
5757
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.+'
5858
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.+'
5959
implementation group: 'org.apache.logging.log4j', name: 'log4j-jcl', version: '2.+'
60+
61+
// Distributed Tracing Dependency on OpenTelemetry and Solace PubSub+ OpenTelemetry Java Integration
62+
implementation group: 'com.solace', name: 'pubsubplus-opentelemetry-java-integration', version: '1.+'
63+
implementation group: 'io.opentelemetry', name: 'opentelemetry-exporter-otlp', version: '1.+'
64+
implementation group: 'io.opentelemetry.semconv', name: 'opentelemetry-semconv', version: '1.+'
6065
}
6166

6267

pom.xml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,39 @@
1010
<dependency>
1111
<groupId>com.solace</groupId>
1212
<artifactId>solace-messaging-client</artifactId>
13-
<version>1.4.0</version>
13+
<version>[1.7.0,2)</version>
1414
</dependency>
1515
<dependency>
1616
<groupId>org.apache.logging.log4j</groupId>
1717
<artifactId>log4j-api</artifactId>
18-
<version>2.17.2</version>
18+
<version>[2.24.0,2.99)</version>
1919
</dependency>
2020
<dependency>
2121
<groupId>org.apache.logging.log4j</groupId>
2222
<artifactId>log4j-core</artifactId>
23-
<version>2.17.2</version>
23+
<version>[2.24.0,2.99)</version>
2424
</dependency>
2525
<dependency>
2626
<groupId>org.apache.logging.log4j</groupId>
2727
<artifactId>log4j-jcl</artifactId>
28-
<version>2.17.2</version>
28+
<version>[2.24.0,2.99)</version>
2929
</dependency>
30+
<!-- Distributed Tracing Dependency on OpenTelemetry and Solace PubSub+ OpenTelemetry Java Integration -->
31+
<dependency>
32+
<groupId>io.opentelemetry</groupId>
33+
<artifactId>opentelemetry-exporter-otlp</artifactId>
34+
<version>[1.42.0,2.0.0)</version>
35+
</dependency>
36+
<dependency>
37+
<groupId>io.opentelemetry.semconv</groupId>
38+
<artifactId>opentelemetry-semconv</artifactId>
39+
<version>[1.27.0-alpha,2.0.0)</version>
40+
</dependency>
41+
<dependency>
42+
<groupId>com.solace</groupId>
43+
<artifactId>pubsubplus-opentelemetry-java-integration</artifactId>
44+
<version>[1.0.0,2.0.0)</version>
45+
</dependency>
3046
</dependencies>
3147

3248
<build>
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*
2+
* Copyright 2021-2024 Solace Corporation. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package com.solace.samples.java.snippets;
18+
19+
import com.solace.messaging.publisher.DirectMessagePublisher;
20+
import com.solace.messaging.publisher.OutboundMessage;
21+
import com.solace.messaging.receiver.InboundMessage;
22+
import com.solace.messaging.resources.Topic;
23+
import com.solace.messaging.trace.propagation.SolacePubSubPlusJavaTextMapGetter;
24+
import com.solace.messaging.trace.propagation.SolacePubSubPlusJavaTextMapSetter;
25+
import io.opentelemetry.api.baggage.Baggage;
26+
import io.opentelemetry.api.baggage.propagation.BaggageUtil;
27+
import io.opentelemetry.api.OpenTelemetry;
28+
import io.opentelemetry.api.trace.Span;
29+
import io.opentelemetry.api.trace.SpanKind;
30+
import io.opentelemetry.api.trace.StatusCode;
31+
import io.opentelemetry.api.trace.Tracer;
32+
import io.opentelemetry.context.Context;
33+
import io.opentelemetry.context.Scope;
34+
import io.opentelemetry.context.propagation.TextMapPropagator;
35+
import io.opentelemetry.semconv.SemanticAttributes;
36+
import io.opentelemetry.semconv.SemanticAttributes.MessagingDestinationKindValues;
37+
import io.opentelemetry.semconv.SemanticAttributes.MessagingOperationValues;
38+
39+
import java.util.function.Consumer;
40+
41+
@SuppressWarnings("deprecation")
42+
public class HowToImplementTracingManualInstrumentation {
43+
44+
/**
45+
* Example how to inject a tracing context into Solace PubSub+ Java Message
46+
* before it is published to a queue or topic.
47+
*
48+
* @param messageToPublish A Solace PubSub+ Java Outbound message to be used for publishing.
49+
* @param openTelemetry The entry point to telemetry functionality for tracing, metrics and
50+
* baggage.
51+
*/
52+
void howToInjectTraceContextInSolaceMessage(OutboundMessage messageToPublish,
53+
OpenTelemetry openTelemetry) {
54+
final SolacePubSubPlusJavaTextMapSetter setter = new SolacePubSubPlusJavaTextMapSetter();
55+
// Injects current context into the message to transport it across message boundaries.
56+
// Transported context will be used to create parent - child relationship
57+
// between spans from different services and broker spans
58+
final Context contextToInject = Context.current();
59+
openTelemetry.getPropagators().getTextMapPropagator()
60+
.inject(contextToInject, messageToPublish, setter);
61+
}
62+
63+
/**
64+
* Example how to extract a tracing context from the Solace PubSub+ Java Message upon message receipt.
65+
*
66+
* @param receivedMessage Received Solace PubSub+ Java Inbound message.
67+
* @param openTelemetry The entry point to telemetry functionality for tracing, metrics and
68+
* baggage.
69+
*/
70+
void howToExtractTraceContextIfAnyFromSolaceMessage(InboundMessage receivedMessage,
71+
OpenTelemetry openTelemetry) {
72+
// Extracts tracing context from a message
73+
// The SolacePubSubPlusJavaTextMapGetter is used our custom TextMapGetter which extracts
74+
// tracing information from the message such as: traceparent, tracestate or baggage
75+
final Context extractedContext = openTelemetry.getPropagators().getTextMapPropagator()
76+
.extract(Context.current(), receivedMessage, new SolacePubSubPlusJavaTextMapGetter());
77+
78+
// Then set the extractedContext as current context
79+
try (Scope scope = extractedContext.makeCurrent()) {
80+
//...
81+
}
82+
}
83+
84+
/**
85+
* Example how to inject a tracing context (including span and baggage) in the Solace PubSub+ Java Message
86+
* and generate a SEND span for the published message.
87+
*
88+
* @param message A Solace PubSub+ Java Message that support tracing context propagation.
89+
* @param messagePublisher Solace PubSub+ Java Message publisher that can publish direct messages
90+
* @param messageDestination message destination
91+
* @param openTelemetry The entry-point to telemetry functionality for tracing, metrics and
92+
* baggage.
93+
* @param tracer Tracer is the interface for Span creation and interaction with the
94+
* in-process context.
95+
*/
96+
void howToCreateSpanAndBaggageOnMessagePublish(OutboundMessage message, DirectMessagePublisher messagePublisher,
97+
Topic messageDestination, OpenTelemetry openTelemetry,
98+
Tracer tracer) {
99+
100+
// Create a new span with a current context as parent of this span
101+
final Span sendSpan = tracer
102+
.spanBuilder("mySolacePublisherApp" + " " + MessagingOperationValues.PROCESS)
103+
.setSpanKind(SpanKind.CLIENT)
104+
// published to a topic endpoint (non-temporary)
105+
.setAttribute(SemanticAttributes.MESSAGING_DESTINATION_KIND, MessagingDestinationKindValues.TOPIC)
106+
.setAttribute(SemanticAttributes.MESSAGING_TEMP_DESTINATION, false)
107+
// Set more attributes as needed
108+
//.setAttribute(...)
109+
//.setAttribute(...)
110+
.setParent(Context.current()) // set current context as parent
111+
.startSpan();
112+
113+
// Create baggage object
114+
Baggage baggage = BaggageUtil.extractBaggage("key1=val1,key2=val2");
115+
116+
// set sendSpan as new current context
117+
try (Scope scope = sendSpan.makeCurrent()) {
118+
// set baggage in the current context
119+
try (Scope scope1 = baggage.storeInContext(Context.current()).makeCurrent()) {
120+
final SolacePubSubPlusJavaTextMapSetter setter = new SolacePubSubPlusJavaTextMapSetter();
121+
final TextMapPropagator propagator = openTelemetry.getPropagators().getTextMapPropagator();
122+
// then inject current context with send span and baggage into the message
123+
// optionally, could also add trace, span, baggage information as User Properties for interop with other protocols (MQTT, AMQP)
124+
propagator.inject(Context.current(), message, setter);
125+
// publish message to the given topic
126+
messagePublisher.publish(message, messageDestination);
127+
}
128+
} catch (Exception e) {
129+
sendSpan.recordException(e); // Span can record exception if any
130+
sendSpan.setStatus(StatusCode.ERROR, e.getMessage()); // Set span status as ERROR/FAILED
131+
} finally {
132+
sendSpan.end(); // End sendSpan. Span data is exported when span.end() is called.
133+
}
134+
}
135+
136+
/**
137+
* Example how to extract a tracing context from the Solace PubSub+ Java Message and generate a RECEIVE span
138+
* for the received message.
139+
*
140+
* @param receivedMessage A Solace PubSub+ Java Message.
141+
* @param messageProcessor A callback function that the user could use to process a message
142+
* @param openTelemetry The OpenTelemetry class is the entry point to telemetry functionality
143+
* for tracing, metrics and baggage from OpenTelemetry Java SDK.
144+
* @param tracer OpenTelemetry Tracer is the interface from OpenTelemetry Java SDK for
145+
* span creation and interaction with the in-process context.
146+
*/
147+
void howToCreateNewSpanOnMessageReceive(InboundMessage receivedMessage,
148+
Consumer<InboundMessage> messageProcessor,
149+
OpenTelemetry openTelemetry, Tracer tracer) {
150+
151+
// Extract tracing context from message
152+
// The SolacePubSubPlusJavaTextMapGetter is our custom TextMapGetter which extracts
153+
// tracing information from the message such as: traceparent, tracestate or baggage
154+
final Context extractedContext = openTelemetry.getPropagators().getTextMapPropagator()
155+
.extract(Context.current(), receivedMessage, new SolacePubSubPlusJavaTextMapGetter());
156+
157+
// Set the extracted context as current context
158+
try (Scope scope = extractedContext.makeCurrent()) {
159+
// Create a child span and set extracted/current context as parent of this span
160+
final Span receiveSpan = tracer
161+
.spanBuilder("mySolaceReceiverApp" + " " + MessagingOperationValues.RECEIVE)
162+
.setSpanKind(SpanKind.CLIENT)
163+
// for the case the message was received on a non-temporary topic endpoint
164+
.setAttribute(SemanticAttributes.MESSAGING_DESTINATION_KIND, MessagingDestinationKindValues.TOPIC)
165+
.setAttribute(SemanticAttributes.MESSAGING_TEMP_DESTINATION, false)
166+
// Set more attributes as needed
167+
//.setAttribute(...)
168+
//.setAttribute(...)
169+
// creates a parent child relationship to a message publisher's application span by calling
170+
.setParent(extractedContext)
171+
// starts span
172+
.startSpan();
173+
try {
174+
// do something with a message in a callback
175+
messageProcessor.accept(receivedMessage);
176+
} catch (Exception e) {
177+
receiveSpan.recordException(e); // Span can record exception if any
178+
receiveSpan.setStatus(StatusCode.ERROR,
179+
e.getMessage()); // and set span status as ERROR/FAILED
180+
} finally {
181+
receiveSpan.end(); // End receiveSpan. Span data is exported when span.end() is called.
182+
}
183+
}
184+
}
185+
}

0 commit comments

Comments
 (0)