Skip to content

Commit a71b61f

Browse files
authored
Merge pull request #8 from peterbourgon/decls-endpoint
Add -declpath flag
2 parents 3df8fbf + 08b82b7 commit a71b61f

File tree

3 files changed

+80
-22
lines changed

3 files changed

+80
-22
lines changed

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Prometheus metrics aggregator [![Latest Release](https://img.shields.io/github/release/peterbourgon/prometheus-aggregator.svg?style=flat-square)](https://github.com/peterbourgon/prometheus-aggregator/releases/latest) [![Travis CI](https://travis-ci.org/peterbourgon/prometheus-aggregator.svg?branch=master)](https://travis-ci.org/peterbourgon/prometheus-aggregator)
1+
# Prometheus metrics aggregator [![Latest Release](https://img.shields.io/github/release/peterbourgon/prometheus-aggregator.svg?style=flat-square)](https://github.com/peterbourgon/prometheus-aggregator/releases/latest) [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fpeterbourgon%2Fprometheus-aggregator%2Fbadge&style=flat-square&label=build)](https://github.com/peterbourgon/prometheus-aggregator/actions?query=workflow%3ATest)
22

33
Receive and aggregate metrics for consumption by a Prometheus server.
44

@@ -47,13 +47,14 @@ USAGE
4747
FLAGS
4848
-debug false log debug information
4949
-declfile ... file containing JSON metric declarations
50+
-declpath ... sibling path to /metrics serving initial metric declarations
5051
-example false print example declfile to stdout and return
5152
-prometheus tcp://127.0.0.1:8192/metrics address for Prometheus scrapes
5253
-socket tcp://127.0.0.1:8191 address for direct socket metric writes
5354
-strict false disconnect clients when they send bad data
5455
5556
VERSION
56-
0.0.12
57+
0.0.14
5758
```
5859

5960
## How it works
@@ -92,6 +93,11 @@ a file containing a JSON array of multiple JSON objects, and pass it to the
9293
program at startup via the `-declfile` flag. Or mix and match both! Life is
9394
full of possibility.
9495

96+
New! Exciting! Great Value! An optional `-declpath` flag allows you to serve
97+
your initial metric declarations on a sibling path to your Prometheus metrics
98+
telemetry. This can be useful if you want to programmatically verify the state
99+
of a prometheus-aggregator instance.
100+
95101
## Prometheus exposition format
96102

97103
If serializing JSON is a bottleneck, you can optionally emit observations (but
@@ -131,7 +137,7 @@ Histograms are supported too. Provide buckets with the declaration.
131137

132138
```
133139
{"name": "myapp_req_dur_seconds", "type": "histogram",
134-
"help": "Duration of request in seconds.",
140+
"help": "Duration of request in seconds.",
135141
"buckets": [0.01, 0.05, 0.1, 0.5, 1, 2, 5, 10]}
136142
myapp_req_dur_seconds{} 0.0123
137143
myapp_req_dur_seconds{} 0.99

main.go

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func main() {
2929
sockAddr = fs.String("socket", "tcp://127.0.0.1:8191", "address for direct socket metric writes")
3030
promAddr = fs.String("prometheus", "tcp://127.0.0.1:8192/metrics", "address for Prometheus scrapes")
3131
declfile = fs.String("declfile", "", "file containing JSON metric declarations")
32+
declpath = fs.String("declpath", "", "sibling path to /metrics serving initial metric declarations")
3233
example = fs.Bool("example", false, "print example declfile to stdout and return")
3334
debug = fs.Bool("debug", false, "log debug information")
3435
strict = fs.Bool("strict", false, "disconnect clients when they send bad data")
@@ -77,6 +78,7 @@ func main() {
7778
}
7879
}
7980

81+
var socketLn net.Listener
8082
var forwardFunc func() error
8183
var forwardClose func() error
8284
{
@@ -118,46 +120,75 @@ func main() {
118120
level.Error(logger).Log("socket", *sockAddr, "err", err)
119121
os.Exit(1)
120122
}
123+
socketLn = ln
121124
forwardFunc = func() error { return forwardListener(ln, u, *strict, logger) }
122125
forwardClose = ln.Close
123126
}
124127
}
125128

126-
var promLn net.Listener
127-
var promPath string
129+
var metricsLn net.Listener
130+
var metricsPath string
128131
{
129132
u, err := url.Parse(*promAddr)
130133
if err != nil {
131134
level.Error(logger).Log("prometheus", *promAddr, "err", err)
132135
os.Exit(1)
133136
}
134-
promLn, err = net.Listen(u.Scheme, u.Host)
137+
metricsLn, err = net.Listen(u.Scheme, u.Host)
135138
if err != nil {
136139
level.Error(logger).Log("prometheus", *promAddr, "err", err)
137140
os.Exit(1)
138141
}
139-
promPath = u.Path
140-
if promPath == "" {
141-
promPath = "/"
142+
metricsPath = u.Path
143+
if metricsPath == "" {
144+
metricsPath = "/"
145+
}
146+
}
147+
148+
var declPath string
149+
var declHandler http.Handler
150+
{
151+
if *declpath != "" {
152+
*declpath = "/" + strings.Trim(*declpath, "/ ")
153+
scheme := metricsLn.Addr().Network()
154+
hostport := metricsLn.Addr().String()
155+
u, err := url.Parse(scheme + "://" + hostport + *declpath)
156+
if err != nil {
157+
level.Error(logger).Log("declpath", *declpath, "err", err)
158+
os.Exit(1)
159+
}
160+
declPath = u.Path
161+
declHandler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
162+
w.Header().Set("content-type", "application/json; charset=utf-8")
163+
p, _ := json.MarshalIndent(initial, "", " ")
164+
w.Write(p)
165+
})
142166
}
143167
}
144168

145169
var g run.Group
146170
{
147171
g.Add(func() error {
148-
level.Info(logger).Log("listener", "socket_writes", "addr", *sockAddr)
172+
level.Info(logger).Log("listener", "socket_writes", "network", socketLn.Addr().Network(), "address", socketLn.Addr().String())
149173
return forwardFunc()
150174
}, func(error) {
151175
forwardClose()
152176
})
153177
}
154178
{
155179
mux := http.NewServeMux()
156-
mux.Handle(promPath, u)
180+
mux.Handle(metricsPath, u)
181+
if declPath != "" {
182+
mux.Handle(declPath, declHandler)
183+
}
157184
server := http.Server{Handler: mux}
158185
g.Add(func() error {
159-
level.Info(logger).Log("listener", "prometheus_scrapes", "addr", promLn.Addr().String(), "path", promPath)
160-
return server.Serve(promLn)
186+
keyvals := []interface{}{"listener", "prometheus_scrapes", "network", metricsLn.Addr().Network(), "address", metricsLn.Addr().String(), "path", metricsPath}
187+
if declPath != "" {
188+
keyvals = append(keyvals, "declarations", declPath)
189+
}
190+
level.Info(logger).Log(keyvals...)
191+
return server.Serve(metricsLn)
161192
}, func(error) {
162193
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
163194
defer cancel()

universe.go

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ type (
3232
values map[timeseriesKey]timeseriesValue
3333
}
3434

35-
// timeseriesKey is universally unique e.g. `http_requests_total{method="GET",status_code="200"}`.
35+
// timeseriesKey is universally unique, e.g.
36+
// `http_requests_total{method="GET",status_code="200"}`.
3637
timeseriesKey string
3738

3839
// timeseriesValue is a set of observations for
@@ -192,8 +193,13 @@ type observation struct {
192193
Value *float64 `json:"value,omitempty"`
193194
}
194195

195-
func (o observation) metricName() metricName { return metricName(o.Name) }
196-
func (o observation) timeseriesKey() timeseriesKey { return makeTimeseriesKey(o.Name, o.Labels) }
196+
func (o observation) metricName() metricName {
197+
return metricName(o.Name)
198+
}
199+
200+
func (o observation) timeseriesKey() timeseriesKey {
201+
return makeTimeseriesKey(o.Name, o.Labels)
202+
}
197203

198204
//
199205
//
@@ -215,8 +221,13 @@ func newCounter(o observation) (*counter, error) {
215221
}, nil
216222
}
217223

218-
func (c *counter) metricName() metricName { return metricName(c.n) }
219-
func (c *counter) timeseriesKey() timeseriesKey { return makeTimeseriesKey(c.n, c.labels) }
224+
func (c *counter) metricName() metricName {
225+
return metricName(c.n)
226+
}
227+
228+
func (c *counter) timeseriesKey() timeseriesKey {
229+
return makeTimeseriesKey(c.n, c.labels)
230+
}
220231

221232
func (c *counter) observe(o observation) error {
222233
if o.Value == nil {
@@ -253,8 +264,13 @@ func newGauge(o observation) (*gauge, error) {
253264
}, nil
254265
}
255266

256-
func (g *gauge) metricName() metricName { return metricName(g.n) }
257-
func (g *gauge) timeseriesKey() timeseriesKey { return makeTimeseriesKey(g.n, g.labels) }
267+
func (g *gauge) metricName() metricName {
268+
return metricName(g.n)
269+
}
270+
271+
func (g *gauge) timeseriesKey() timeseriesKey {
272+
return makeTimeseriesKey(g.n, g.labels)
273+
}
258274

259275
func (g *gauge) observe(o observation) error {
260276
if o.Value == nil {
@@ -307,8 +323,13 @@ func newHistogram(o observation) (*histogram, error) {
307323
}, nil
308324
}
309325

310-
func (h *histogram) metricName() metricName { return metricName(h.n) }
311-
func (h *histogram) timeseriesKey() timeseriesKey { return makeTimeseriesKey(h.n, h.labels) }
326+
func (h *histogram) metricName() metricName {
327+
return metricName(h.n)
328+
}
329+
330+
func (h *histogram) timeseriesKey() timeseriesKey {
331+
return makeTimeseriesKey(h.n, h.labels)
332+
}
312333

313334
func (h *histogram) observe(o observation) error {
314335
if o.Value == nil {

0 commit comments

Comments
 (0)