/
otel.go
67 lines (57 loc) · 1.74 KB
/
otel.go
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
package wpgx
import (
"context"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
semconv "go.opentelemetry.io/otel/semconv/v1.11.0"
"go.opentelemetry.io/otel/trace"
)
const (
// TracerName is the name of the tracer. This will be used as an attribute
// on each span.
tracerName = "github.com/stumble/wpgx"
// InstrumentationVersion is the version of the wpgx library. This will
// be used as an attribute on each span.
instrumentationVersion = "v0.0.1"
)
type tracer struct {
tracer trace.Tracer
attrs []attribute.KeyValue
}
// NewTracer returns a new Tracer.
func newTracer() *tracer {
return &tracer{
tracer: otel.GetTracerProvider().Tracer(
tracerName, trace.WithInstrumentationVersion(instrumentationVersion)),
attrs: []attribute.KeyValue{
semconv.DBSystemPostgreSQL,
},
}
}
func recordError(span trace.Span, err error) {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
}
// TraceStart is called at the beginning of Query, QueryRow, and Exec calls.
// The returned context is used for the rest of the call and will be passed to TraceQueryEnd.
func (t *tracer) TraceStart(ctx context.Context, queryName string) context.Context {
if !trace.SpanFromContext(ctx).IsRecording() {
return ctx
}
opts := []trace.SpanStartOption{
trace.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(t.attrs...),
trace.WithAttributes(semconv.DBStatementKey.String(queryName)),
}
ctx, _ = t.tracer.Start(ctx, queryName, opts...)
return ctx
}
// TraceQueryEnd is called at the end of Query, QueryRow, and Exec calls.
func (t *tracer) TraceEnd(ctx context.Context, err error) {
span := trace.SpanFromContext(ctx)
recordError(span, err)
span.End()
}