/
opentracing.go
106 lines (90 loc) · 2.7 KB
/
opentracing.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
package buffet
import (
"strings"
"github.com/gobuffalo/buffalo"
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
olog "github.com/opentracing/opentracing-go/log"
)
var tracer opentracing.Tracer
// OpenTracing is a buffalo middleware that adds the necessary
// components to the request to make it traced through OpenTracing.
// Initialize it by passing in an opentracing.Tracer.
func OpenTracing(tr opentracing.Tracer) buffalo.MiddlewareFunc {
tracer = tr
return func(next buffalo.Handler) buffalo.Handler {
return func(c buffalo.Context) error {
opName := "HTTP " + c.Request().Method + c.Request().URL.Path
rt := c.Value("current_route")
if rt != nil {
route, ok := rt.(buffalo.RouteInfo)
if ok {
opName = operation(route.HandlerName)
}
}
wireContext, _ := tr.Extract(
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(c.Request().Header))
// Create the span referring to the RPC client if available.
// If wireContext == nil, a root span will be created.
sp := tr.StartSpan(
opName,
ext.RPCServerOption(wireContext))
ext.HTTPMethod.Set(sp, c.Request().Method)
ext.HTTPUrl.Set(sp, c.Request().URL.String())
ext.Component.Set(sp, "buffalo")
c.Set("otspan", sp)
err := next(c)
if err != nil {
ext.Error.Set(sp, true)
sp.LogFields(olog.Error(err))
}
br, ok := c.Response().(*buffalo.Response)
if ok {
ext.HTTPStatusCode.Set(sp, uint16(br.Status))
}
sp.Finish()
return err
}
}
}
// SpanFromContext attempts to retrieve a span from the Buffalo context,
// returning it if found. If none is found a new one is created.
func SpanFromContext(c buffalo.Context) opentracing.Span {
// fast path - find span in the buffalo context and return it
sp := c.Value("otspan")
if sp != nil {
span, ok := sp.(opentracing.Span)
if ok {
c.LogField("span found", true)
return span
}
}
c.LogField("span found", false)
// none exists, make a new one (sadface)
opName := "HTTP " + c.Request().Method + c.Request().URL.Path
rt := c.Value("current_route")
if rt != nil {
route, ok := rt.(buffalo.RouteInfo)
if ok {
opName = operation(route.HandlerName)
}
}
span := tracer.StartSpan(opName)
ext.HTTPMethod.Set(span, c.Request().Method)
ext.HTTPUrl.Set(span, c.Request().URL.String())
ext.Component.Set(span, "buffalo")
return span
}
// ChildSpan returns a child span derived from the buffalo context "c"
func ChildSpan(opname string, c buffalo.Context) opentracing.Span {
psp := SpanFromContext(c)
sp := tracer.StartSpan(
opname,
opentracing.ChildOf(psp.Context()))
return sp
}
func operation(s string) string {
chunks := strings.Split(s, ".")
return chunks[len(chunks)-1]
}