-
Notifications
You must be signed in to change notification settings - Fork 33
/
ServerTracingFilter.java
141 lines (123 loc) · 5.2 KB
/
ServerTracingFilter.java
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package io.opentracing.contrib.jaxrs2.server;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.Tracer;
import io.opentracing.contrib.jaxrs2.internal.CastUtils;
import io.opentracing.contrib.jaxrs2.internal.SpanWrapper;
import io.opentracing.propagation.Format;
import io.opentracing.tag.Tags;
import javax.annotation.Priority;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Context;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import static io.opentracing.contrib.jaxrs2.internal.SpanWrapper.PROPERTY_NAME;
/**
* @author Pavol Loffay
*/
@Priority(Priorities.HEADER_DECORATOR)
public class ServerTracingFilter implements ContainerRequestFilter, ContainerResponseFilter {
private static final Logger log = Logger.getLogger(ServerTracingFilter.class.getName());
private Tracer tracer;
private List<ServerSpanDecorator> spanDecorators;
private String operationName;
private OperationNameProvider operationNameProvider;
private Pattern skipPattern;
private final boolean joinExistingActiveSpan;
protected ServerTracingFilter(
Tracer tracer,
String operationName,
List<ServerSpanDecorator> spanDecorators,
OperationNameProvider operationNameProvider,
Pattern skipPattern,
boolean joinExistingActiveSpan) {
this.tracer = tracer;
this.operationName = operationName;
this.spanDecorators = new ArrayList<>(spanDecorators);
this.operationNameProvider = operationNameProvider;
this.skipPattern = skipPattern;
this.joinExistingActiveSpan = joinExistingActiveSpan;
}
@Context
private HttpServletRequest httpServletRequest;
@Override
public void filter(ContainerRequestContext requestContext) {
// return in case filter if registered twice
if (requestContext.getProperty(PROPERTY_NAME) != null || matchesSkipPattern(requestContext)) {
return;
}
if (tracer != null) {
SpanContext parentSpanContext = parentSpanContext(requestContext);
Span span = tracer.buildSpan(operationNameProvider.operationName(requestContext))
.ignoreActiveSpan()
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
.asChildOf(parentSpanContext)
.start();
if (spanDecorators != null) {
for (ServerSpanDecorator decorator: spanDecorators) {
decorator.decorateRequest(requestContext, span);
}
}
// override operation name set by @Traced
if (this.operationName != null) {
span.setOperationName(operationName);
}
if (log.isLoggable(Level.FINEST)) {
log.finest("Creating server span: " + operationName);
}
requestContext.setProperty(PROPERTY_NAME, new SpanWrapper(span, tracer.activateSpan(span)));
}
}
/**
* Returns a parent for a span created by this filter (jax-rs span).
* The context from the active span takes precedence over context in the request,
* but only if joinExistingActiveSpan has been set.
* The current active span should be child-of extracted context and for example
* created at a lower level e.g. jersey filter.
*/
private SpanContext parentSpanContext(ContainerRequestContext requestContext) {
Span activeSpan = tracer.activeSpan();
if (activeSpan != null && this.joinExistingActiveSpan) {
return activeSpan.context();
} else {
return tracer.extract(
Format.Builtin.HTTP_HEADERS,
new ServerHeadersExtractTextMap(requestContext.getHeaders())
);
}
}
@Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) {
SpanWrapper spanWrapper = CastUtils.cast(requestContext.getProperty(PROPERTY_NAME), SpanWrapper.class);
if (spanWrapper == null) {
return;
}
if (spanDecorators != null) {
for (ServerSpanDecorator decorator: spanDecorators) {
decorator.decorateResponse(responseContext, spanWrapper.get());
}
}
}
private boolean matchesSkipPattern(ContainerRequestContext requestContext) {
// skip URLs matching skip pattern
// e.g. pattern is defined as '/health|/status' then URL 'http://localhost:5000/context/health' won't be traced
String path = requestContext.getUriInfo().getPath();
if (skipPattern != null && path != null) {
if (path.length() > 0 && path.charAt(0) != '/') {
path = "/" + path;
}
return skipPattern.matcher(path).matches();
}
return false;
}
}