Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functions that instruments http handler using promhttp #15

Merged
merged 4 commits into from
Feb 9, 2018

Conversation

tifayuki
Copy link
Contributor

In the latest prometheus go client, handlers provided before in prometheus package are deprecated. Instead, promhttp package is recommended.

This PR implements functions that wraps original methods inpromhttp.

It also fix the compilation error, when building against prometheus/client-golang master.

@tifayuki
Copy link
Contributor Author

@stevvooe
can you please review this PR, I would like to use it in docker/distribution to provide http prometheus metrics

cc @manishtomar

@tifayuki
Copy link
Contributor Author

cc @nandhini915

@stevvooe
Copy link
Contributor

cc @crosbymichael

handler.go Outdated

// InstrumentHandlerFuncWithOpts instruments http handler with in-flight gauge,
// request count, handle duration, request size, and response size
func InstrumentHandlerFuncWithOpts(opts HttpHandlerOpts, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should take the handler type, not the function type. Also, it should return a handler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stevvooe The deprecated functions uses http.HandlerFunc. I can added another wrapper that uses/returns a handler type. Do we need that ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. http.HandlerFunc is an implementation of http.Handler. I would generally only deal in http.Handler for exported types, but I can see this is a specific function. Doing it the other way around would be better, since it is odd to take a method value:

func InstrumentHandlerWithOpts(ops HTTPHandlerOpts, handler http.Handler) http.Handler {
// body of this function.
}

func InstrumentHandlerFuncWithOpts(opts HttpHandlerOpts, handlerFunc func(http.ResponseWriter, *http.Request)) http.Handler {
    return InstrumentHandlerWithOpts(opts, http.HandlerFunc(handlerFunc))
}

handler.go Outdated
inFlightGauge := prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: opts.Namespace,
Subsystem: opts.Subsystem,
Name: fmt.Sprintf("%s_in_flight_requests", opts.HandlerName),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't handler names be labels?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that using it is better to use labels. However the promhttp API only allows "code" and "method" as labels:
https://godoc.org/github.com/prometheus/client_golang/prometheus/promhttp#InstrumentHandlerCounter

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Label the counter before you pass it to that function. Is that possible?

The issue here is there is nothing to enforce naming standard on the handler name.

Copy link
Contributor Author

@tifayuki tifayuki Nov 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can give a try to see if we can label the counter. Well, not only counter, but almost all the APIs only accept "code" and "method" as labels.

If the handler name is not standard, say use "blob-upload" instead of "blob_upload" the API will panic at run time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, these are fine then. It would be a lot easier to service-wide rollups if these are labels, but you'd have to rewrite all of these.

@stevvooe
Copy link
Contributor

Looks like this is copy pasted from https://github.com/prometheus/client_golang/blob/master/prometheus/http.go#L232. Why not use the standard layout?

@stevvooe
Copy link
Contributor

Answered my own question in godoc: "- It uses Summaries rather than Histograms. Summaries are not useful if aggregation across multiple instances is required.".

handler.go Outdated
}
responseSizeHistogram := prometheus.NewHistogramVec(responseSizeHistogramOpts, []string{})

prometheus.MustRegister(inFlightGauge, requestTotal, requestDurationHistogram, requestSizeHistogram, responseSizeHistogram)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should register with the go-metrics registry.

handler.go Outdated
if len(responseSizeHistogramOpts.Buckets) == 0 {
responseSizeHistogramOpts.Buckets = defaultResponseSizeBucket
}
responseSizeHistogram := prometheus.NewHistogramVec(responseSizeHistogramOpts, []string{})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these need to define the buckets?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The buckets can be defined in HttpHandlerOpts. If not provided, it uses the default bucket: defaultResponseSizeBucket = prometheus.ExponentialBuckets(1024, 2, 22) //1K to 4G

handler.go Outdated
}

// HttpHandlerOpts describes a set of configurable options of http metrics
type HttpHandlerOpts struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please follow Go style guidelines: HTTPHandlerOpts.

timer.go Outdated
@@ -36,7 +36,7 @@ type labeledTimer struct {
}

