-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathflexmetrics.go
159 lines (131 loc) · 4.19 KB
/
flexmetrics.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
package flexmetrics
import (
"context"
"fmt"
"log"
"net"
"net/http"
"net/http/pprof"
"os"
"time"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
const (
// DefaultAddr is the port that we listen to the prometheus path on by default.
DefaultAddr = "0.0.0.0:9090"
// DefaultPath is the path where we expose prometheus by default.
DefaultPath = "/metrics"
// DefaultReadTimeout is the default read timeout for the http server.
DefaultReadTimeout = 5 * time.Second
// DefaultReadHeaderTimeout is the default read header timeout for the http server.
DefaultReadHeaderTimeout = 1 * time.Second
// DefaultIdleTimeout is the default idle timeout for the http server.
DefaultIdleTimeout = 1 * time.Second
// DefaultWriteTimeout is the default write timeout for the http server.
DefaultWriteTimeout = 15 * time.Second
)
// default package logger to be used if no logger is provided.
var logger = log.New(os.Stderr, "flexmetrics: ", 0)
// Option is a type of func that allows you change defaults of the *Server
// returned by New.
type Option func(s *Server)
// WithPath allows you to specify the path Prometheus metrics should be served
// on. If provided, this option will override the use of
// METRICS_PROMETHEUS_PATH environment variable.
func WithPath(path string) Option {
return func(s *Server) {
s.path = path
}
}
// WithAddr allows you to specify the address the HTTP server should bind to.
// If provided, this option will override the use of METRICS_ADDR environment
// variable.
func WithAddr(addr string) Option {
return func(s *Server) {
s.server.Addr = addr
}
}
// WithServer allows you to provide your own HTTP server to be used to serve
// metrics.
func WithServer(server *http.Server) Option {
return func(s *Server) {
s.server = server
}
}
// Logger defines any logger able to call Printf.
type Logger interface {
Printf(format string, v ...interface{})
}
// WithLogger allows you to set a logger for the server.
func WithLogger(l Logger) Option {
return func(s *Server) {
s.logger = l
}
}
// New creates a new default metrics server.
func New(options ...Option) *Server {
path := os.Getenv("METRICS_PROMETHEUS_PATH")
if path == "" {
path = DefaultPath
}
addr := os.Getenv("METRICS_ADDR")
if addr == "" {
addr = DefaultAddr
}
server := &Server{
logger: logger,
path: path,
server: &http.Server{
Addr: addr,
ReadTimeout: DefaultReadTimeout,
ReadHeaderTimeout: DefaultReadHeaderTimeout,
IdleTimeout: DefaultIdleTimeout,
WriteTimeout: DefaultWriteTimeout,
},
}
for _, option := range options {
option(server)
}
return server
}
// Server represents a prometheus metrics server.
type Server struct {
logger Logger
server *http.Server
path string
}
// serverAddrKeyType is a type used to store the server address in the context.
type serverAddrKeyType string
// serverAddrKey is the key used to store the server address in the context.
const serverAddrKey serverAddrKeyType = "serverAddr"
// Run will start the metrics server.
func (s *Server) Run(ctx context.Context) error {
lis, err := net.Listen("tcp", s.server.Addr)
if err != nil {
return err
}
// use the provided context for the server
s.server.BaseContext = func(lis net.Listener) context.Context {
ctx = context.WithValue(ctx, serverAddrKey, lis.Addr().String())
return ctx
}
mux := http.NewServeMux()
mux.Handle(s.path, promhttp.Handler())
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
s.server.Handler = mux
s.logger.Printf("serving profiling and prometheus metrics over http on http://%s%s", lis.Addr().String(), s.path)
return s.server.Serve(lis)
}
// Halt will attempt to gracefully shut down the server.
func (s *Server) Halt(ctx context.Context) error {
listenerAddress, ok := ctx.Value(serverAddrKey).(string)
if !ok {
return fmt.Errorf("listener address not found in context")
}
s.logger.Printf("stopping serving profiling and prometheus metrics over http on http://%s%s", listenerAddress, s.path)
return s.server.Shutdown(ctx)
}