Skip to content

Commit

Permalink
Allow specifying Collector's own Resource in the config
Browse files Browse the repository at this point in the history
Resolves #5398

This adds a sub-section in the `service.telemetry` config section where any
Resource attributes can be specified.

For example we can have the following in the config:

service:
  telemetry:
    resource:
      service.instance.id: 01G3EN4NW306AFVGQT5ZYC0GEK
      service.namespace: onlineshop
      deployment.environment: production
  • Loading branch information
tigrannajaryan committed May 19, 2022
1 parent d11fe93 commit 39c367d
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 22 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
### 💡 Enhancements 💡

- Update OTLP to v0.17.0 (#5335)
- User-defined Resource attributes can be specified under `service.telemetry.resource`
configuration key and will be included as metric lables for own telemetry.
If `service.instance.id` is not specified it will be auto-generated. Previously
`service.instance.id` was always auto-generated, so the default of the new
behavior matches the old behavior. (#5402)

### 🧰 Bug fixes 🧰

Expand Down
5 changes: 3 additions & 2 deletions config/moved_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ type Service struct {
// ServiceTelemetry defines the configurable settings for service telemetry.
// Deprecated: [v0.52.0] Use service.ConfigServiceTelemetry
type ServiceTelemetry struct {
Logs ServiceTelemetryLogs `mapstructure:"logs"`
Metrics ServiceTelemetryMetrics `mapstructure:"metrics"`
Logs ServiceTelemetryLogs `mapstructure:"logs"`
Metrics ServiceTelemetryMetrics `mapstructure:"metrics"`
Resource map[string]string `mapstructure:"resource"`
}

// ServiceTelemetryLogs defines the configurable settings for service telemetry logs.
Expand Down
48 changes: 38 additions & 10 deletions service/collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"go.opentelemetry.io/collector/config/mapconverter/overwritepropertiesmapconverter"
"go.opentelemetry.io/collector/internal/testcomponents"
"go.opentelemetry.io/collector/internal/testutil"
"go.opentelemetry.io/collector/internal/version"
"go.opentelemetry.io/collector/service/featuregate"
)

Expand Down Expand Up @@ -194,10 +195,25 @@ func testCollectorStartHelper(t *testing.T, telemetry collectorTelemetryExporter
cfgSet := newDefaultConfigProviderSettings([]string{
filepath.Join("testdata", "otelcol-config.yaml"),
})

// Define some Resource attributes.
userDefinedResource := map[string]string{
"custom_resource_attr": "resource_attr_test_value",
}

// Prepare config properties to be merged with the main config.
extraCfgAsProps := []string{
// Set the metrics address to expose own metrics on.
"service.telemetry.metrics.address=" + metricsAddr,
}
// Also include resource attributes under the service.telemetry.resource key.
for k, v := range userDefinedResource {
extraCfgAsProps = append(extraCfgAsProps,
"service.telemetry.resource."+k+"="+v)
}

cfgSet.MapConverters = append([]config.MapConverterFunc{
overwritepropertiesmapconverter.New(
[]string{"service.telemetry.metrics.address=" + metricsAddr},
)},
overwritepropertiesmapconverter.New(extraCfgAsProps)},
cfgSet.MapConverters...,
)
cfgProvider, err := NewConfigProvider(cfgSet)
Expand Down Expand Up @@ -226,9 +242,18 @@ func testCollectorStartHelper(t *testing.T, telemetry collectorTelemetryExporter
// and requires a good justification. The reason is that changes to metric
// names or labels can break alerting, dashboards, etc that are used to
// monitor the Collector in production deployments.
mandatoryLabels := []string{
"service_instance_id",
mandatoryLabels := map[string]string{
"service_instance_id": "", // Empty string means the value will not be asserted.
}
if AddCollectorVersionTag {
mandatoryLabels["service_version"] = version.Version
}

// Attributes of user defined Resource must also be included as labels of metrics.
for k, v := range userDefinedResource {
mandatoryLabels[k] = v
}

assertMetrics(t, metricsAddr, mandatoryLabels)

assertZPages(t)
Expand Down Expand Up @@ -316,7 +341,7 @@ func (tel *mockColTelemetry) shutdown() error {
return errors.New("err1")
}

func assertMetrics(t *testing.T, metricsAddr string, mandatoryLabels []string) {
func assertMetrics(t *testing.T, metricsAddr string, mandatoryLabels map[string]string) {
client := &http.Client{}
resp, err := client.Get("http://" + metricsAddr + "/metrics")
require.NoError(t, err)
Expand All @@ -341,14 +366,17 @@ func assertMetrics(t *testing.T, metricsAddr string, mandatoryLabels []string) {
metricName[:len(prefix)+1]+"...")

for _, metric := range metricFamily.Metric {
var labelNames []string
labelMap := map[string]string{}
for _, labelPair := range metric.Label {
labelNames = append(labelNames, *labelPair.Name)
labelMap[*labelPair.Name] = *labelPair.Value
}

for _, mandatoryLabel := range mandatoryLabels {
for k, v := range mandatoryLabels {
// require is used here so test fails with a single message.
require.Contains(t, labelNames, mandatoryLabel, "mandatory label %q not present", mandatoryLabel)
require.NotEmpty(t, labelMap[k], "mandatory label %q not present", k)
if v != "" {
require.Equal(t, v, labelMap[k], "mandatory label %q value mismatch", k)
}
}
}
}
Expand Down
32 changes: 22 additions & 10 deletions service/telemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ func (tel *colTelemetry) init(col *Collector) error {
func (tel *colTelemetry) initOnce(col *Collector) error {
logger := col.telemetry.Logger
cfg := col.service.config.Telemetry
resource := cfg.Resource

level := cfg.Metrics.Level
metricsAddr := cfg.Metrics.Address
Expand All @@ -109,8 +110,22 @@ func (tel *colTelemetry) initOnce(col *Collector) error {

logger.Info("Setting up own telemetry...")

instanceUUID, _ := uuid.NewRandom()
instanceID := instanceUUID.String()
if resource == nil {
resource = map[string]string{}
}

var instanceID string
instanceID = resource[semconv.AttributeServiceInstanceID]
if instanceID == "" {
// AttributeServiceInstanceID is not specified in the config. Auto-generate one.
instanceUUID, _ := uuid.NewRandom()
instanceID = instanceUUID.String()
resource[semconv.AttributeServiceInstanceID] = instanceID
}

if AddCollectorVersionTag {
resource[semconv.AttributeServiceVersion] = version.Version
}

var pe http.Handler
if tel.registry.IsEnabled(useOtelForInternalMetricsfeatureGateID) {
Expand All @@ -120,7 +135,7 @@ func (tel *colTelemetry) initOnce(col *Collector) error {
}
pe = otelHandler
} else {
ocHandler, err := tel.initOpenCensus(col, instanceID)
ocHandler, err := tel.initOpenCensus(col, resource)
if err != nil {
return err
}
Expand All @@ -131,8 +146,7 @@ func (tel *colTelemetry) initOnce(col *Collector) error {
"Serving Prometheus metrics",
zap.String(zapKeyTelemetryAddress, metricsAddr),
zap.String(zapKeyTelemetryLevel, level.String()),
zap.String(semconv.AttributeServiceInstanceID, instanceID),
zap.String(semconv.AttributeServiceVersion, version.Version),
zap.Any("Resource", resource),
)

mux := http.NewServeMux()
Expand All @@ -152,7 +166,7 @@ func (tel *colTelemetry) initOnce(col *Collector) error {
return nil
}

func (tel *colTelemetry) initOpenCensus(col *Collector, instanceID string) (http.Handler, error) {
func (tel *colTelemetry) initOpenCensus(col *Collector, labels map[string]string) (http.Handler, error) {
processMetricsViews, err := telemetry2.NewProcessMetricsViews(getBallastSize(col.service.host))
if err != nil {
return nil, err
Expand All @@ -178,10 +192,8 @@ func (tel *colTelemetry) initOpenCensus(col *Collector, instanceID string) (http

opts.ConstLabels = make(map[string]string)

opts.ConstLabels[sanitizePrometheusKey(semconv.AttributeServiceInstanceID)] = instanceID

if AddCollectorVersionTag {
opts.ConstLabels[sanitizePrometheusKey(semconv.AttributeServiceVersion)] = version.Version
for k, v := range labels {
opts.ConstLabels[sanitizePrometheusKey(k)] = v
}

pe, err := prometheus.NewExporter(opts)
Expand Down

0 comments on commit 39c367d

Please sign in to comment.