2727import io .opentelemetry .context .Context ;
2828import io .opentelemetry .instrumentation .api .incubator .semconv .db .RedisCommandSanitizer ;
2929import io .opentelemetry .instrumentation .api .instrumenter .AttributesExtractor ;
30+ import io .opentelemetry .instrumentation .api .instrumenter .OperationListener ;
3031import io .opentelemetry .instrumentation .api .internal .SemconvStability ;
3132import io .opentelemetry .instrumentation .api .semconv .network .NetworkAttributesExtractor ;
3233import io .opentelemetry .instrumentation .api .semconv .network .ServerAttributesExtractor ;
@@ -54,8 +55,11 @@ final class OpenTelemetryTracing implements Tracing {
5455 NetworkAttributesExtractor .create (new LettuceServerAttributesGetter ());
5556 private final TracerProvider tracerProvider ;
5657
57- OpenTelemetryTracing (io .opentelemetry .api .trace .Tracer tracer , RedisCommandSanitizer sanitizer ) {
58- this .tracerProvider = new OpenTelemetryTracerProvider (tracer , sanitizer );
58+ OpenTelemetryTracing (
59+ io .opentelemetry .api .trace .Tracer tracer ,
60+ RedisCommandSanitizer sanitizer ,
61+ OperationListener metrics ) {
62+ this .tracerProvider = new OpenTelemetryTracerProvider (tracer , sanitizer , metrics );
5963 }
6064
6165 @ Override
@@ -93,8 +97,10 @@ private static class OpenTelemetryTracerProvider implements TracerProvider {
9397 private final Tracer openTelemetryTracer ;
9498
9599 OpenTelemetryTracerProvider (
96- io .opentelemetry .api .trace .Tracer tracer , RedisCommandSanitizer sanitizer ) {
97- openTelemetryTracer = new OpenTelemetryTracer (tracer , sanitizer );
100+ io .opentelemetry .api .trace .Tracer tracer ,
101+ RedisCommandSanitizer sanitizer ,
102+ OperationListener metrics ) {
103+ openTelemetryTracer = new OpenTelemetryTracer (tracer , sanitizer , metrics );
98104 }
99105
100106 @ Override
@@ -135,10 +141,15 @@ private static class OpenTelemetryTracer extends Tracer {
135141
136142 private final io .opentelemetry .api .trace .Tracer tracer ;
137143 private final RedisCommandSanitizer sanitizer ;
144+ private final OperationListener metrics ;
138145
139- OpenTelemetryTracer (io .opentelemetry .api .trace .Tracer tracer , RedisCommandSanitizer sanitizer ) {
146+ OpenTelemetryTracer (
147+ io .opentelemetry .api .trace .Tracer tracer ,
148+ RedisCommandSanitizer sanitizer ,
149+ OperationListener metrics ) {
140150 this .tracer = tracer ;
141151 this .sanitizer = sanitizer ;
152+ this .metrics = metrics ;
142153 }
143154
144155 @ Override
@@ -165,7 +176,7 @@ private OpenTelemetrySpan nextSpan(Context context) {
165176 .setSpanKind (SpanKind .CLIENT )
166177 .setParent (context )
167178 .setAttribute (DB_SYSTEM , REDIS );
168- return new OpenTelemetrySpan (context , spanBuilder , sanitizer );
179+ return new OpenTelemetrySpan (context , spanBuilder , sanitizer , metrics );
169180 }
170181 }
171182
@@ -178,18 +189,26 @@ private static class OpenTelemetrySpan extends Tracer.Span {
178189 private final Context context ;
179190 private final SpanBuilder spanBuilder ;
180191 private final RedisCommandSanitizer sanitizer ;
192+ private final OperationListener metrics ;
181193
182194 @ Nullable private String name ;
183195 @ Nullable private List <Object > events ;
184196 @ Nullable private Throwable error ;
185197 @ Nullable private Span span ;
198+ private long spanStartNanos ;
199+ private final AttributesBuilder attributesBuilder = Attributes .builder ().put (DB_SYSTEM , REDIS );
186200 @ Nullable private List <String > argsList ;
187201 @ Nullable private String argsString ;
188202
189- OpenTelemetrySpan (Context context , SpanBuilder spanBuilder , RedisCommandSanitizer sanitizer ) {
203+ OpenTelemetrySpan (
204+ Context context ,
205+ SpanBuilder spanBuilder ,
206+ RedisCommandSanitizer sanitizer ,
207+ OperationListener metrics ) {
190208 this .context = context ;
191209 this .spanBuilder = spanBuilder ;
192210 this .sanitizer = sanitizer ;
211+ this .metrics = metrics ;
193212 }
194213
195214 @ Override
@@ -218,11 +237,13 @@ private void fillEndpoint(OpenTelemetryEndpoint endpoint) {
218237 Context currentContext = span == null ? context : context .with (span );
219238 serverAttributesExtractor .onStart (attributesBuilder , currentContext , endpoint );
220239 networkAttributesExtractor .onEnd (attributesBuilder , currentContext , endpoint , null , null );
240+ Attributes attributes = attributesBuilder .build ();
221241 if (span != null ) {
222- span .setAllAttributes (attributesBuilder . build () );
242+ span .setAllAttributes (attributes );
223243 } else {
224- spanBuilder .setAllAttributes (attributesBuilder . build () );
244+ spanBuilder .setAllAttributes (attributes );
225245 }
246+ this .attributesBuilder .putAll (attributes );
226247 }
227248
228249 // Added and called in 6.0+
@@ -231,6 +252,7 @@ private void fillEndpoint(OpenTelemetryEndpoint endpoint) {
231252 @ SuppressWarnings ("UnusedMethod" )
232253 public synchronized Tracer .Span start (RedisCommand <?, ?, ?> command ) {
233254 start ();
255+ long startNanos = System .nanoTime ();
234256
235257 Span span = this .span ;
236258 if (span == null ) {
@@ -258,7 +280,7 @@ public synchronized Tracer.Span start(RedisCommand<?, ?, ?> command) {
258280 }
259281 }
260282
261- finish (span );
283+ finish (span , startNanos );
262284 });
263285 }
264286
@@ -270,6 +292,7 @@ public synchronized Tracer.Span start(RedisCommand<?, ?, ?> command) {
270292 @ CanIgnoreReturnValue
271293 public synchronized Tracer .Span start () {
272294 span = spanBuilder .startSpan ();
295+ spanStartNanos = System .nanoTime ();
273296 if (name != null ) {
274297 span .updateName (name );
275298 }
@@ -330,6 +353,7 @@ public synchronized Tracer.Span tag(String key, String value) {
330353 } else {
331354 spanBuilder .setAttribute (key , value );
332355 }
356+ attributesBuilder .put (key , value );
333357 return this ;
334358 }
335359
@@ -347,16 +371,20 @@ public synchronized Tracer.Span error(Throwable throwable) {
347371 @ Override
348372 public synchronized void finish () {
349373 if (span != null ) {
350- finish (span );
374+ finish (span , spanStartNanos );
351375 }
352376 }
353377
354- private void finish (Span span ) {
378+ private void finish (Span span , long startTime ) {
355379 if (name != null ) {
356380 String statement =
357381 sanitizer .sanitize (name , argsList != null ? argsList : splitArgs (argsString ));
358382 if (SemconvStability .emitStableDatabaseSemconv ()) {
359383 span .setAttribute (DB_QUERY_TEXT , statement );
384+ metrics .onEnd (
385+ metrics .onStart (Context .current (), Attributes .empty (), startTime ),
386+ attributesBuilder .build (),
387+ System .nanoTime ());
360388 }
361389 if (SemconvStability .emitOldDatabaseSemconv ()) {
362390 span .setAttribute (DB_STATEMENT , statement );
0 commit comments