func (lt *labeledTimer) WithValues(labels ...string) Timer {
return &timer{m: lt.m.WithLabelValues(labels...)}
return &timer{m: lt.m.WithLabelValues(labels...).(prometheus.Histogram)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is going on here? Was there a problem?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, due to the api change, it cannot compile against prom master now:
#12

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please send a separate PR. We may need to change the field type instead of adding a type assertion.

@stevvooe
Copy link
Contributor

Ok, this generally looks okay.

@cpuguy83 Did we instrument the moby api in prometheus yet? We should probably use this functions, if we can.

.gitignore Outdated
@@ -0,0 +1 @@
.idea/

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this go into ~/.gitconfig?

@cpuguy83
Copy link

I'm not crazy about the API here.
Name at least should be a func argument in all cases, this would make the split WithOpts and no-opts functions a bit more useful.

Should this panic if name is empty?
Should this also be tied to a namespace rather than making the namespace optional?

@tifayuki
Copy link
Contributor Author

I have pushed another commit with the following changes:

  1. remove the .gitignore file
  2. rename HttHandlerOpts to HTTPHandlerOpts
  3. add namespace paramenter to non-WithOpts functions
  4. panic if namespace or handlerName is not given
  5. use handler name as constant label, avoiding use them as the name of a metrics
  6. use register from go-metrics instead of MustRegister from prometheus/client-golang

@cpuguy83
Copy link

@tifayuki I really meant that it would be good to bind the HTTP instrumentation helpers to the *Namespece type and that is one less thing that needs to be passed in.

@stevvooe
Copy link
Contributor

@tifayuki @cpuguy83 Yes, these should be a function of the namespace. All metrics should descend from the namespace, per this package.

If that is not done, it makes these additions a little redundant.

@tifayuki tifayuki force-pushed the promhttp branch 3 times, most recently from c6e608f to bb4f080 Compare November 30, 2017 01:19
@tifayuki
Copy link
Contributor Author

@stevvooe @cpuguy83
I have re-implemented the http handlers using namespace. Can you take a look?

@tifayuki
Copy link
Contributor Author

tifayuki commented Dec 6, 2017

@stevvooe
Can you please review the PR again? Need it to be merged so that we can use it to provide metrics in docker/distribution
Thank you

namespace.go Outdated

func (n *Namespace) NewHttpMetricsWithOpts(opts HttpHandlerOpts) []*HttpMetric {
if _, ok := n.labels["handler"]; !ok {
panic("label \"handler\" must be provided in the namespace")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this part of the original interface?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so it looks like we need a specialized constructor that creates this for the particular handler. Looking at the example, it should not be required to construct the namespace with a specific label. That should be part of creating the handler metric.

namespace.go Outdated

func (n *Namespace) NewResponseSizeMetric(buckets []float64) *HttpMetric {
if len(buckets) == 0 {
panic("ResponseSizeBuckets must be provided")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not provided, use a default.

handler.go Outdated
InstrumentHandlerInFlight
)

type HttpMetric struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTPMetric

Signed-off-by: tifayuki <tifayuki@gmail.com>
Signed-off-by: tifayuki <tifayuki@gmail.com>
namespace.go Outdated
},
[]string{"code", "method"},
)
httpMetric := &HTTPMetric{metric, InstrumentHandlerCounter}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to specify the fields that these are getting set to.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to fix this one.

namespace.go Outdated
ConstLabels: prometheus.Labels(labels),
}
metric := prometheus.NewHistogramVec(opts, []string{"method"})
httpMetric := &HTTPMetric{metric, InstrumentHandlerDuration}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to fix this one.

namespace.go Outdated
ConstLabels: prometheus.Labels(labels),
}
metric := prometheus.NewHistogramVec(opts, []string{})
httpMetric := &HTTPMetric{metric, InstrumentHandlerRequestSize}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix this one.

Signed-off-by: tifayuki <tifayuki@gmail.com>
handler.go Outdated
}

var (
defaultDurationBuckets = []float64{0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 2., 5., 10., 20., 30., 40., 50.}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[]float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, 25, 60}

Note that I went with 60, instead of 50 at the top end.

Signed-off-by: tifayuki <tifayuki@gmail.com>
@stevvooe
Copy link
Contributor

stevvooe commented Feb 9, 2018

LGTM

@stevvooe stevvooe merged commit 399ea8c into docker:master Feb 9, 2018
thaJeztah added a commit to thaJeztah/containerd that referenced this pull request Jan 13, 2020
full diff: docker/go-metrics@4ea375f...v0.0.1

- docker/go-metrics#15 Add functions that instruments http handler using promhttp
- docker/go-metrics#20 Rename LICENSE.code → LICENSE
- docker/go-metrics#22 Support Go Modules

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
thaJeztah added a commit to thaJeztah/docker that referenced this pull request Jan 16, 2020
bump docker/go-metrics v0.0.1:

full diff: docker/go-metrics@d466d4f...v0.0.1

- docker/go-metrics#16 fix the compilation error against prometheus/client-golang master
- fixes docker/go-metrics#12 No longer builds against Prom master
- docker/go-metrics#18 metrics: address compile error correctly
- fixes docker/go-metrics#12 No longer builds against Prom master
- docker/go-metrics#15 Add functions that instruments http handler using promhttp
- docker/go-metrics#20 Rename LICENSE.code → LICENSE
- docker/go-metrics#22 Support Go Modules

bump prometheus/client_golang v0.9.4:

full diff: prometheus/client_golang@c5b7fcc...v0.9.4

version v0.9.0 is the minimum required version to work with go-metrics v0.0.1,
as it depends on `prometheus.Observer`:

    vendor/github.com/docker/go-metrics/timer.go:39:4: undefined: prometheus.Observer

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
docker-jenkins pushed a commit to docker/docker-ce that referenced this pull request Jan 17, 2020
bump docker/go-metrics v0.0.1:

full diff: docker/go-metrics@d466d4f...v0.0.1

- docker/go-metrics#16 fix the compilation error against prometheus/client-golang master
- fixes docker/go-metrics#12 No longer builds against Prom master
- docker/go-metrics#18 metrics: address compile error correctly
- fixes docker/go-metrics#12 No longer builds against Prom master
- docker/go-metrics#15 Add functions that instruments http handler using promhttp
- docker/go-metrics#20 Rename LICENSE.code → LICENSE
- docker/go-metrics#22 Support Go Modules

bump prometheus/client_golang v0.9.4:

full diff: prometheus/client_golang@c5b7fcc...v0.9.4

version v0.9.0 is the minimum required version to work with go-metrics v0.0.1,
as it depends on `prometheus.Observer`:

    vendor/github.com/docker/go-metrics/timer.go:39:4: undefined: prometheus.Observer

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Upstream-commit: b2db7c8bc967b52609877f5d856c338ea51e4c46
Component: engine
tussennet pushed a commit to tussennet/containerd that referenced this pull request Sep 11, 2020
full diff: docker/go-metrics@4ea375f...v0.0.1

- docker/go-metrics#15 Add functions that instruments http handler using promhttp
- docker/go-metrics#20 Rename LICENSE.code → LICENSE
- docker/go-metrics#22 Support Go Modules

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants