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

Skip ConstLabels and namespace prefixes for "up" & internal metrics #24

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions prometheus.go
Expand Up @@ -148,7 +148,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)
}

var labels prometheus.Labels
switch {
case metric.Resource == nil:
Expand Down
93 changes: 93 additions & 0 deletions prometheus_test.go
Expand Up @@ -609,3 +609,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 bar
# TYPE tests_bar counter
tests_bar{instance="localhost:9999",service="spanner"} 1
# HELP tests_baz baz
# TYPE tests_baz counter
tests_baz{instance="localhost:9999",service="spanner"} 1
# HELP tests_foo 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)
}
}