From 284ca0ff585b7576b4507c5c5618ea8f0eb80ef7 Mon Sep 17 00:00:00 2001 From: Arthur Silva Sens Date: Mon, 14 Oct 2024 11:31:13 -0300 Subject: [PATCH] Optinally print OM created lines (#1408) Signed-off-by: Arthur Silva Sens Co-authored-by: Arthur Silva Sens --- examples/createdtimestamps/main.go | 60 ++++++++++++++++++++++++++++++ prometheus/promhttp/http.go | 23 +++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 examples/createdtimestamps/main.go diff --git a/examples/createdtimestamps/main.go b/examples/createdtimestamps/main.go new file mode 100644 index 0000000..d616bd0 --- /dev/null +++ b/examples/createdtimestamps/main.go @@ -0,0 +1,60 @@ +// Copyright 2022 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// A simple example of how to exposed created timestamps in OpenMetrics format. + +package main + +import ( + "log" + "net/http" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +func main() { + requestDurations := prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "http_request_duration_seconds", + Help: "A histogram of the HTTP request durations in seconds.", + Buckets: prometheus.ExponentialBuckets(0.1, 1.5, 5), + }) + + // Create non-global registry. + registry := prometheus.NewRegistry() + registry.MustRegister( + requestDurations, + ) + + go func() { + for { + // Record fictional latency. + now := time.Now() + requestDurations.Observe(time.Since(now).Seconds()) + time.Sleep(600 * time.Millisecond) + } + }() + + // Expose /metrics HTTP endpoint using the created custom registry. + http.Handle( + "/metrics", promhttp.HandlerFor( + registry, + promhttp.HandlerOpts{ + EnableOpenMetrics: true, + EnableOpenMetricsTextCreatedSamples: true, + }), + ) + // To test: curl -H 'Accept: application/openmetrics-text' localhost:8080/metrics + log.Fatalln(http.ListenAndServe(":8080", nil)) +} diff --git a/prometheus/promhttp/http.go b/prometheus/promhttp/http.go index e598e66..02a36b6 100644 --- a/prometheus/promhttp/http.go +++ b/prometheus/promhttp/http.go @@ -207,7 +207,13 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO if encodingHeader != string(Identity) { rsp.Header().Set(contentEncodingHeader, encodingHeader) } - enc := expfmt.NewEncoder(w, contentType) + + var enc expfmt.Encoder + if opts.EnableOpenMetricsTextCreatedSamples { + enc = expfmt.NewEncoder(w, contentType, expfmt.WithCreatedLines()) + } else { + enc = expfmt.NewEncoder(w, contentType) + } // handleError handles the error according to opts.ErrorHandling // and returns true if we have to abort after the handling. @@ -408,6 +414,21 @@ type HandlerOpts struct { // (which changes the identity of the resulting series on the Prometheus // server). EnableOpenMetrics bool + // EnableOpenMetricsTextCreatedSamples specifies if this handler should add, extra, synthetic + // Created Timestamps for counters, histograms and summaries, which for the current + // version of OpenMetrics are defined as extra series with the same name and "_created" + // suffix. See also the OpenMetrics specification for more details + // https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#counter-1 + // + // Created timestamps are used to improve the accuracy of reset detection, + // but the way it's designed in OpenMetrics 1.0 it also dramatically increases cardinality + // if the scraper does not handle those metrics correctly (converting to created timestamp + // instead of leaving those series as-is). New OpenMetrics versions might improve + // this situation. + // + // Prometheus introduced the feature flag 'created-timestamp-zero-ingestion' + // in version 2.50.0 to handle this situation. + EnableOpenMetricsTextCreatedSamples bool // ProcessStartTime allows setting process start timevalue that will be exposed // with "Process-Start-Time-Unix" response header along with the metrics // payload. This allow callers to have efficient transformations to cumulative