Skip to content
This repository has been archived by the owner on Oct 3, 2023. It is now read-only.

Commit

Permalink
Skip ConstLabels and namespace prefixes for "up" & internal metrics
Browse files Browse the repository at this point in the history
Internal metrics consumed by Prometheus such as "up" indicate
a status of the target, as either "up" with 1.0 or "down" with 0.0.
This change ensures that no ConstLabels, nor namespace prefixes will
be added to such metrics. This ensures that when one exports with
the special name "up", that it passes through up to the Prometheus
exporter, so:

    # HELP up up
    # TYPE up counter
    up{instance="localhost:9999"} 1

instead of:

    # HELP tests_up tests/up
    # TYPE tests_up counter
    tests_up{instance="localhost:9999",service="spanner"} 1

A further assertion can be added to ensure that "up" is a gauge,
but I am not sure that it might be necessary, just in case some
user wants to expose it as a counter.

Updates open-telemetry/wg-prometheus#8
  • Loading branch information
odeke-em committed Apr 13, 2021
1 parent 6151c48 commit d000bdd
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
17 changes: 17 additions & 0 deletions prometheus.go
Expand Up @@ -149,7 +149,24 @@ func newCollector(opts Options, registrar prometheus.Registerer) *collector {
reader: metricexport.NewReader()}
}

func isInternalMetric(metricName string) bool {
return metricName == "up"
}

func (c *collector) toDesc(metric *metricdata.Metric) *prometheus.Desc {
if isInternalMetric(metric.Descriptor.Name) {
// Internal metrics should not have any namespace
// prefixes, nor any const labels attached to them,
// but instead just set as they are, to allow the exporter
// to operate as if it were a passthrough.
// See https://github.com/open-telemetry/wg-prometheus/issues/8
return prometheus.NewDesc(
metric.Descriptor.Name,
metric.Descriptor.Description,
toPromLabels(metric.Descriptor.LabelKeys),
nil)
}

return prometheus.NewDesc(
metricName(c.opts.Namespace, metric),
metric.Descriptor.Description,
Expand Down
93 changes: 93 additions & 0 deletions prometheus_test.go
Expand Up @@ -527,3 +527,96 @@ prom_counter 1
}

}

func TestInternalMetricsWithoutConstLabels(t *testing.T) {
constLabels := prometheus.Labels{
"service": "spanner",
}
instanceLabel, _ := tag.NewKey("instance")

exporter, err := NewExporter(Options{
ConstLabels: constLabels,
})
if err != nil {
t.Fatalf("failed to create prometheus exporter: %v", err)
}

names := []string{"tests/foo", "tests/bar", "tests/baz", "tests/up", "up"}

var measures mSlice
for _, name := range names {
measures.createAndAppend(name, name, "")
}

var vc vCreator
for _, m := range measures {
vc.createAndAppend(m.Name(), m.Description(), []tag.Key{instanceLabel}, m, view.Count())
}

if err := view.Register(vc...); err != nil {
t.Fatalf("failed to create views: %v", err)
}
defer view.Unregister(vc...)

ctx, _ := tag.New(context.Background(), tag.Upsert(instanceLabel, "localhost:9999"))
for _, m := range measures {
stats.Record(ctx, m.M(1))
}

srv := httptest.NewServer(exporter)
defer srv.Close()

var i int
var output string
for {
time.Sleep(10 * time.Millisecond)
if i == 10 {
t.Fatal("no output at /metrics (100ms wait)")
}
i++

resp, err := http.Get(srv.URL)
if err != nil {
t.Fatalf("failed to get /metrics: %v", err)
}

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatalf("failed to read body: %v", err)
}
resp.Body.Close()

output = string(body)
if output != "" {
break
}
}

if strings.Contains(output, "collected before with the same name and label values") {
t.Fatal("metric name and labels being duplicated but must be unique")
}

if strings.Contains(output, "error(s) occurred") {
t.Fatal("error reported by prometheus registry")
}

want := `# HELP tests_bar tests/bar
# TYPE tests_bar counter
tests_bar{instance="localhost:9999",service="spanner"} 1
# HELP tests_baz tests/baz
# TYPE tests_baz counter
tests_baz{instance="localhost:9999",service="spanner"} 1
# HELP tests_foo tests/foo
# TYPE tests_foo counter
tests_foo{instance="localhost:9999",service="spanner"} 1
# HELP tests_up tests/up
# TYPE tests_up counter
tests_up{instance="localhost:9999",service="spanner"} 1
# HELP up up
# TYPE up counter
up{instance="localhost:9999"} 1
`
if output != want {
t.Fatalf("output differed from expected\nGot:\n%q\nWant:\n%q", output, want)
}
}

0 comments on commit d000bdd

Please sign in to comment.