Skip to content

Commit 2eaffbd

Browse files
authored
Merge pull request #1253 from prometheus/fixpro
Fixed promhttp Instrument* handlers.
2 parents d7896d4 + b8fdd23 commit 2eaffbd

File tree

3 files changed

+33
-13
lines changed

3 files changed

+33
-13
lines changed

prometheus/promhttp/instrument_client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
7878
for label, resolve := range rtOpts.extraLabelsFromCtx {
7979
l[label] = resolve(resp.Request.Context())
8080
}
81-
counter.With(l).(prometheus.ExemplarAdder).AddWithExemplar(1, rtOpts.getExemplarFn(r.Context()))
81+
addWithExemplar(counter.With(l), 1, rtOpts.getExemplarFn(r.Context()))
8282
}
8383
return resp, err
8484
}
@@ -122,7 +122,7 @@ func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundT
122122
for label, resolve := range rtOpts.extraLabelsFromCtx {
123123
l[label] = resolve(resp.Request.Context())
124124
}
125-
obs.With(l).(prometheus.ExemplarObserver).ObserveWithExemplar(time.Since(start).Seconds(), rtOpts.getExemplarFn(r.Context()))
125+
observeWithExemplar(obs.With(l), time.Since(start).Seconds(), rtOpts.getExemplarFn(r.Context()))
126126
}
127127
return resp, err
128128
}

prometheus/promhttp/instrument_server.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,26 @@ import (
2828
// magicString is used for the hacky label test in checkLabels. Remove once fixed.
2929
const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa"
3030

31+
// observeWithExemplar is a wrapper for [prometheus.ExemplarAdder.ExemplarObserver],
32+
// which falls back to [prometheus.Observer.Observe] if no labels are provided.
33+
func observeWithExemplar(obs prometheus.Observer, val float64, labels map[string]string) {
34+
if labels == nil {
35+
obs.Observe(val)
36+
return
37+
}
38+
obs.(prometheus.ExemplarObserver).ObserveWithExemplar(val, labels)
39+
}
40+
41+
// addWithExemplar is a wrapper for [prometheus.ExemplarAdder.AddWithExemplar],
42+
// which falls back to [prometheus.Counter.Add] if no labels are provided.
43+
func addWithExemplar(obs prometheus.Counter, val float64, labels map[string]string) {
44+
if labels == nil {
45+
obs.Add(val)
46+
return
47+
}
48+
obs.(prometheus.ExemplarAdder).AddWithExemplar(val, labels)
49+
}
50+
3151
// InstrumentHandlerInFlight is a middleware that wraps the provided
3252
// http.Handler. It sets the provided prometheus.Gauge to the number of
3353
// requests currently handled by the wrapped http.Handler.
@@ -80,7 +100,7 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, op
80100
for label, resolve := range hOpts.extraLabelsFromCtx {
81101
l[label] = resolve(r.Context())
82102
}
83-
obs.With(l).(prometheus.ExemplarObserver).ObserveWithExemplar(time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
103+
observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
84104
}
85105
}
86106

@@ -91,7 +111,7 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, op
91111
for label, resolve := range hOpts.extraLabelsFromCtx {
92112
l[label] = resolve(r.Context())
93113
}
94-
obs.With(l).(prometheus.ExemplarObserver).ObserveWithExemplar(time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
114+
observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
95115
}
96116
}
97117

@@ -130,7 +150,7 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler,
130150
for label, resolve := range hOpts.extraLabelsFromCtx {
131151
l[label] = resolve(r.Context())
132152
}
133-
counter.With(l).(prometheus.ExemplarAdder).AddWithExemplar(1, hOpts.getExemplarFn(r.Context()))
153+
addWithExemplar(counter.With(l), 1, hOpts.getExemplarFn(r.Context()))
134154
}
135155
}
136156

@@ -141,7 +161,7 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler,
141161
for label, resolve := range hOpts.extraLabelsFromCtx {
142162
l[label] = resolve(r.Context())
143163
}
144-
counter.With(l).(prometheus.ExemplarAdder).AddWithExemplar(1, hOpts.getExemplarFn(r.Context()))
164+
addWithExemplar(counter.With(l), 1, hOpts.getExemplarFn(r.Context()))
145165
}
146166
}
147167

@@ -183,7 +203,7 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
183203
for label, resolve := range hOpts.extraLabelsFromCtx {
184204
l[label] = resolve(r.Context())
185205
}
186-
obs.With(l).(prometheus.ExemplarObserver).ObserveWithExemplar(time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
206+
observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
187207
})
188208
next.ServeHTTP(d, r)
189209
}
@@ -227,7 +247,7 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler,
227247
for label, resolve := range hOpts.extraLabelsFromCtx {
228248
l[label] = resolve(r.Context())
229249
}
230-
obs.With(l).(prometheus.ExemplarObserver).ObserveWithExemplar(float64(size), hOpts.getExemplarFn(r.Context()))
250+
observeWithExemplar(obs.With(l), float64(size), hOpts.getExemplarFn(r.Context()))
231251
}
232252
}
233253

@@ -239,7 +259,7 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler,
239259
for label, resolve := range hOpts.extraLabelsFromCtx {
240260
l[label] = resolve(r.Context())
241261
}
242-
obs.With(l).(prometheus.ExemplarObserver).ObserveWithExemplar(float64(size), hOpts.getExemplarFn(r.Context()))
262+
observeWithExemplar(obs.With(l), float64(size), hOpts.getExemplarFn(r.Context()))
243263
}
244264
}
245265

@@ -279,7 +299,7 @@ func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler
279299
for label, resolve := range hOpts.extraLabelsFromCtx {
280300
l[label] = resolve(r.Context())
281301
}
282-
obs.With(l).(prometheus.ExemplarObserver).ObserveWithExemplar(float64(d.Written()), hOpts.getExemplarFn(r.Context()))
302+
observeWithExemplar(obs.With(l), float64(d.Written()), hOpts.getExemplarFn(r.Context()))
283303
})
284304
}
285305

prometheus/promhttp/option.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ func WithExtraMethods(methods ...string) Option {
6666
})
6767
}
6868

69-
// WithExemplarFromContext adds allows to put a hook to all counter and histogram metrics.
70-
// If the hook function returns non-nil labels, exemplars will be added for that request, otherwise metric
71-
// will get instrumented without exemplar.
69+
// WithExemplarFromContext allows to inject function that will get exemplar from context that will be put to counter and histogram metrics.
70+
// If the function returns nil labels or the metric does not support exemplars, no exemplar will be added (noop), but
71+
// metric will continue to observe/increment.
7272
func WithExemplarFromContext(getExemplarFn func(requestCtx context.Context) prometheus.Labels) Option {
7373
return optionApplyFunc(func(o *options) {
7474
o.getExemplarFn = getExemplarFn

0 commit comments

Comments
 (0)