|
6 | 6 | package io.opentelemetry.contrib.stacktrace; |
7 | 7 |
|
8 | 8 | import io.opentelemetry.api.common.AttributeKey; |
9 | | -import io.opentelemetry.contrib.stacktrace.internal.AbstractSimpleChainingSpanProcessor; |
10 | | -import io.opentelemetry.contrib.stacktrace.internal.MutableSpan; |
11 | | -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; |
| 9 | +import io.opentelemetry.context.Context; |
| 10 | +import io.opentelemetry.sdk.trace.ReadWriteSpan; |
12 | 11 | import io.opentelemetry.sdk.trace.ReadableSpan; |
13 | | -import io.opentelemetry.sdk.trace.SpanProcessor; |
| 12 | +import io.opentelemetry.sdk.trace.internal.ExtendedSpanProcessor; |
14 | 13 | import java.io.PrintWriter; |
15 | 14 | import java.io.StringWriter; |
16 | | -import java.time.Duration; |
17 | 15 | import java.util.function.Predicate; |
18 | | -import java.util.logging.Level; |
19 | | -import java.util.logging.Logger; |
20 | 16 |
|
21 | | -public class StackTraceSpanProcessor extends AbstractSimpleChainingSpanProcessor { |
22 | | - |
23 | | - private static final String CONFIG_MIN_DURATION = |
24 | | - "otel.java.experimental.span-stacktrace.min.duration"; |
25 | | - private static final Duration CONFIG_MIN_DURATION_DEFAULT = Duration.ofMillis(5); |
| 17 | +public class StackTraceSpanProcessor implements ExtendedSpanProcessor { |
26 | 18 |
|
27 | 19 | // inlined incubating attribute to prevent direct dependency on incubating semconv |
28 | 20 | private static final AttributeKey<String> SPAN_STACKTRACE = |
29 | 21 | AttributeKey.stringKey("code.stacktrace"); |
30 | 22 |
|
31 | | - private static final Logger logger = Logger.getLogger(StackTraceSpanProcessor.class.getName()); |
32 | | - |
33 | 23 | private final long minSpanDurationNanos; |
34 | 24 |
|
35 | 25 | private final Predicate<ReadableSpan> filterPredicate; |
36 | 26 |
|
37 | 27 | /** |
38 | | - * @param next next span processor to invoke |
39 | 28 | * @param minSpanDurationNanos minimum span duration in ns for stacktrace capture |
40 | 29 | * @param filterPredicate extra filter function to exclude spans if needed |
41 | 30 | */ |
42 | 31 | public StackTraceSpanProcessor( |
43 | | - SpanProcessor next, long minSpanDurationNanos, Predicate<ReadableSpan> filterPredicate) { |
44 | | - super(next); |
45 | | - this.minSpanDurationNanos = minSpanDurationNanos; |
46 | | - this.filterPredicate = filterPredicate; |
| 32 | + long minSpanDurationNanos, Predicate<ReadableSpan> filterPredicate) { |
47 | 33 | if (minSpanDurationNanos < 0) { |
48 | | - logger.log(Level.FINE, "Stack traces capture is disabled"); |
49 | | - } else { |
50 | | - logger.log( |
51 | | - Level.FINE, |
52 | | - "Stack traces will be added to spans with a minimum duration of {0} nanos", |
53 | | - minSpanDurationNanos); |
| 34 | + throw new IllegalArgumentException("minimal span duration must be positive or zero"); |
54 | 35 | } |
55 | | - } |
56 | 36 |
|
57 | | - /** |
58 | | - * @param next next span processor to invoke |
59 | | - * @param config configuration |
60 | | - * @param filterPredicate extra filter function to exclude spans if needed |
61 | | - */ |
62 | | - public StackTraceSpanProcessor( |
63 | | - SpanProcessor next, ConfigProperties config, Predicate<ReadableSpan> filterPredicate) { |
64 | | - this( |
65 | | - next, |
66 | | - config.getDuration(CONFIG_MIN_DURATION, CONFIG_MIN_DURATION_DEFAULT).toNanos(), |
67 | | - filterPredicate); |
| 37 | + this.minSpanDurationNanos = minSpanDurationNanos; |
| 38 | + this.filterPredicate = filterPredicate; |
68 | 39 | } |
69 | 40 |
|
70 | 41 | @Override |
71 | | - protected boolean requiresStart() { |
| 42 | + public boolean isStartRequired() { |
72 | 43 | return false; |
73 | 44 | } |
74 | 45 |
|
75 | 46 | @Override |
76 | | - protected boolean requiresEnd() { |
| 47 | + public void onStart(Context context, ReadWriteSpan readWriteSpan) {} |
| 48 | + |
| 49 | + @Override |
| 50 | + public boolean isOnEndingRequired() { |
77 | 51 | return true; |
78 | 52 | } |
79 | 53 |
|
80 | 54 | @Override |
81 | | - protected ReadableSpan doOnEnd(ReadableSpan span) { |
82 | | - if (minSpanDurationNanos < 0 || span.getLatencyNanos() < minSpanDurationNanos) { |
83 | | - return span; |
| 55 | + public void onEnding(ReadWriteSpan span) { |
| 56 | + if (span.getLatencyNanos() < minSpanDurationNanos) { |
| 57 | + return; |
84 | 58 | } |
85 | 59 | if (span.getAttribute(SPAN_STACKTRACE) != null) { |
86 | 60 | // Span already has a stacktrace, do not override |
87 | | - return span; |
| 61 | + return; |
88 | 62 | } |
89 | 63 | if (!filterPredicate.test(span)) { |
90 | | - return span; |
| 64 | + return; |
91 | 65 | } |
92 | | - MutableSpan mutableSpan = MutableSpan.makeMutable(span); |
| 66 | + span.setAttribute(SPAN_STACKTRACE, generateSpanEndStacktrace()); |
| 67 | + } |
93 | 68 |
|
94 | | - String stacktrace = generateSpanEndStacktrace(); |
95 | | - mutableSpan.setAttribute(SPAN_STACKTRACE, stacktrace); |
96 | | - return mutableSpan; |
| 69 | + @Override |
| 70 | + public boolean isEndRequired() { |
| 71 | + return false; |
97 | 72 | } |
98 | 73 |
|
| 74 | + @Override |
| 75 | + public void onEnd(ReadableSpan readableSpan) {} |
| 76 | + |
99 | 77 | private static String generateSpanEndStacktrace() { |
100 | 78 | Throwable exception = new Throwable(); |
101 | 79 | StringWriter stringWriter = new StringWriter(); |
|
0 commit comments