-
Notifications
You must be signed in to change notification settings - Fork 179
Expand file tree
/
Copy pathStackTraceAutoConfig.java
More file actions
115 lines (102 loc) · 4.06 KB
/
StackTraceAutoConfig.java
File metadata and controls
115 lines (102 loc) · 4.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.contrib.stacktrace;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.SEVERE;
import com.google.auto.service.AutoService;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.trace.ReadableSpan;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.Duration;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
@AutoService(AutoConfigurationCustomizerProvider.class)
public class StackTraceAutoConfig implements AutoConfigurationCustomizerProvider {
private static final Logger log = Logger.getLogger(StackTraceAutoConfig.class.getName());
static final String PREFIX = "otel.java.experimental.span-stacktrace.";
static final String CONFIG_MIN_DURATION = PREFIX + "min.duration";
private static final Duration CONFIG_MIN_DURATION_DEFAULT = Duration.ofMillis(5);
private static final String CONFIG_FILTER = PREFIX + "filter";
@Override
public void customize(AutoConfigurationCustomizer config) {
config.addTracerProviderCustomizer(
(providerBuilder, properties) -> {
if (getMinDuration(properties) >= 0) {
providerBuilder.addSpanProcessor(create(properties));
}
return providerBuilder;
});
}
static StackTraceSpanProcessor create(ConfigProperties properties) {
return new StackTraceSpanProcessor(getMinDuration(properties), getFilterPredicate(properties));
}
// package-private for testing
static long getMinDuration(ConfigProperties properties) {
long minDuration =
properties.getDuration(CONFIG_MIN_DURATION, CONFIG_MIN_DURATION_DEFAULT).toNanos();
if (minDuration < 0) {
log.fine("Stack traces capture is disabled");
} else {
log.log(
FINE,
"Stack traces will be added to spans with a minimum duration of {0} nanos",
minDuration);
}
return minDuration;
}
// package private for testing
static Predicate<ReadableSpan> getFilterPredicate(ConfigProperties properties) {
String filterClass = properties.getString(CONFIG_FILTER);
Predicate<ReadableSpan> filter = null;
if (filterClass != null) {
Class<?> filterType = getFilterType(filterClass);
if (filterType != null) {
filter = getFilterInstance(filterType);
}
}
if (filter == null) {
// if value is set, lack of filtering is likely an error and must be reported
Level disabledLogLevel = filterClass != null ? SEVERE : FINE;
log.log(disabledLogLevel, "Span stacktrace filtering disabled");
return span -> true;
} else {
log.fine("Span stacktrace filtering enabled with: " + filterClass);
return filter;
}
}
@Nullable
private static Class<?> getFilterType(String filterClass) {
try {
Class<?> filterType = Class.forName(filterClass);
if (!Predicate.class.isAssignableFrom(filterType)) {
log.severe("Filter must be a subclass of java.util.function.Predicate");
return null;
}
return filterType;
} catch (ClassNotFoundException e) {
log.severe("Unable to load filter class: " + filterClass);
return null;
}
}
@Nullable
@SuppressWarnings("unchecked") // filterType must implement Predicate<ReadableSpan>
private static Predicate<ReadableSpan> getFilterInstance(Class<?> filterType) {
try {
Constructor<?> constructor = filterType.getConstructor();
return (Predicate<ReadableSpan>) constructor.newInstance();
} catch (NoSuchMethodException
| InstantiationException
| IllegalAccessException
| InvocationTargetException e) {
log.severe("Unable to create filter instance with no-arg constructor: " + filterType);
return null;
}
}
}