diff --git a/.chloggen/prometheusreceiver_add_otel_scope_schema_url_support.yaml b/.chloggen/prometheusreceiver_add_otel_scope_schema_url_support.yaml new file mode 100644 index 0000000000000..bfab0d50372ac --- /dev/null +++ b/.chloggen/prometheusreceiver_add_otel_scope_schema_url_support.yaml @@ -0,0 +1,22 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: receiver/prometheus + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add support for otel_scope_schema_url label mapping to OpenTelemetry ScopeMetrics schema URL field + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [41488] + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] diff --git a/pkg/translator/prometheus/constants.go b/pkg/translator/prometheus/constants.go index c6358681c23d4..82a17dc7eae8a 100644 --- a/pkg/translator/prometheus/constants.go +++ b/pkg/translator/prometheus/constants.go @@ -28,6 +28,10 @@ const ( // version of the OpenTelemetry scope which produced the metric: // https://github.com/open-telemetry/opentelemetry-specification/blob/e6eccba97ebaffbbfad6d4358408a2cead0ec2df/specification/compatibility/prometheus_and_openmetrics.md#instrumentation-scope ScopeVersionLabelKey = "otel_scope_version" + // ScopeSchemaURLLabelKey is the name of the label key used to identify the + // schema URL of the OpenTelemetry scope which produced the metric: + // https://github.com/open-telemetry/opentelemetry-specification/blob/e6eccba97ebaffbbfad6d4358408a2cead0ec2df/specification/compatibility/prometheus_and_openmetrics.md#instrumentation-scope + ScopeSchemaURLLabelKey = "otel_scope_schema_url" // TargetInfoMetricName is the name of the metric used to preserve resource // attributes in Prometheus format: // https://github.com/open-telemetry/opentelemetry-specification/blob/e6eccba97ebaffbbfad6d4358408a2cead0ec2df/specification/compatibility/prometheus_and_openmetrics.md#resource-attributes-1 diff --git a/receiver/prometheusreceiver/internal/transaction.go b/receiver/prometheusreceiver/internal/transaction.go index a1d1629b6f1d0..768e448dd17d2 100644 --- a/receiver/prometheusreceiver/internal/transaction.go +++ b/receiver/prometheusreceiver/internal/transaction.go @@ -74,8 +74,9 @@ type transaction struct { var emptyScopeID scopeID type scopeID struct { - name string - version string + name string + version string + schemaURL string } func newTransaction( @@ -431,6 +432,9 @@ func (t *transaction) getMetrics() (pmetric.Metrics, error) { // Otherwise, use the scope that was provided with the metrics. ils.Scope().SetName(scope.name) ils.Scope().SetVersion(scope.version) + if scope.schemaURL != "" { + ils.SetSchemaUrl(scope.schemaURL) + } // If we got an otel_scope_info metric for that scope, get scope // attributes from it. if scopeAttributes, ok := t.scopeAttributes[rKey]; ok { @@ -472,6 +476,9 @@ func getScopeID(ls labels.Labels) scopeID { if lbl.Name == prometheus.ScopeVersionLabelKey { scope.version = lbl.Value } + if lbl.Name == prometheus.ScopeSchemaURLLabelKey { + scope.schemaURL = lbl.Value + } }) return scope } @@ -597,6 +604,10 @@ func (t *transaction) addScopeInfo(key resourceKey, ls labels.Labels) { scope.version = lbl.Value return } + if lbl.Name == prometheus.ScopeSchemaURLLabelKey { + scope.schemaURL = lbl.Value + return + } attrs.PutStr(lbl.Name, lbl.Value) }) if _, ok := t.scopeAttributes[key]; !ok { diff --git a/receiver/prometheusreceiver/internal/util.go b/receiver/prometheusreceiver/internal/util.go index d8787cb9bd191..84308bb9db79b 100644 --- a/receiver/prometheusreceiver/internal/util.go +++ b/receiver/prometheusreceiver/internal/util.go @@ -43,7 +43,7 @@ var ( notUsefulLabelsOther = sortString([]string{ model.MetricNameLabel, model.InstanceLabel, model.SchemeLabel, - model.MetricsPathLabel, model.JobLabel, prometheus.ScopeNameLabelKey, prometheus.ScopeVersionLabelKey, + model.MetricsPathLabel, model.JobLabel, prometheus.ScopeNameLabelKey, prometheus.ScopeVersionLabelKey, prometheus.ScopeSchemaURLLabelKey, }) notUsefulLabelsHistogram = sortString(append(notUsefulLabelsOther, model.BucketLabel)) notUsefulLabelsSummary = sortString(append(notUsefulLabelsOther, model.QuantileLabel)) diff --git a/receiver/prometheusreceiver/metrics_receiver_labels_test.go b/receiver/prometheusreceiver/metrics_receiver_labels_test.go index c85392c1776c3..a04b9b8e93e90 100644 --- a/receiver/prometheusreceiver/metrics_receiver_labels_test.go +++ b/receiver/prometheusreceiver/metrics_receiver_labels_test.go @@ -825,7 +825,7 @@ func verifyTargetInfoResourceAttributes(t *testing.T, td *testData, rms []pmetri const targetInstrumentationScopes = ` # HELP jvm_memory_bytes_used Used bytes of a given JVM memory area. # TYPE jvm_memory_bytes_used gauge -jvm_memory_bytes_used{area="heap", otel_scope_name="fake.scope.name", otel_scope_version="v0.1.0"} 100 +jvm_memory_bytes_used{area="heap", otel_scope_name="fake.scope.name", otel_scope_version="v0.1.0", otel_scope_schema_url="https://opentelemetry.io/schemas/1.21.0"} 100 jvm_memory_bytes_used{area="heap", otel_scope_name="scope.with.attributes", otel_scope_version="v1.5.0"} 100 jvm_memory_bytes_used{area="heap"} 100 # TYPE otel_scope_info gauge @@ -858,17 +858,20 @@ func verifyMultipleScopes(t *testing.T, td *testData, rms []pmetric.ResourceMetr require.Equal(t, "fake.scope.name", sms.At(0).Scope().Name()) require.Equal(t, "v0.1.0", sms.At(0).Scope().Version()) + require.Equal(t, "https://opentelemetry.io/schemas/1.21.0", sms.At(0).SchemaUrl()) require.Equal(t, 0, sms.At(0).Scope().Attributes().Len()) require.Equal(t, "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver", sms.At(1).Scope().Name()) + require.Empty(t, sms.At(1).SchemaUrl()) require.Equal(t, 0, sms.At(1).Scope().Attributes().Len()) require.Equal(t, "scope.with.attributes", sms.At(2).Scope().Name()) require.Equal(t, "v1.5.0", sms.At(2).Scope().Version()) + require.Empty(t, sms.At(2).SchemaUrl()) require.Equal(t, 1, sms.At(2).Scope().Attributes().Len()) scopeAttrVal, found := sms.At(2).Scope().Attributes().Get("animal") require.True(t, found) require.Equal(t, "bear", scopeAttrVal.Str()) - // Check that otel_scope_name and otel_scope_version are dropped from metric data point attributes + // Check that otel_scope_name, otel_scope_version, and otel_scope_schema_url are dropped from metric data point attributes require.Equal(t, 1, sms.At(0).Metrics().Len()) metric := sms.At(0).Metrics().At(0) dp := metric.Gauge().DataPoints().At(0)