forked from zendesk/statsd-logger
/
trace_server.go
113 lines (92 loc) · 2.42 KB
/
trace_server.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
package trace
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"time"
)
// DefaultAddress is the default address to listen to traces
const DefaultAddress = ":8126"
// Server mimics the HTTP API exposed by the datadog APM agent
type Server struct {
// tcp address to listen on
Address string
server *http.Server
output io.Writer
formatter Formatter
}
// ServerOption provides optional configuration for initializing a new server
type ServerOption func(*serverConfig)
type serverConfig struct {
output io.Writer
formatter Formatter
}
// WithOutput allows for overriding the output destination for traces
func WithOutput(output io.Writer) ServerOption {
return func(config *serverConfig) {
config.output = output
}
}
// NewServer creates a new trace server
func NewServer(address string, options ...ServerOption) *Server {
config := serverConfig{
output: os.Stdout,
formatter: ColourFormatter{},
}
for _, opt := range options {
opt(&config)
}
server := Server{
Address: address,
output: config.output,
formatter: config.formatter,
}
mux := http.NewServeMux()
// v0.3 & v0.4 formats are messagepack based
mux.HandleFunc("/v0.3/traces", server.HandleTrace)
mux.HandleFunc("/v0.4/traces", server.HandleTrace)
httpServer := &http.Server{
Addr: address,
Handler: mux,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
}
server.server = httpServer
return &server
}
// Listen starts the trace server
func (server Server) Listen() error {
fmt.Printf("[Trace] Listening at %s\n", server.Address)
return server.server.ListenAndServe()
}
// HandleTrace receives tracing requests from datadog clients and prints them to the console
func (server Server) HandleTrace(w http.ResponseWriter, req *http.Request) {
body, err := ioutil.ReadAll(req.Body)
if err != nil {
log.Printf("error reading body: %+v", err)
w.WriteHeader(422)
return
}
defer req.Body.Close()
spans, err := DecodeSpans(body)
if err != nil {
log.Printf("error decoding spans: %+v", err)
w.WriteHeader(422)
return
}
for _, span := range spans {
fmt.Fprintf(server.output, server.formatter.Format(span))
}
w.WriteHeader(200)
}
// Close shuts down the trace server
func (server Server) Close() error {
fmt.Println("[Trace] Shutting down")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
return server.server.Shutdown(ctx)
}