Skip to content

Commit 9b4b0ad

Browse files
committed
Add DefaultMongodbObservationConvention and move tag production out of TracingManager
Replaced all imperative tagLowCardinality/tagHighCardinality calls with a convention-based approach. TracingManager and InternalStreamConnection now populate domain fields on MongodbContext, and DefaultMongodbObservationConvention reads those fields at stop time to produce the final key-values. This decouples tag naming from span creation, enabling users to register a GlobalObservationConvention<MongodbContext> to customize tag names for their environment (e.g. Spring Boot tag alignment with their existing DefaultMongoCommandTagsProvider). Added domain fields to MongodbContext: observationType, commandName, databaseName, collectionName, serverAddress, connectionId, cursorId, transactionNumber, sessionId, queryText, responseStatusCode. Removed tagLowCardinality/tagHighCardinality from the Span interface as they are no longer used.
1 parent 52efa25 commit 9b4b0ad

File tree

7 files changed

+240
-184
lines changed

7 files changed

+240
-184
lines changed

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/internal/connection/InternalStreamConnection.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import com.mongodb.internal.diagnostics.logging.Logger;
5050
import com.mongodb.internal.diagnostics.logging.Loggers;
5151
import com.mongodb.internal.logging.StructuredLogger;
52+
import com.mongodb.internal.observability.micrometer.MongodbContext;
5253
import com.mongodb.internal.observability.micrometer.Span;
5354
import com.mongodb.internal.session.SessionContext;
5455
import com.mongodb.internal.time.Timeout;
@@ -94,8 +95,7 @@
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.CommandLowCardinalityKeyNames.RESPONSE_STATUS_CODE;
98+
9999
import static com.mongodb.internal.thread.InterruptionUtil.translateInterruptedException;
100100
import static java.util.Arrays.asList;
101101

@@ -473,7 +473,7 @@ private <T> T sendAndReceiveInternal(final CommandMessage message, final Decoder
473473
commandEventSender = new NoOpCommandEventSender();
474474
}
475475
if (isTracingCommandPayloadNeeded) {
476-
tracingSpan.tagHighCardinality(QUERY_TEXT.asString(), commandDocument);
476+
tracingSpan.setQueryText(commandDocument);
477477
}
478478

