Skip to content

Commit 649813e

Browse files
authored
Merge branch 'main' into JAVA-5391
2 parents dd1eceb + a6ea5ff commit 649813e

25 files changed

Lines changed: 829 additions & 269 deletions

config/checkstyle/suppressions.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060

6161
<!-- Allow printStackTrace in this file -->
6262
<suppress checks="Regexp" files="CallbackResultHolder"/>
63-
<suppress checks="Regexp" files="MicrometerTracer"/>
63+
<suppress checks="Regexp" files="DefaultMongodbObservationConvention"/>
6464

6565
<!--Do not check documentation tests classes -->
6666
<suppress checks="Javadoc*" files=".*documentation.*"/>

driver-core/src/main/com/mongodb/MongoClientSettings.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,6 @@ public Builder transportSettings(final TransportSettings transportSettings) {
517517
* @see #getObservabilitySettings()
518518
* @since 5.7
519519
*/
520-
@Alpha(Reason.CLIENT)
521520
public Builder observabilitySettings(final ObservabilitySettings observabilitySettings) {
522521
this.observabilitySettings = notNull("observabilitySettings", observabilitySettings);
523522
return this;

driver-core/src/main/com/mongodb/internal/connection/InternalStreamConnection.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import com.mongodb.internal.session.SessionContext;
5454
import com.mongodb.internal.time.Timeout;
5555
import com.mongodb.lang.Nullable;
56+
import com.mongodb.observability.micrometer.MongodbObservationContext;
5657
import org.bson.BsonBinaryReader;
5758
import org.bson.BsonDocument;
5859
import org.bson.ByteBuf;
@@ -94,8 +95,6 @@
9495
import static com.mongodb.internal.connection.ProtocolHelper.getSnapshotTimestamp;
9596
import static com.mongodb.internal.connection.ProtocolHelper.isCommandOk;
9697
import static com.mongodb.internal.logging.LogMessage.Level.DEBUG;
97-
import static com.mongodb.internal.observability.micrometer.MongodbObservation.HighCardinalityKeyNames.QUERY_TEXT;
98-
import static com.mongodb.internal.observability.micrometer.MongodbObservation.LowCardinalityKeyNames.RESPONSE_STATUS_CODE;
9998
import static com.mongodb.internal.thread.InterruptionUtil.translateInterruptedException;
10099
import static java.util.Arrays.asList;
101100

@@ -454,7 +453,6 @@ private <T> T sendAndReceiveInternal(final CommandMessage message, final Decoder
454453
() -> getDescription().getServerAddress(),
455454
() -> getDescription().getConnectionId()
456455
);
457-
458456
boolean isLoggingCommandNeeded = isLoggingCommandNeeded();
459457
boolean isTracingCommandPayloadNeeded = tracingSpan != null && operationContext.getTracingManager().isCommandPayloadEnabled();
460458

@@ -473,14 +471,19 @@ private <T> T sendAndReceiveInternal(final CommandMessage message, final Decoder
473471
commandEventSender = new NoOpCommandEventSender();
474472
}
475473
if (isTracingCommandPayloadNeeded) {
476-
tracingSpan.tagHighCardinality(QUERY_TEXT.asString(), commandDocument);
474+
tracingSpan.setQueryText(commandDocument);
475+
}
476+
if (tracingSpan != null) {
477+
tracingSpan.openScope();
477478
}
478479

479480
try {
480481
sendCommandMessage(message, bsonOutput, operationContext);
481482
} catch (Exception e) {
482483
if (tracingSpan != null) {
483484
tracingSpan.error(e);
485+
tracingSpan.closeScope();
486+
tracingSpan.end();
484487
}
485488
commandEventSender.sendFailedEvent(e);
486489
throw e;
@@ -492,6 +495,7 @@ private <T> T sendAndReceiveInternal(final CommandMessage message, final Decoder
492495
} else {
493496
commandEventSender.sendSucceededEventForOneWayCommand();
494497
if (tracingSpan != null) {
498+
tracingSpan.closeScope();
495499
tracingSpan.end();
496500
}
497501
return null;
@@ -585,13 +589,17 @@ private <T> T receiveCommandMessageResponse(final Decoder<T> decoder, final Comm
585589
}
586590
if (tracingSpan != null) {
587591
if (e instanceof MongoCommandException) {
588-
tracingSpan.tagLowCardinality(RESPONSE_STATUS_CODE.withValue(String.valueOf(((MongoCommandException) e).getErrorCode())));
592+
MongodbObservationContext ctx = tracingSpan.getMongodbObservationContext();
593+
if (ctx != null) {
594+
ctx.setResponseStatusCode(String.valueOf(((MongoCommandException) e).getErrorCode()));
595+
}
589596
}
590597
tracingSpan.error(e);
591598
}
592599
throw e;
593600
} finally {
594601
if (tracingSpan != null) {
602+
tracingSpan.closeScope();
595603
tracingSpan.end();
596604
}
597605
}
@@ -639,16 +647,18 @@ private <T> void sendAndReceiveAsyncInternal(final CommandMessage message, final
639647
commandEventSender = new NoOpCommandEventSender();
640648
}
641649
if (isTracingCommandPayloadNeeded) {
642-
tracingSpan.tagHighCardinality(QUERY_TEXT.asString(), commandDocument);
650+
tracingSpan.setQueryText(commandDocument);
643651
}
644652

645653
final Span commandSpan = tracingSpan;
646654
SingleResultCallback<T> tracingCallback = commandSpan == null ? callback : (result, t) -> {
647655
try {
648656
if (t != null) {
649657
if (t instanceof MongoCommandException) {
650-
commandSpan.tagLowCardinality(
651-
RESPONSE_STATUS_CODE.withValue(String.valueOf(((MongoCommandException) t).getErrorCode())));
658+
MongodbObservationContext ctx = commandSpan.getMongodbObservationContext();
659+
if (ctx != null) {
660+
ctx.setResponseStatusCode(String.valueOf(((MongoCommandException) t).getErrorCode()));
661+
}
652662
}
653663
commandSpan.error(t);
654664
}

driver-core/src/main/com/mongodb/internal/observability/micrometer/MicrometerTracer.java

Lines changed: 50 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,20 @@
1818

1919
import com.mongodb.MongoNamespace;
2020
import com.mongodb.lang.Nullable;
21-
import io.micrometer.common.KeyValue;
22-
import io.micrometer.common.KeyValues;
21+
import com.mongodb.observability.micrometer.DefaultMongodbObservationConvention;
22+
import com.mongodb.observability.micrometer.MongodbObservation;
23+
import com.mongodb.observability.micrometer.MongodbObservationContext;
2324
import io.micrometer.observation.Observation;
25+
import io.micrometer.observation.ObservationConvention;
2426
import io.micrometer.observation.ObservationRegistry;
25-
import io.micrometer.observation.transport.Kind;
26-
import io.micrometer.observation.transport.SenderContext;
2727
import org.bson.BsonDocument;
2828
import org.bson.BsonReader;
2929
import org.bson.json.JsonMode;
3030
import org.bson.json.JsonWriter;
3131
import org.bson.json.JsonWriterSettings;
3232

33-
import java.io.PrintWriter;
3433
import java.io.StringWriter;
3534

36-
import static com.mongodb.internal.observability.micrometer.MongodbObservation.LowCardinalityKeyNames.EXCEPTION_MESSAGE;
37-
import static com.mongodb.internal.observability.micrometer.MongodbObservation.LowCardinalityKeyNames.EXCEPTION_STACKTRACE;
38-
import static com.mongodb.internal.observability.micrometer.MongodbObservation.LowCardinalityKeyNames.EXCEPTION_TYPE;
39-
import static com.mongodb.internal.observability.micrometer.MongodbObservation.MONGODB_OBSERVATION;
4035
import static com.mongodb.internal.observability.micrometer.TracingManager.ENV_OBSERVABILITY_QUERY_TEXT_MAX_LENGTH;
4136
import static java.lang.System.getenv;
4237
import static java.util.Optional.ofNullable;
@@ -55,34 +50,30 @@ public class MicrometerTracer implements Tracer {
5550
private final ObservationRegistry observationRegistry;
5651
private final boolean allowCommandPayload;
5752
private final int textMaxLength;
58-
private static final String QUERY_TEXT_LENGTH_CONTEXT_KEY = "QUERY_TEXT_MAX_LENGTH";
53+
private final ObservationConvention<MongodbObservationContext> convention;
5954

6055
/**
6156
* Constructs a new {@link MicrometerTracer} instance.
6257
*
6358
* @param observationRegistry The Micrometer {@link ObservationRegistry} to delegate tracing operations to.
64-
*/
65-
public MicrometerTracer(final ObservationRegistry observationRegistry) {
66-
this(observationRegistry, false, 0);
67-
}
68-
69-
/**
70-
* Constructs a new {@link MicrometerTracer} instance with an option to allow command payloads.
71-
*
72-
* @param observationRegistry The Micrometer {@link ObservationRegistry} to delegate tracing operations to.
7359
* @param allowCommandPayload Whether to allow command payloads in the trace context.
60+
* @param textMaxLength The maximum length for query text truncation.
61+
* @param customConvention A custom observation convention, or null to use the default.
7462
*/
75-
public MicrometerTracer(final ObservationRegistry observationRegistry, final boolean allowCommandPayload, final int textMaxLength) {
63+
public MicrometerTracer(final ObservationRegistry observationRegistry, final boolean allowCommandPayload,
64+
final int textMaxLength, @Nullable final ObservationConvention<MongodbObservationContext> customConvention) {
7665
this.allowCommandPayload = allowCommandPayload;
7766
this.observationRegistry = observationRegistry;
7867
this.textMaxLength = ofNullable(getenv(ENV_OBSERVABILITY_QUERY_TEXT_MAX_LENGTH))
7968
.map(Integer::parseInt)
8069
.orElse(textMaxLength);
70+
this.convention = customConvention != null ? customConvention : new DefaultMongodbObservationConvention();
8171
}
8272

8373
@Override
84-
public Span nextSpan(final String name, @Nullable final TraceContext parent, @Nullable final MongoNamespace namespace) {
85-
Observation observation = getObservation(name);
74+
public Span nextSpan(final MongodbObservation observationType, final String name,
75+
@Nullable final TraceContext parent, @Nullable final MongoNamespace namespace) {
76+
Observation observation = getObservation(observationType, name);
8677

8778
if (parent instanceof MicrometerTraceContext) {
8879
Observation parentObservation = ((MicrometerTraceContext) parent).observation;
@@ -91,7 +82,7 @@ public Span nextSpan(final String name, @Nullable final TraceContext parent, @Nu
9182
}
9283
}
9384

94-
return new MicrometerSpan(observation.start(), namespace);
85+
return new MicrometerSpan(observation.start(), namespace, textMaxLength);
9586
}
9687

9788
@Override
@@ -104,12 +95,12 @@ public boolean includeCommandPayload() {
10495
return allowCommandPayload;
10596
}
10697

107-
private Observation getObservation(final String name) {
108-
Observation observation = MONGODB_OBSERVATION.observation(observationRegistry,
109-
() -> new SenderContext<>((carrier, key, value) -> {}, Kind.CLIENT))
110-
.contextualName(name);
111-
observation.getContext().put(QUERY_TEXT_LENGTH_CONTEXT_KEY, textMaxLength);
112-
return observation;
98+
private Observation getObservation(final MongodbObservation observationType, final String name) {
99+
return observationType.observation(observationRegistry, () -> {
100+
MongodbObservationContext ctx = new MongodbObservationContext();
101+
ctx.setObservationType(observationType);
102+
return ctx;
103+
}).observationConvention(convention).contextualName(name);
113104
}
114105
/**
115106
* Represents a Micrometer-based trace context.
@@ -135,38 +126,43 @@ private static class MicrometerSpan implements Span {
135126
@Nullable
136127
private final MongoNamespace namespace;
137128
private final int queryTextLength;
129+
@Nullable
130+
private Observation.Scope scope;
138131

139132
/**
140133
* Constructs a new {@link MicrometerSpan} instance with an associated Observation and MongoDB namespace.
141134
*
142-
* @param observation The Micrometer {@link Observation}, or null if none exists.
143-
* @param namespace The MongoDB namespace associated with the span.
135+
* @param observation The Micrometer {@link Observation}, or null if none exists.
136+
* @param namespace The MongoDB namespace associated with the span.
137+
* @param queryTextLength The maximum length for query text truncation.
144138
*/
145-
MicrometerSpan(final Observation observation, @Nullable final MongoNamespace namespace) {
139+
MicrometerSpan(final Observation observation, @Nullable final MongoNamespace namespace, final int queryTextLength) {
146140
this.namespace = namespace;
147141
this.observation = observation;
148-
this.queryTextLength = ofNullable(observation.getContext().get(QUERY_TEXT_LENGTH_CONTEXT_KEY))
149-
.filter(Integer.class::isInstance)
150-
.map(Integer.class::cast)
151-
.orElse(Integer.MAX_VALUE);
142+
this.queryTextLength = queryTextLength;
152143
}
153144

154145
@Override
155-
public void tagLowCardinality(final KeyValue keyValue) {
156-
observation.lowCardinalityKeyValue(keyValue);
146+
public void openScope() {
147+
this.scope = observation.openScope();
157148
}
158149

159150
@Override
160-
public void tagLowCardinality(final KeyValues keyValues) {
161-
observation.lowCardinalityKeyValues(keyValues);
151+
public void closeScope() {
152+
if (scope != null) {
153+
scope.close();
154+
scope = null;
155+
}
162156
}
163157

164158
@Override
165-
public void tagHighCardinality(final String keyName, final BsonDocument value) {
166-
observation.highCardinalityKeyValue(keyName,
167-
(queryTextLength < Integer.MAX_VALUE) // truncate values that are too long
168-
? getTruncatedBsonDocument(value)
169-
: value.toString());
159+
public void setQueryText(final BsonDocument commandDocument) {
160+
MongodbObservationContext ctx = getMongodbObservationContext();
161+
if (ctx != null) {
162+
ctx.setQueryText((queryTextLength < Integer.MAX_VALUE)
163+
? getTruncatedBsonDocument(commandDocument)
164+
: commandDocument.toString());
165+
}
170166
}
171167

172168
@Override
@@ -176,11 +172,6 @@ public void event(final String event) {
176172

177173
@Override
178174
public void error(final Throwable throwable) {
179-
observation.lowCardinalityKeyValues(KeyValues.of(
180-
EXCEPTION_MESSAGE.withValue(throwable.getMessage()),
181-
EXCEPTION_TYPE.withValue(throwable.getClass().getName()),
182-
EXCEPTION_STACKTRACE.withValue(getStackTraceAsString(throwable))
183-
));
184175
observation.error(throwable);
185176
}
186177

@@ -196,15 +187,17 @@ public TraceContext context() {
196187

197188
@Override
198189
@Nullable
199-
public MongoNamespace getNamespace() {
200-
return namespace;
190+
public MongodbObservationContext getMongodbObservationContext() {
191+
if (observation.getContext() instanceof MongodbObservationContext) {
192+
return (MongodbObservationContext) observation.getContext();
193+
}
194+
return null;
201195
}
202196

203-
private String getStackTraceAsString(final Throwable throwable) {
204-
StringWriter sw = new StringWriter();
205-
PrintWriter pw = new PrintWriter(sw);
206-
throwable.printStackTrace(pw);
207-
return sw.toString();
197+
@Override
198+
@Nullable
199+
public MongoNamespace getNamespace() {
200+
return namespace;
208201
}
209202

210203
private String getTruncatedBsonDocument(final BsonDocument commandDocument) {

0 commit comments

Comments
 (0)