From 696e914414274e1e9f5116153f92f8d6da791205 Mon Sep 17 00:00:00 2001 From: Tigran Najaryan Date: Mon, 26 Sep 2022 15:39:10 -0400 Subject: [PATCH] Add service.name resource attribute to the collector's own telemetry Resolves https://github.com/open-telemetry/opentelemetry-collector/issues/6136 - The default service.name is set to "io.opentelemetry.collector". I think this is a good choice since it is unambiguous and is still short enough to be readable. This also matches the OpAMP recommendations: https://github.com/open-telemetry/opamp-spec/blob/main/specification.md#agentdescriptionidentifying_attributes - The service.name can be overridden by the end user via telemetry config setting. --- CHANGELOG.md | 1 + cmd/otelcorecol/builder-config.yaml | 1 + service/telemetry.go | 59 +++++++++++++++--------- service/telemetry_test.go | 69 +++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 21 deletions(-) create mode 100644 service/telemetry_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 45154704f1f..472355170b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - Add AppendEmpty and EnsureCapacity method to primitive pdata slices (#6060) - Expose `AsRaw` and `FromRaw` `pcommon.Value` methods (#6090) +- service.name Resource attribute is added to Collector's own telemetry and defaults to "io.opentelemetry.collector" (#6152) ## v0.60.0 Beta diff --git a/cmd/otelcorecol/builder-config.yaml b/cmd/otelcorecol/builder-config.yaml index 9baebf8c784..86bcb89b600 100644 --- a/cmd/otelcorecol/builder-config.yaml +++ b/cmd/otelcorecol/builder-config.yaml @@ -4,6 +4,7 @@ dist: description: Local OpenTelemetry Collector binary, testing only. version: 0.60.0-dev otelcol_version: 0.60.0 + service_name: io.opentelemetry.collector receivers: - import: go.opentelemetry.io/collector/receiver/otlpreceiver diff --git a/service/telemetry.go b/service/telemetry.go index 0ce6057b780..2eaefc007e0 100644 --- a/service/telemetry.go +++ b/service/telemetry.go @@ -60,6 +60,11 @@ const ( // supported trace propagators traceContextPropagator = "tracecontext" b3Propagator = "b3" + + // Default value of "service.name" attribute in the telemetry + // that the Collector produces about itself. This can be overridden + // by the end user via telemetry.Config.Resource setting. + defaultServiceName = "io.opentelemetry.collector" ) var ( @@ -112,27 +117,8 @@ func (tel *telemetryInitializer) initOnce(buildInfo component.BuildInfo, logger logger.Info("Setting up own telemetry...") - // Construct telemetry attributes from resource attributes. - telAttrs := map[string]string{} - for k, v := range cfg.Resource { - // nil value indicates that the attribute should not be included in the telemetry. - if v != nil { - telAttrs[k] = *v - } - } - - if _, ok := cfg.Resource[semconv.AttributeServiceInstanceID]; !ok { - // AttributeServiceInstanceID is not specified in the config. Auto-generate one. - instanceUUID, _ := uuid.NewRandom() - instanceID := instanceUUID.String() - telAttrs[semconv.AttributeServiceInstanceID] = instanceID - } - - if _, ok := cfg.Resource[semconv.AttributeServiceVersion]; !ok { - // AttributeServiceVersion is not specified in the config. Use the actual - // build version. - telAttrs[semconv.AttributeServiceVersion] = buildInfo.Version - } + // Construct telemetry attributes from build info and config's resource attributes. + telAttrs := buildTelAttrs(buildInfo, cfg) if tp, err := textMapPropagatorFromConfig(cfg.Traces.Propagators); err == nil { otel.SetTextMapPropagator(tp) @@ -174,6 +160,37 @@ func (tel *telemetryInitializer) initOnce(buildInfo component.BuildInfo, logger return nil } +func buildTelAttrs(buildInfo component.BuildInfo, cfg telemetry.Config) map[string]string { + telAttrs := map[string]string{} + + for k, v := range cfg.Resource { + // nil value indicates that the attribute should not be included in the telemetry. + if v != nil { + telAttrs[k] = *v + } + } + + if _, ok := cfg.Resource[semconv.AttributeServiceName]; !ok { + // AttributeServiceName is not specified in the config. Use the Service name. + telAttrs[semconv.AttributeServiceName] = defaultServiceName + } + + if _, ok := cfg.Resource[semconv.AttributeServiceInstanceID]; !ok { + // AttributeServiceInstanceID is not specified in the config. Auto-generate one. + instanceUUID, _ := uuid.NewRandom() + instanceID := instanceUUID.String() + telAttrs[semconv.AttributeServiceInstanceID] = instanceID + } + + if _, ok := cfg.Resource[semconv.AttributeServiceVersion]; !ok { + // AttributeServiceVersion is not specified in the config. Use the actual + // build version. + telAttrs[semconv.AttributeServiceVersion] = buildInfo.Version + } + + return telAttrs +} + func (tel *telemetryInitializer) initOpenCensus(cfg telemetry.Config, telAttrs map[string]string) (http.Handler, error) { tel.ocRegistry = ocmetric.NewRegistry() metricproducer.GlobalManager().AddProducer(tel.ocRegistry) diff --git a/service/telemetry_test.go b/service/telemetry_test.go new file mode 100644 index 00000000000..35940d730a8 --- /dev/null +++ b/service/telemetry_test.go @@ -0,0 +1,69 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package service + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/component" + semconv "go.opentelemetry.io/collector/semconv/v1.5.0" + "go.opentelemetry.io/collector/service/telemetry" +) + +func TestBuildTelAttrs(t *testing.T) { + buildInfo := component.NewDefaultBuildInfo() + + // Check default config + cfg := telemetry.Config{} + telAttrs := buildTelAttrs(buildInfo, cfg) + + assert.Len(t, telAttrs, 3) + assert.Equal(t, defaultServiceName, telAttrs[semconv.AttributeServiceName]) + assert.Equal(t, buildInfo.Version, telAttrs[semconv.AttributeServiceVersion]) + + _, exists := telAttrs[semconv.AttributeServiceInstanceID] + assert.True(t, exists) + + // Check override by nil + cfg = telemetry.Config{ + Resource: map[string]*string{ + semconv.AttributeServiceName: nil, + semconv.AttributeServiceVersion: nil, + semconv.AttributeServiceInstanceID: nil, + }, + } + telAttrs = buildTelAttrs(buildInfo, cfg) + + // Attributes should not exist since we nil-ified all. + assert.Len(t, telAttrs, 0) + + // Check override values + strPtr := func(v string) *string { return &v } + cfg = telemetry.Config{ + Resource: map[string]*string{ + semconv.AttributeServiceName: strPtr("a"), + semconv.AttributeServiceVersion: strPtr("b"), + semconv.AttributeServiceInstanceID: strPtr("c"), + }, + } + telAttrs = buildTelAttrs(buildInfo, cfg) + + assert.Len(t, telAttrs, 3) + assert.Equal(t, "a", telAttrs[semconv.AttributeServiceName]) + assert.Equal(t, "b", telAttrs[semconv.AttributeServiceVersion]) + assert.Equal(t, "c", telAttrs[semconv.AttributeServiceInstanceID]) +}