@@ -185,7 +185,7 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
185185 }
186186
187187 var contentType expfmt.Format
188- if opts .EnableOpenMetrics {
188+ if opts .EnableOpenMetrics || opts . OpenMetricsOptions . Enable {
189189 contentType = expfmt .NegotiateIncludingOpenMetrics (req .Header )
190190 } else {
191191 contentType = expfmt .Negotiate (req .Header )
@@ -207,7 +207,13 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
207207 if encodingHeader != string (Identity ) {
208208 rsp .Header ().Set (contentEncodingHeader , encodingHeader )
209209 }
210- enc := expfmt .NewEncoder (w , contentType )
210+
211+ var enc expfmt.Encoder
212+ if opts .OpenMetricsOptions .EnableCreatedTimestamps {
213+ enc = expfmt .NewEncoder (w , contentType , expfmt .WithCreatedLines ())
214+ } else {
215+ enc = expfmt .NewEncoder (w , contentType )
216+ }
211217
212218 // handleError handles the error according to opts.ErrorHandling
213219 // and returns true if we have to abort after the handling.
@@ -398,16 +404,11 @@ type HandlerOpts struct {
398404 // away). Until the implementation is improved, it is recommended to
399405 // implement a separate timeout in potentially slow Collectors.
400406 Timeout time.Duration
401- // If true, the experimental OpenMetrics encoding is added to the
402- // possible options during content negotiation. Note that Prometheus
403- // 2.5.0+ will negotiate OpenMetrics as first priority. OpenMetrics is
404- // the only way to transmit exemplars. However, the move to OpenMetrics
405- // is not completely transparent. Most notably, the values of "quantile"
406- // labels of Summaries and "le" labels of Histograms are formatted with
407- // a trailing ".0" if they would otherwise look like integer numbers
408- // (which changes the identity of the resulting series on the Prometheus
409- // server).
407+ // Deprecated: Use OpenMetricsOptions.Enable instead.
410408 EnableOpenMetrics bool
409+ // OpenMetricsOptions holds settings for the experimental OpenMetrics encoding.
410+ // It can be used to enable OpenMetrics encoding and for setting extra options.
411+ OpenMetricsOptions OpenMetricsOptions
411412 // ProcessStartTime allows setting process start timevalue that will be exposed
412413 // with "Process-Start-Time-Unix" response header along with the metrics
413414 // payload. This allow callers to have efficient transformations to cumulative
@@ -418,6 +419,43 @@ type HandlerOpts struct {
418419 ProcessStartTime time.Time
419420}
420421
422+ type OpenMetricsOptions struct {
423+ // Enable specifies if the experimental OpenMetrics encoding is added to the
424+ // possible options during content negotiation.
425+ //
426+ // Note that Prometheus 2.5.0+ might negotiate OpenMetrics Text format
427+ // as first priority unless user uses custom scrape protocol prioritization or
428+ // histograms feature is enabled (then Prometheus proto format is prioritized,
429+ // which client_golang supports).
430+ //
431+ // Keep in mind that the move to OpenMetrics is not completely transparent. Most notably,
432+ // the values of "quantile" labels of Summaries and "le" labels of Histograms are
433+ // formatted with a trailing ".0" if they would otherwise look like integer numbers
434+ // (which changes the identity of the resulting series on the Prometheus
435+ // server).
436+ //
437+ // See other options in OpenMetricsOptions to learn how to enable some special
438+ // features e.g. potentially dangerous created timestamp series.
439+ Enable bool
440+ // EnableCreatedTimestamps specifies if this handler should add, extra, synthetic
441+ // Created Timestamps for counters, histograms and summaries, which for the current
442+ // version of OpenMetrics are defined as extra series with the same name and "_created"
443+ // suffix. See also the OpenMetrics specification for more details
444+ // https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#counter-1
445+ //
446+ // Created timestamps are used to improve the accuracy of reset detection,
447+ // but the way it's designed in OpenMetrics 1.0 it also dramatically increases cardinality
448+ // if the scraper does not handle those metrics correctly (converting to created timestamp
449+ // instead of leaving those series as-is). New OpenMetrics versions might improve
450+ // this situation.
451+ //
452+ // Prometheus introduced the feature flag 'created-timestamp-zero-ingestion'
453+ // in version 2.50.0, but only for the Prometheus protobuf format. Starting in
454+ // future Prometheus version, the feature flag will be extended to the OpenMetrics
455+ // text format, thus safe to be enabled to improve accuracy of counters in Prometheus.
456+ EnableCreatedTimestamps bool
457+ }
458+
421459// httpError removes any content-encoding header and then calls http.Error with
422460// the provided error and http.StatusInternalServerError. Error contents is
423461// supposed to be uncompressed plain text. Same as with a plain http.Error, this
0 commit comments