1818
1919import com .mongodb .MongoNamespace ;
2020import 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 ;
2324import io .micrometer .observation .Observation ;
25+ import io .micrometer .observation .ObservationConvention ;
2426import io .micrometer .observation .ObservationRegistry ;
25- import io .micrometer .observation .transport .Kind ;
26- import io .micrometer .observation .transport .SenderContext ;
2727import org .bson .BsonDocument ;
2828import org .bson .BsonReader ;
2929import org .bson .json .JsonMode ;
3030import org .bson .json .JsonWriter ;
3131import org .bson .json .JsonWriterSettings ;
3232
33- import java .io .PrintWriter ;
3433import 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 ;
4035import static com .mongodb .internal .observability .micrometer .TracingManager .ENV_OBSERVABILITY_QUERY_TEXT_MAX_LENGTH ;
4136import static java .lang .System .getenv ;
4237import 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