-
Notifications
You must be signed in to change notification settings - Fork 5
/
OpenTracingCollector.java
163 lines (150 loc) · 6.32 KB
/
OpenTracingCollector.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package io.opentracing.contrib.jdbi;
import io.opentracing.Span;
import io.opentracing.Tracer;
import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.TimingCollector;
/**
* OpenTracingCollector is a JDBI TimingCollector that creates OpenTracing Spans for each JDBI SQLStatement.
*
* <p>Example usage:
* <pre>{@code
* io.opentracing.Tracer tracer = ...;
* DBI dbi = ...;
*
* // One time only: bind OpenTracing to the DBI instance as a TimingCollector.
* dbi.setTimingCollector(new OpenTracingCollector(tracer));
*
* // Elsewhere, anywhere a `Handle` is available:
* Handle handle = ...;
* Span parentSpan = ...; // optional
*
* // Create statements as usual with your `handle` instance.
* Query<Map<String, Object>> statement = handle.createQuery("SELECT COUNT(*) FROM accounts");
*
* // If a parent Span is available, establish the relationship via setParent.
* OpenTracingCollector.setParent(statement, parent);
*
* // Use JDBI as per usual, and Spans will be created for every SQLStatement automatically.
* List<Map<String, Object>> results = statement.list();
* }</pre>
*/
public class OpenTracingCollector implements TimingCollector {
public final static String PARENT_SPAN_ATTRIBUTE_KEY = "io.opentracing.parent";
private final Tracer tracer;
private final SpanDecorator spanDecorator;
private final ActiveSpanSource activeSpanSource;
public OpenTracingCollector(Tracer tracer) {
this(tracer, SpanDecorator.DEFAULT);
}
public OpenTracingCollector(Tracer tracer, SpanDecorator spanDecorator) {
this(tracer, spanDecorator, null);
}
public OpenTracingCollector(Tracer tracer, ActiveSpanSource spanSource) {
this(tracer, SpanDecorator.DEFAULT, spanSource);
}
public OpenTracingCollector(Tracer tracer, SpanDecorator operationNamer, ActiveSpanSource spanSource) {
this.tracer = tracer;
this.spanDecorator = operationNamer;
this.activeSpanSource = spanSource;
}
public void collect(long elapsedNanos, StatementContext statementContext) {
long nowMicros = System.currentTimeMillis() * 1000;
Tracer.SpanBuilder builder = tracer
.buildSpan(spanDecorator.generateOperationName(statementContext))
.withStartTimestamp(nowMicros - (elapsedNanos / 1000));
Span parent = (Span)statementContext.getAttribute(PARENT_SPAN_ATTRIBUTE_KEY);
if (parent == null && this.activeSpanSource != null) {
parent = this.activeSpanSource.activeSpan(statementContext);
}
if (parent != null) {
builder = builder.asChildOf(parent);
}
Span collectSpan = builder.start();
spanDecorator.decorateSpan(collectSpan, elapsedNanos, statementContext);
try {
collectSpan.log("SQL query finished", statementContext.getRawSql());
} finally {
collectSpan.finish(nowMicros);
}
}
/**
* Establish an explicit parent relationship for the (child) Span associated with a SQLStatement.
*
* @param statement the JDBI SQLStatement which will act as the child of `parent`
* @param parent the parent Span for `statement`
*/
public static void setParent(SQLStatement<?> statement, Span parent) {
statement.getContext().setAttribute(PARENT_SPAN_ATTRIBUTE_KEY, parent);
}
/**
* SpanDecorator allows the OpenTracingCollector user to control the precise naming and decoration of OpenTracing
* Spans emitted by the collector.
*
* @see OpenTracingCollector#OpenTracingCollector(Tracer, SpanDecorator)
*/
public interface SpanDecorator {
public static SpanDecorator DEFAULT = new SpanDecorator() {
public String generateOperationName(StatementContext ctx) {
return "DBI Statement";
}
@Override
public void decorateSpan(Span jdbiSpan, long elapsedNanos, StatementContext ctx) {
// (by default, do nothing)
}
};
/**
* Transform an DBI StatementContext into an OpenTracing Span operation name.
*
* @param ctx the StatementContext passed to TimingCollector.collect()
* @return an operation name suitable for the associated OpenTracing Span
*/
public String generateOperationName(StatementContext ctx);
/**
* Get the active Span (to use as a parent for any DBI Spans). Implementations may or may not need to refer
* to the StatementContext.
*
* @param jdbiSpan the JDBI Span to decorate (before `finish` is called)
* @param elapsedNanos the elapsedNanos passed to TimingCollector.collect()
* @param ctx the StatementContext passed to TimingCollector.collect()
*/
public void decorateSpan(Span jdbiSpan, long elapsedNanos, StatementContext ctx);
}
/**
* An abstract API that allows the OpenTracingCollector to customize how parent Spans are discovered.
*
* For instance, if Spans are stored in a thread-local variable, an ActiveSpanSource could access them like so:
* <p>Example usage:
* <pre>{@code
* public class SomeClass {
* // Thread local variable containing each thread's ID
* private static final ThreadLocal<Span> activeSpan =
* new ThreadLocal<Span>() {
* protected Integer initialValue() {
* return null;
* }
* };
* };
*
* ... elsewhere ...
* ActiveSpanSource spanSource = new ActiveSpanSource() {
* public Span activeSpan(StatementContext ctx) {
* // (In this example we ignore `ctx` entirely)
* return activeSpan.get();
* }
* };
* OpenTracingCollector otColl = new OpenTracingCollector(tracer, spanSource);
* ...
* }</pre>
*/
public interface ActiveSpanSource {
/**
* Get the active Span (to use as a parent for any DBI Spans). Implementations may or may not need to refer
* to the StatementContext.
*
* @param ctx the StatementContext that needs to be collected and traced
* @return the currently active Span (for this thread, etc), or null if no such Span could be found.
*/
public Span activeSpan(StatementContext ctx);
}
}