I'm currently running into a problem closely related to 
https://github.com/prometheus/client_golang/issues/834: the inability to 
exclude metrics from collection based on partially-specified labels. I'm 
sending this as an email rather than as a github issue based on the advice 
in the new issue template; please let me know if you'd prefer I move this 
conversation to a github issue.

Suppose I have a `CounterVec` that I call `requestsCounter`, with labels 
`method` (whose values are only `GET` and `POST`) and `success` (whose 
values are only `true` and `false`). Maybe I have a set of unittests which 
implement a purposefully-broken handler, and I'd like to assert that we 
incremented the counter for unsuccessful requests the appropriate number of 
times, _regardless_ of whether those requests were GETs or POSTs.

Here's what I wrote in my first attempt to accomplish this goal:

```go
// AssertMetricEquals determines whether the value held by a prometheus 
Collector
// (e.g. Gauge, Counter, CounterVec, etc) is equal to the expected integer.
// In the case of vector collectors, it collects and sums the values from 
all
// metrics in the vector prior to comparison; this is so that users can 
easily
// make assertions about one of many field dimensions (e.g. for a 
CounterVec with
// fields "host" and "valid", being able to assert that two "valid": "true"
// incremets occurred, without caring which host did each increment). To 
make
// assertions about subsets of a vector's metrics, use the MetricVec's 
.CurryWith
// or .GetMetricWith methods. Only works for integer metrics (Counters and 
Gauges),
// does not work for Histograms.
func AssertMetricEquals(t *testing.T, c prometheus.Collector, expected int) 
{
ch := make(chan prometheus.Metric)
done := make(chan struct{})
go func() {
c.Collect(ch)
close(done)
}()
var total int
timeout := time.After(time.Second)
loop:
for {
select {
case <-timeout:
t.Fatal("timed out collecting metrics")
case <-done:
break loop
case m := <-ch:
var mpb prometheus_client_pb.Metric
_ = m.Write(&mpb)
// Exactly one of the Counter or Gauge values will be populated by the
// .Write() operation, so just add both because the other will be 0.
total += int(mpb.Counter.GetValue())
total += int(mpb.Gauge.GetValue())
}
}
AssertEquals(t, total, expected)
}

<snip>

AssertMetricEquals(t, 
requestsCounter.MustCurryWith(prometheus.Labels{"success": "false"}), 10)
```

Unfortunately this fails, because the curried `MetricVec` still sends *all* 
metrics to the `.Collect()` channel, even those that would be excluded by 
the curried labels.

The only real solution that I see here is to perform the currying ourselves 
-- rather than passing a curried `MetricVec` into the `AssertMetricEquals` 
function, pass a set of `Labels` into it and do the filtering ourselves 
based on the contents of `iom.Label`. This would be functionally the same 
as the "very hacky and weird" workaround in #834.

>From an outsider perspective, the most elegant solution here would be to 
change the behavior of `.Collect()` to not send metrics which are excluded 
by the current set of curried labels. But I understand that that may be 
sufficiently backwards incompatible as to be a non-starter. What are the 
options here?

Thanks,
Aaron

-- 
You received this message because you are subscribed to the Google Groups 
"Prometheus Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/prometheus-developers/d7ff2b02-87ca-4a5a-9c29-b34ee9c59ca4n%40googlegroups.com.

Reply via email to