479479
try {
@@ -585,7 +585,10 @@ private <T> T receiveCommandMessageResponse(final Decoder<T> decoder, final Comm
585585
}
586586
if (tracingSpan != null) {
587587
if (e instanceof MongoCommandException) {
588-
tracingSpan.tagLowCardinality(RESPONSE_STATUS_CODE.withValue(String.valueOf(((MongoCommandException) e).getErrorCode())));
588+
MongodbContext ctx = tracingSpan.getMongodbContext();
589+
if (ctx != null) {
590+
ctx.setResponseStatusCode(String.valueOf(((MongoCommandException) e).getErrorCode()));
591+
}
589592
}
590593
tracingSpan.error(e);
591594
}
@@ -639,16 +642,18 @@ private <T> void sendAndReceiveAsyncInternal(final CommandMessage message, final
639642
commandEventSender = new NoOpCommandEventSender();
640643
}
641644
if (isTracingCommandPayloadNeeded) {
642-
tracingSpan.tagHighCardinality(QUERY_TEXT.asString(), commandDocument);
645+
tracingSpan.setQueryText(commandDocument);
643646
}
644647

645648
final Span commandSpan = tracingSpan;
646649
SingleResultCallback<T> tracingCallback = commandSpan == null ? callback : (result, t) -> {
647650
try {
648651
if (t != null) {
649652
if (t instanceof MongoCommandException) {
650-
commandSpan.tagLowCardinality(
651-
RESPONSE_STATUS_CODE.withValue(String.valueOf(((MongoCommandException) t).getErrorCode())));
653+
MongodbContext ctx = commandSpan.getMongodbContext();
654+
if (ctx != null) {
655+
ctx.setResponseStatusCode(String.valueOf(((MongoCommandException) t).getErrorCode()));
656+
}
652657
}
653658
commandSpan.error(t);
654659
}

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

Lines changed: 25 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
import com.mongodb.MongoNamespace;
2020
import com.mongodb.lang.Nullable;
21-
import io.micrometer.common.KeyValue;
22-
import io.micrometer.common.KeyValues;
2321
import io.micrometer.observation.Observation;
2422
import io.micrometer.observation.ObservationRegistry;
2523
import org.bson.BsonDocument;
@@ -28,12 +26,8 @@
2826
import org.bson.json.JsonWriter;
2927
import org.bson.json.JsonWriterSettings;
3028

31-
import java.io.PrintWriter;
3229
import java.io.StringWriter;
3330

34-
import static com.mongodb.internal.observability.micrometer.MongodbObservation.HighCardinalityKeyNames.EXCEPTION_MESSAGE;
35-
import static com.mongodb.internal.observability.micrometer.MongodbObservation.HighCardinalityKeyNames.EXCEPTION_STACKTRACE;
36-
import static com.mongodb.internal.observability.micrometer.MongodbObservation.HighCardinalityKeyNames.EXCEPTION_TYPE;
3731
import static com.mongodb.internal.observability.micrometer.TracingManager.ENV_OBSERVABILITY_QUERY_TEXT_MAX_LENGTH;
3832
import static java.lang.System.getenv;
3933
import static java.util.Optional.ofNullable;
@@ -66,6 +60,10 @@ public MicrometerTracer(final ObservationRegistry observationRegistry, final boo
6660
this.textMaxLength = ofNullable(getenv(ENV_OBSERVABILITY_QUERY_TEXT_MAX_LENGTH))
6761
.map(Integer::parseInt)
6862
.orElse(textMaxLength);
63+
// Register default convention. Users can override by registering their own GlobalObservationConvention
64+
// after the MongoClient is created — the last matching convention wins.
65+
DefaultMongodbObservationConvention defaultConvention = new DefaultMongodbObservationConvention();
66+
observationRegistry.observationConfig().observationConvention(defaultConvention);
6967
}
7068

7169
@Override
@@ -94,8 +92,11 @@ public boolean includeCommandPayload() {
9492
}
9593

9694
private Observation getObservation(final MongodbObservation observationType, final String name) {
97-
return observationType.observation(observationRegistry, MongodbContext::new)
98-
.contextualName(name);
95+
return observationType.observation(observationRegistry, () -> {
96+
MongodbContext ctx = new MongodbContext();
97+
ctx.setObservationType(observationType);
98+
return ctx;
99+
}).contextualName(name);
99100
}
100101
/**
101102
* Represents a Micrometer-based trace context.
@@ -136,31 +137,13 @@ private static class MicrometerSpan implements Span {
136137
}
137138

138139
@Override
139-
public void tagLowCardinality(final KeyValue keyValue) {
140-
observation.lowCardinalityKeyValue(keyValue);
141-
}
142-
143-
@Override
144-
public void tagLowCardinality(final KeyValues keyValues) {
145-
observation.lowCardinalityKeyValues(keyValues);
146-
}
147-
148-
@Override
149-
public void tagHighCardinality(final KeyValue keyValue) {
150-
observation.highCardinalityKeyValue(keyValue);
151-
}
152-
153-
@Override
154-
public void tagHighCardinality(final KeyValues keyValues) {
155-
observation.highCardinalityKeyValues(keyValues);
156-
}
157-
158-
@Override
159-
public void tagHighCardinality(final String keyName, final BsonDocument value) {
160-
observation.highCardinalityKeyValue(keyName,
161-
(queryTextLength < Integer.MAX_VALUE) // truncate values that are too long
162-
? getTruncatedBsonDocument(value)
163-
: value.toString());
140+
public void setQueryText(final BsonDocument commandDocument) {
141+
MongodbContext ctx = getMongodbContext();
142+
if (ctx != null) {
143+
ctx.setQueryText((queryTextLength < Integer.MAX_VALUE)
144+
? getTruncatedBsonDocument(commandDocument)
145+
: commandDocument.toString());
146+
}
164147
}
165148

166149
@Override
@@ -170,11 +153,6 @@ public void event(final String event) {
170153

171154
@Override
172155
public void error(final Throwable throwable) {
173-
observation.highCardinalityKeyValues(KeyValues.of(
174-
EXCEPTION_MESSAGE.withValue(throwable.getMessage()),
175-
EXCEPTION_TYPE.withValue(throwable.getClass().getName()),
176-
EXCEPTION_STACKTRACE.withValue(getStackTraceAsString(throwable))
177-
));
178156
observation.error(throwable);
179157
}
180158

@@ -190,15 +168,17 @@ public TraceContext context() {
190168

191169
@Override
192170
@Nullable
193-
public MongoNamespace getNamespace() {
194-
return namespace;
171+
public MongodbContext getMongodbContext() {
172+
if (observation.getContext() instanceof MongodbContext) {
173+
return (MongodbContext) observation.getContext();
174+
}
175+
return null;
195176
}
196177

197-
private String getStackTraceAsString(final Throwable throwable) {
198-
StringWriter sw = new StringWriter();
199-
PrintWriter pw = new PrintWriter(sw);
200-
throwable.printStackTrace(pw);
201-
return sw.toString();
178+
@Override
179+
@Nullable
180+
public MongoNamespace getNamespace() {
181+
return namespace;
202182
}
203183

204184
private String getTruncatedBsonDocument(final BsonDocument commandDocument) {

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

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package com.mongodb.internal.observability.micrometer;
1818

19+
import com.mongodb.ServerAddress;
20+
import com.mongodb.connection.ConnectionId;
21+
import com.mongodb.lang.Nullable;
1922
import io.micrometer.observation.transport.Kind;
2023
import io.micrometer.observation.transport.SenderContext;
2124

@@ -26,11 +29,146 @@
2629
* in the tracing bridge. Provides a MongoDB-specific type that users can filter on
2730
* when registering {@code ObservationHandler} or {@code ObservationConvention} instances.
2831
* </p>
32+
* <p>
33+
* Domain fields (commandName, databaseName, etc.) are populated by the driver after
34+
* the observation is started and before it is stopped. The {@code ObservationConvention}
35+
* reads these fields at stop time to produce the final tag key-values.
36+
* </p>
2937
*
3038
* @since 5.7
3139
*/
3240
public class MongodbContext extends SenderContext<Object> {
41+
42+
private MongodbObservation observationType;
43+
@Nullable
44+
private String commandName;
45+
@Nullable
46+
private String databaseName;
47+
@Nullable
48+
private String collectionName;
49+
@Nullable
50+
private ServerAddress serverAddress;
51+
@Nullable
52+
private ConnectionId connectionId;
53+
@Nullable
54+
private Long cursorId;
55+
@Nullable
56+
private Long transactionNumber;
57+
@Nullable
58+
private String sessionId;
59+
@Nullable
60+
private String queryText;
61+
@Nullable
62+
private String responseStatusCode;
63+
private boolean isUnixSocket;
64+
3365
public MongodbContext() {
3466
super((carrier, key, value) -> { }, Kind.CLIENT);
3567
}
68+
69+
@Nullable
70+
public String getCommandName() {
71+
return commandName;
72+
}
73+
74+
public void setCommandName(@Nullable final String commandName) {
75+
this.commandName = commandName;
76+
}
77+
78+
@Nullable
79+
public String getDatabaseName() {
80+
return databaseName;
81+
}
82+
83+
public void setDatabaseName(@Nullable final String databaseName) {
84+
this.databaseName = databaseName;
85+
}
86+
87+
@Nullable
88+
public String getCollectionName() {
89+
return collectionName;
90+
}
91+
92+
public void setCollectionName(@Nullable final String collectionName) {
93+
this.collectionName = collectionName;
94+
}
95+
96+
@Nullable
97+
public ServerAddress getServerAddress() {
98+
return serverAddress;
99+
}
100+
101+
public void setServerAddress(@Nullable final ServerAddress serverAddress) {
102+
this.serverAddress = serverAddress;
103+
}
104+
105+
@Nullable
106+
public ConnectionId getConnectionId() {
107+
return connectionId;
108+
}
109+
110+
public void setConnectionId(@Nullable final ConnectionId connectionId) {
111+
this.connectionId = connectionId;
112+
}
113+
114+
public MongodbObservation getObservationType() {
115+
return observationType;
116+
}
117+
118+
public void setObservationType(final MongodbObservation observationType) {
119+
this.observationType = observationType;
120+
}
121+
122+
@Nullable
123+
public Long getCursorId() {
124+
return cursorId;
125+
}
126+
127+
public void setCursorId(@Nullable final Long cursorId) {
128+
this.cursorId = cursorId;
129+
}
130+
131+
@Nullable
132+
public Long getTransactionNumber() {
133+
return transactionNumber;
134+
}
135+
136+
public void setTransactionNumber(@Nullable final Long transactionNumber) {
137+
this.transactionNumber = transactionNumber;
138+
}
139+
140+
@Nullable
141+
public String getSessionId() {
142+
return sessionId;
143+
}
144+
145+
public void setSessionId(@Nullable final String sessionId) {
146+
this.sessionId = sessionId;
147+
}
148+
149+
public boolean isUnixSocket() {
150+
return isUnixSocket;
151+
}
152+
153+
public void setUnixSocket(final boolean unixSocket) {
154+
isUnixSocket = unixSocket;
155+
}
156+
157+
@Nullable
158+
public String getQueryText() {
159+
return queryText;
160+
}
161+
162+
public void setQueryText(@Nullable final String queryText) {
163+
this.queryText = queryText;
164+
}
165+
166+
@Nullable
167+
public String getResponseStatusCode() {
168+
return responseStatusCode;
169+
}
170+
171+
public void setResponseStatusCode(@Nullable final String responseStatusCode) {
172+
this.responseStatusCode = responseStatusCode;
173+
}
36174
}

0 commit comments

Comments
 (0)