/
tracer.go
171 lines (149 loc) · 4.61 KB
/
tracer.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
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
164
165
166
167
168
169
170
171
package trace
import (
"log"
"net/http"
api "github.com/kyma-project/kyma/components/event-bus/api/publish"
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
otlog "github.com/opentracing/opentracing-go/log"
zipkin "github.com/openzipkin/zipkin-go-opentracing"
)
const (
// DefaultTraceDebug trace option
DefaultTraceDebug = false
// DefaultTraceAPIURL trace option
DefaultTraceAPIURL = "http://localhost:9411/api/v1/spans"
// DefaultTraceHostPort trace option
DefaultTraceHostPort = "0.0.0.0:0"
// DefaultTraceServiceName trace option
DefaultTraceServiceName = "trace-service"
// DefaultTraceOperationName trace option
DefaultTraceOperationName = "trace-operation"
)
// Options represents the trace options.
type Options struct {
Debug bool
APIURL string
HostPort string
ServiceName string
OperationName string
}
// Tracer encapsulates the trace behaviours.
type Tracer interface {
IsStarted() bool
Options() *Options
Stop()
}
// OpenTracer represents an open tracer.
type OpenTracer struct {
opts Options
collector zipkin.Collector
}
// GetDefaultTraceOptions returns a default trace options instance.
func GetDefaultTraceOptions() *Options {
options := Options{
DefaultTraceDebug,
DefaultTraceAPIURL,
DefaultTraceHostPort,
DefaultTraceServiceName,
DefaultTraceOperationName,
}
return &options
}
// StartNewTracer starts a new tracer.
func StartNewTracer(opts *Options) Tracer {
tracer := new(OpenTracer)
tracer.opts = *opts
tracer.Start()
return tracer
}
// Start starts a new OpenTracer instance.
func (zk *OpenTracer) Start() {
if collector, err := zipkin.NewHTTPCollector(zk.opts.APIURL); err != nil {
log.Printf("Tracer :: Start :: Error creating Zipkin collector :: Error: %v", err)
} else {
recorder := zipkin.NewRecorder(collector, zk.opts.Debug, zk.opts.HostPort, zk.opts.ServiceName)
if tracer, err := zipkin.NewTracer(recorder, zipkin.TraceID128Bit(false)); err != nil {
log.Printf("Tracer :: Start :: Error creating Zipkin tracer :: Error: %v", err)
} else {
zk.collector = collector
opentracing.SetGlobalTracer(tracer)
}
}
}
// IsStarted returns a boolean value indicating id the OpenTracer is started or not.
func (zk *OpenTracer) IsStarted() bool {
return zk.collector != nil
}
// Options returns the OpenTracer options.
func (zk *OpenTracer) Options() *Options {
return &zk.opts
}
// Stop stops the OpenTracer.
func (zk *OpenTracer) Stop() {
if zk.collector != nil {
_ = zk.collector.Close()
}
}
// ReadTraceHeaders returns an opentracing.SpanContext instance.
func ReadTraceHeaders(header *http.Header) *opentracing.SpanContext {
if header == nil {
return nil
}
spanContext, err := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(*header))
if err != nil {
return nil
}
return &spanContext
}
// StartSpan starts and returns an opentracing.Span instance.
func StartSpan(spanContext *opentracing.SpanContext, operationName *string, opts ...opentracing.StartSpanOption) *opentracing.Span {
if spanContext != nil {
if opts == nil || len(opts) == 0 {
opts = make([]opentracing.StartSpanOption, 0)
}
opts = append(opts, opentracing.ChildOf(*spanContext))
}
span := opentracing.StartSpan(*operationName, opts...)
return &span
}
// WriteSpan writes the given opentracing.Span and returns an api.TraceContext instance.
func WriteSpan(span *opentracing.Span) *api.TraceContext {
if span == nil {
log.Printf("Tracer :: WriteSpan :: Error writing trace span nil")
return nil
}
traceContext := make(api.TraceContext)
carrier := opentracing.TextMapCarrier(traceContext)
_ = opentracing.GlobalTracer().Inject((*span).Context(), opentracing.TextMap, carrier)
return &traceContext
}
// TagSpanAsError tags the opentracing.Span as an error with the error details.
func TagSpanAsError(span *opentracing.Span, errorMessage, errorStack string) {
if span != nil {
ext.Error.Set(*span, true)
// log more details about the error
var fields []otlog.Field
if len(errorMessage) != 0 {
fields = append(fields, otlog.String("message", errorMessage)) // human readable error message
}
if len(errorStack) != 0 {
fields = append(fields, otlog.String("stack", errorStack)) // error stacktrace
}
(*span).LogFields(fields...)
}
}
// FinishSpan finishes the opentracing.Span.
func FinishSpan(span *opentracing.Span) {
if span != nil {
(*span).Finish()
}
}
// SetSpanTags sets the opentracing.Span tags.
func SetSpanTags(span *opentracing.Span, tags *map[string]string) {
if span != nil && tags != nil {
for key, value := range *tags {
(*span).SetTag(key, value)
}
}
}