@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 144 lines 3.82 KB
Raw
1 package tracing
2
3 import (
4 "fmt"
5 "net/http"
6
7 "go.uber.org/zap"
8
9 "github.com/caddyserver/caddy/v2"
10 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
11 "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
12 "github.com/caddyserver/caddy/v2/modules/caddyhttp"
13 )
14
15 func init() {
16 caddy.RegisterModule(Tracing{})
17 httpcaddyfile.RegisterHandlerDirective("tracing", parseCaddyfile)
18 }
19
20 // Tracing implements an HTTP handler that adds support for distributed tracing,
21 // using OpenTelemetry. This module is responsible for the injection and
22 // propagation of the trace context. Configure this module via environment
23 // variables (see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md).
24 // Some values can be overwritten in the configuration file.
25 type Tracing struct {
26 // SpanName is a span name. It should follow the naming guidelines here:
27 // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#span
28 SpanName string `json:"span"`
29
30 // SpanAttributes are custom key-value pairs to be added to spans
31 SpanAttributes map[string]string `json:"span_attributes,omitempty"`
32
33 // otel implements opentelemetry related logic.
34 otel openTelemetryWrapper
35
36 logger *zap.Logger
37 }
38
39 // CaddyModule returns the Caddy module information.
40 func (Tracing) CaddyModule() caddy.ModuleInfo {
41 return caddy.ModuleInfo{
42 ID: "http.handlers.tracing",
43 New: func() caddy.Module { return new(Tracing) },
44 }
45 }
46
47 // Provision implements caddy.Provisioner.
48 func (ot *Tracing) Provision(ctx caddy.Context) error {
49 ot.logger = ctx.Logger()
50
51 var err error
52 ot.otel, err = newOpenTelemetryWrapper(ctx, ot.SpanName, ot.SpanAttributes)
53
54 return err
55 }
56
57 // Cleanup implements caddy.CleanerUpper and closes any idle connections. It
58 // calls Shutdown method for a trace provider https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#shutdown.
59 func (ot *Tracing) Cleanup() error {
60 if err := ot.otel.cleanup(ot.logger); err != nil {
61 return fmt.Errorf("tracerProvider shutdown: %w", err)
62 }
63 return nil
64 }
65
66 // ServeHTTP implements caddyhttp.MiddlewareHandler.
67 func (ot *Tracing) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
68 return ot.otel.ServeHTTP(w, r, next)
69 }
70
71 // UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
72 //
73 // tracing {
74 // [span <span_name>]
75 // [span_attributes {
76 // attr1 value1
77 // attr2 value2
78 // }]
79 // }
80 func (ot *Tracing) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
81 setParameter := func(d *caddyfile.Dispenser, val *string) error {
82 if d.NextArg() {
83 *val = d.Val()
84 } else {
85 return d.ArgErr()
86 }
87 if d.NextArg() {
88 return d.ArgErr()
89 }
90 return nil
91 }
92
93 // paramsMap is a mapping between "string" parameter from the Caddyfile and its destination within the module
94 paramsMap := map[string]*string{
95 "span": &ot.SpanName,
96 }
97
98 d.Next() // consume directive name
99 if d.NextArg() {
100 return d.ArgErr()
101 }
102
103 for d.NextBlock(0) {
104 switch d.Val() {
105 case "span_attributes":
106 if ot.SpanAttributes == nil {
107 ot.SpanAttributes = make(map[string]string)
108 }
109 for d.NextBlock(1) {
110 key := d.Val()
111 if !d.NextArg() {
112 return d.ArgErr()
113 }
114 value := d.Val()
115 if d.NextArg() {
116 return d.ArgErr()
117 }
118 ot.SpanAttributes[key] = value
119 }
120 default:
121 if dst, ok := paramsMap[d.Val()]; ok {
122 if err := setParameter(d, dst); err != nil {
123 return err
124 }
125 } else {
126 return d.ArgErr()
127 }
128 }
129 }
130 return nil
131 }
132
133 func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
134 var m Tracing
135 err := m.UnmarshalCaddyfile(h.Dispenser)
136 return &m, err
137 }
138
139 // Interface guards
140 var (
141 _ caddy.Provisioner = (*Tracing)(nil)
142 _ caddyhttp.MiddlewareHandler = (*Tracing)(nil)
143 _ caddyfile.Unmarshaler = (*Tracing)(nil)
144 )