Conversation
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
|
Hey @vesari , just passing by to ask if there is anything we could do to unblock you 👋 |
@ArthurSens hello! I think I'm just using a Go version which is too new, I plan on fixing that later today. Thanks a lot for checking on me, much appreciated! :) |
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
bwplotka
left a comment
There was a problem hiding this comment.
This is amazing. Solid work, thanks for finding way to not break compatibility.
Added a few suggestions and ideas, hope those help! Overall this goes in a good direction 👍🏽
prometheus/promhttp/http.go
Outdated
| enc = expfmt.NewEncoder(w, contentType) | ||
| encOpts = append(encOpts, expfmt.WithCreatedLines()) | ||
| } | ||
| if opts.EnableOpenMetricsUnit { |
There was a problem hiding this comment.
Do we need this manual flag?
Why can't we simply add UNIT line if someone enabled OM? Shouldn't this be safe?
There was a problem hiding this comment.
We added flag for EnableOpenMetricsTextCreatedSamples because we believe CT line is potentially breaking to the ecosystem (lot's of problems). But with UNIT metadata, I'd expect OM compatible parsers to either ignore it or parse. Even TEXT formats should work, because it's just a # .. comment.
The only potential risk is the slight increase of payload size, but this is actually limited by the user who need to manually add Unit: <....> fields to their metric definitions, no?
There was a problem hiding this comment.
I see your point. However, as things stand, the flag is necessary because prometheus/common's expfmt encoder requires explicit opt-in via WithUnit() to output units. Without it, units are silently ignored even if set in the MetricFamily. I think this was to avoid potential changes to metric names to happen automatically. In fact, because of this logic
if we:
- Opt in with
WithUnit() - Have a metric
foo_totalwith Unit:"seconds" - The metric name doesn't already end with
_seconds
The metric name becomes foo_seconds_total. I believe the consensus back then was this should be the result of a very explicit decision by the user.
Of course, if - for example - we decide we’re allowed not to enforce the unit suffix anymore or that we deem acceptable to silently add unit suffixes, then the flag becomes superfluous, and can be removed as soon as the related code in common gets modified accordingly. I’ll be happy to do that myself, if consensus is ever reached in that sense.
There was a problem hiding this comment.
I think we agree it's a bit toxic to change name depending on the unit, even though it's what OM 1.0 kind of requires (but there tons of other way to handle this e.g. return error on registration e.g. using pedantic registry).
To proceed I think we need to simplify this for users and make sure there's a mode in expfmt that do not change metric names, perhaps even to _total. Then we also need to reduce risk this mode will be not alter.
The problem with adding a feature flag "for now", it's because it's for forever (v1) and it's also adding a flag with something that we don't recommend and can have consequences. So let's try to alter common then?
There was a problem hiding this comment.
Sure thing. Opened the corresponding PR on common today.
prometheus/promhttp/http.go
Outdated
| encOpts = append(encOpts, expfmt.WithCreatedLines()) | ||
| } | ||
| if opts.EnableOpenMetricsUnit { | ||
| encOpts = append(encOpts, expfmt.WithUnit()) |
There was a problem hiding this comment.
I wonder, does this print UNIT line if UNIT is unknown (empty string?)
Can we ensure this does NOT add UNIT if it's unknown? Just to safe space and limit the risks mentioned in https://github.com/prometheus/client_golang/pull/1392/files#r2580622660
prometheus/promhttp/http.go
Outdated
| EnableOpenMetricsTextCreatedSamples bool | ||
| // EnableOpenMetricsUnit enables unit metadata in the OpenMetrics output format. | ||
| // This is only applicable when OpenMetrics format is negotiated. | ||
| EnableOpenMetricsUnit bool |
There was a problem hiding this comment.
again, I wonder if we could skip this (reduce complexity and effort for everyone, users already need to manually add Unit field).
| } | ||
|
|
||
| wantMsg := `error gathering metrics: error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", constLabels: {}, variableLabels: {}}: collect error | ||
| wantMsg := `error gathering metrics: error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", unit: "", constLabels: {}, variableLabels: {}}: collect error |
There was a problem hiding this comment.
Can we ensure everywhere we don't print empty string? (and just skip it?). It does not give a lot of info in an empty string form
prometheus/desc.go
Outdated
| // For constLabels, the label values are constant. Therefore, they are fully | ||
| // specified in the Desc. See the Collector example for a usage pattern. | ||
| func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels) *Desc { | ||
| func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels, unit ...string) *Desc { |
There was a problem hiding this comment.
Here, I wonder if we don't want to break compatibility. 🤔 It's V2 and I wished we marked it as experimental somewhere visibility (it was meant to experiment on a new API). However, I bet downstream ecosystem already started using it.
I'd suggest, (see A, B options in https://github.com/prometheus/client_golang/pull/1392/files#r2580668173)
- For
NewDescwe do (B) - For V2 we do (A) ?
prometheus/desc.go
Outdated
| // label names. | ||
| xxh.Reset() | ||
| xxh.WriteString(help) | ||
| xxh.WriteString(optionalUnitValue(unit...)) |
There was a problem hiding this comment.
let's eval unit as soon as we have it from descV2Opts or something
| } | ||
| return fmt.Sprintf( | ||
| "Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: {%s}}", | ||
| "Desc{fqName: %q, help: %q, unit: %q, constLabels: {%s}, variableLabels: {%s}}", |
| sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name}) | ||
| sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1] | ||
|
|
||
| // Extract unit from the runtime/metrics name (e.g., "/gc/heap/allocs:bytes" -> "bytes") |
Co-authored-by: Bartlomiej Plotka <[email protected]> Signed-off-by: Arianna Vespri <[email protected]>
Co-authored-by: Bartlomiej Plotka <[email protected]> Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Thank you very much, I'm working on addressing your requests for changes and your observations. I'll get back to you once I'm done :) |
…t is given Signed-off-by: Arianna Vespri <[email protected]>
…c argument in V2 NewDesc Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
|
This is now ready for review :) |
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
| err error | ||
| } | ||
|
|
||
| type DescOpt func(*Desc) |
There was a problem hiding this comment.
Probably needs commentary (public structure)
prometheus/desc.go
Outdated
| for _, opt := range opts { | ||
| opt(d) | ||
| } | ||
| unit := d.unit |
prometheus/desc.go
Outdated
| } | ||
| unitStr := "" | ||
| if d.unit != "" { | ||
| unitStr = fmt.Sprintf(", unit: %q", d.unit) |
There was a problem hiding this comment.
I'd add this inline and show unit is empty? We expanded the data structure so we can expand the error too
prometheus/example_metricvec_test.go
Outdated
|
|
||
| func NewInfoVec(name, help string, labelNames []string) *InfoVec { | ||
| desc := prometheus.NewDesc(name, help, labelNames, nil) | ||
| func NewInfoVec(name, help string, labelNames []string, unit ...string) *InfoVec { |
There was a problem hiding this comment.
Info likely does not have unit?
prometheus/go_collector_latest.go
Outdated
| sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1] | ||
|
|
||
| // Extract unit from the runtime/metrics name (e.g., "/gc/heap/allocs:bytes" -> "bytes") | ||
| unit := d.Name[strings.IndexRune(d.Name, ':')+1:] |
There was a problem hiding this comment.
As found in https://gist.github.com/bwplotka/a38c33a74fad88a46c4623e924fa58c8#file-prometheusclient_golang1392-md, I think indeed we should handle the case of no unit here gracefully (-1 index response):
> Unsafe Substring Slice during Runtime Metric Unit Extraction
File with exact line number: prometheus/go_collector_latest.go:L213
Link to a file line on GitHub PR: https://github.com/prometheus/client_golang/pull/1392/files#diff-8360f0c0ae2f0d98fb9ecdf37119d6d333dc17ec23f0547055c1ddfdf4ed0759R213
Problem: The unit is extracted using d.Name[strings.IndexRune(d.Name, ':')+1:]. If a runtime metric is introduced without a :, strings.IndexRune evaluates to -1 resulting in -1+1 = 0. The unit silently turns into the entire metric name, bypassing obvious fault detection. (Note: this extraction assumption existed before the PR for histograms, but was generalized here).
Suggestion: Consider checking if strings.ContainsRune(d.Name, ':') before slicing to future-proof the collector against misconfigured runtime metrics.
Co-authored-by: Bartlomiej Plotka <[email protected]> Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
Signed-off-by: Arianna Vespri <[email protected]>
This PR adds support for unit for Open Metrics. It is ready for review, but not ready to merge (see my long comment below). Fixes #684.