|
5 | 5 |
|
6 | 6 | package io.opentelemetry.instrumentation.api.instrumenter; |
7 | 7 |
|
| 8 | +import static io.opentelemetry.api.common.AttributeKey.longKey; |
| 9 | +import static io.opentelemetry.api.common.AttributeKey.stringKey; |
| 10 | +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; |
8 | 11 | import static java.util.Objects.requireNonNull; |
9 | 12 | import static java.util.logging.Level.WARNING; |
10 | 13 |
|
11 | 14 | import com.google.errorprone.annotations.CanIgnoreReturnValue; |
12 | 15 | import io.opentelemetry.api.OpenTelemetry; |
| 16 | +import io.opentelemetry.api.common.AttributeKey; |
| 17 | +import io.opentelemetry.api.common.AttributesBuilder; |
| 18 | +import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; |
| 19 | +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; |
13 | 20 | import io.opentelemetry.api.metrics.Meter; |
14 | 21 | import io.opentelemetry.api.metrics.MeterBuilder; |
15 | 22 | import io.opentelemetry.api.trace.SpanKind; |
@@ -54,6 +61,8 @@ public final class InstrumenterBuilder<REQUEST, RESPONSE> { |
54 | 61 | ConfigPropertiesUtil.getString( |
55 | 62 | "otel.instrumentation.experimental.span-suppression-strategy")); |
56 | 63 |
|
| 64 | + static boolean isIncubator = isIncubator(); |
| 65 | + |
57 | 66 | final OpenTelemetry openTelemetry; |
58 | 67 | final String instrumentationName; |
59 | 68 | SpanNameExtractor<? super REQUEST> spanNameExtractor; |
@@ -84,6 +93,16 @@ public final class InstrumenterBuilder<REQUEST, RESPONSE> { |
84 | 93 | operationListenerAttributesExtractor, "operationListenerAttributesExtractor"))); |
85 | 94 | } |
86 | 95 |
|
| 96 | + private static boolean isIncubator() { |
| 97 | + try { |
| 98 | + Class.forName("io.opentelemetry.api.incubator.ExtendedOpenTelemetry"); |
| 99 | + return true; |
| 100 | + } catch (ClassNotFoundException e) { |
| 101 | + // incubator module is not available |
| 102 | + return false; |
| 103 | + } |
| 104 | + } |
| 105 | + |
87 | 106 | InstrumenterBuilder( |
88 | 107 | OpenTelemetry openTelemetry, |
89 | 108 | String instrumentationName, |
@@ -297,6 +316,7 @@ private Instrumenter<REQUEST, RESPONSE> buildInstrumenter( |
297 | 316 | InstrumenterConstructor<REQUEST, RESPONSE> constructor, |
298 | 317 | SpanKindExtractor<? super REQUEST> spanKindExtractor) { |
299 | 318 |
|
| 319 | + addThreadDetailsAttributeExtractor(this); |
300 | 320 | applyCustomizers(this); |
301 | 321 |
|
302 | 322 | this.spanKindExtractor = spanKindExtractor; |
@@ -446,6 +466,28 @@ public void setSpanNameExtractor( |
446 | 466 | } |
447 | 467 | } |
448 | 468 |
|
| 469 | + private static <RESPONSE, REQUEST> void addThreadDetailsAttributeExtractor( |
| 470 | + InstrumenterBuilder<REQUEST, RESPONSE> builder) { |
| 471 | + if (isIncubator && builder.openTelemetry instanceof ExtendedOpenTelemetry) { |
| 472 | + // Declarative config is used. |
| 473 | + // Otherwise, thread details are configured in |
| 474 | + // io.opentelemetry.javaagent.tooling.AgentTracerProviderConfigurer. |
| 475 | + |
| 476 | + DeclarativeConfigProperties instrumentationConfig = |
| 477 | + ((ExtendedOpenTelemetry) builder.openTelemetry) |
| 478 | + .getConfigProvider() |
| 479 | + .getInstrumentationConfig(); |
| 480 | + |
| 481 | + if (instrumentationConfig != null |
| 482 | + && instrumentationConfig |
| 483 | + .getStructured("java", empty()) |
| 484 | + .getStructured("thread_details", empty()) |
| 485 | + .getBoolean("enabled", false)) { |
| 486 | + builder.addAttributesExtractor(new ThreadDetailsAttributesExtractor<>()); |
| 487 | + } |
| 488 | + } |
| 489 | + } |
| 490 | + |
449 | 491 | private interface InstrumenterConstructor<RQ, RS> { |
450 | 492 | Instrumenter<RQ, RS> create(InstrumenterBuilder<RQ, RS> builder); |
451 | 493 |
|
@@ -490,4 +532,26 @@ public <RQ, RS> void propagateOperationListenersToOnEnd( |
490 | 532 | } |
491 | 533 | }); |
492 | 534 | } |
| 535 | + |
| 536 | + private static class ThreadDetailsAttributesExtractor<RESPONSE, REQUEST> |
| 537 | + implements AttributesExtractor<REQUEST, RESPONSE> { |
| 538 | + // attributes are not stable yet |
| 539 | + private static final AttributeKey<Long> THREAD_ID = longKey("thread.id"); |
| 540 | + private static final AttributeKey<String> THREAD_NAME = stringKey("thread.name"); |
| 541 | + |
| 542 | + @Override |
| 543 | + public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST request) { |
| 544 | + Thread currentThread = Thread.currentThread(); |
| 545 | + attributes.put(THREAD_ID, currentThread.getId()); |
| 546 | + attributes.put(THREAD_NAME, currentThread.getName()); |
| 547 | + } |
| 548 | + |
| 549 | + @Override |
| 550 | + public void onEnd( |
| 551 | + AttributesBuilder attributes, |
| 552 | + Context context, |
| 553 | + REQUEST request, |
| 554 | + @Nullable RESPONSE response, |
| 555 | + @Nullable Throwable error) {} |
| 556 | + } |
493 | 557 | } |
0 commit comments