Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Datadog] Span naming option to use OTel semantic convention #6611

Merged
merged 13 commits into from
Jan 7, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- `prometheusremotewriteexporter`: Handling Staleness flag from OTLP (#6679)
- `mysqlreceiver`: Add Integration test (#6916)
- `datadogexporter`: Add compatibility with ECS Fargate semantic conventions (#6670)
- `datadogexporter`: Add configuration option to use OTel span name into the Datatog resource name (#6611)
- `k8s_observer`: discover k8s.node endpoints (#6820)
- `redisreceiver`: Add missing description fields to keyspace metrics (#6940)
- `kafkaexporter`: Allow controlling Kafka acknowledgment behaviour (#6301)
Expand Down
10 changes: 10 additions & 0 deletions exporter/datadogexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ datadog:
site: datadoghq.eu
```

If you want to use the OpenTelemetry Span Name as the Datadog Resource Name you can set the `span_name_as_resource_name` configuration option to `true` (default is `false`). For more info on the downsides of this option check [this](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/1909) issue.

```yaml
datadog:
api:
key: "<API key>"
traces:
span_name_as_resource_name: true
```

The hostname, environment, service and version can be set in the configuration for unified service tagging.
The exporter will try to retrieve a hostname following the OpenTelemetry semantic conventions if there is one available.

Expand Down
5 changes: 5 additions & 0 deletions exporter/datadogexporter/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ type TracesConfig struct {
// instrumentation:express.server: express
// go.opentelemetry.io_contrib_instrumentation_net_http_otelhttp.client: http.client
SpanNameRemappings map[string]string `mapstructure:"span_name_remappings"`

// If set to true the OpenTelemetry span name will used in the Datadog resource name.
// If set to false the resource name will be filled with the instrumentation library name + span kind.
// The default value is `false`.
SpanNameAsResourceName bool `mapstructure:"span_name_as_resource_name"`
}

// TagsConfig defines the tag-related configuration
Expand Down
7 changes: 7 additions & 0 deletions exporter/datadogexporter/example/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,13 @@ exporters:
# instrumentation:express.server: express
# go.opentelemetry.io_contrib_instrumentation_net_http_otelhttp.client: http.client

## @param span_name_as_resource_name - use OpenTelemetry semantic convention for span naming - optional
## Option created to maintain similarity with the OpenTelemetry semantic conventions as discussed in the issue below.
## https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/trace/semantic_conventions
## https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/1909
#
# span_name_as_resource_name: true
gfonseca-tc marked this conversation as resolved.
Show resolved Hide resolved


service:
pipelines:
Expand Down
7 changes: 6 additions & 1 deletion exporter/datadogexporter/translate_traces.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,10 +304,15 @@ func spanToDatadogSpan(s pdata.Span,

resourceName := getDatadogResourceName(s, tags)

name := s.Name()
if !cfg.Traces.SpanNameAsResourceName {
name = getDatadogSpanName(s, tags)
}

span := &pb.Span{
TraceID: decodeAPMTraceID(s.TraceID().Bytes()),
SpanID: decodeAPMSpanID(s.SpanID().Bytes()),
Name: remapDatadogSpanName(getDatadogSpanName(s, tags), spanNameMap),
Name: remapDatadogSpanName(name, spanNameMap),
Resource: resourceName,
Service: normalizedServiceName,
Start: int64(startTime),
Expand Down
29 changes: 29 additions & 0 deletions exporter/datadogexporter/translate_traces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1571,3 +1571,32 @@ func TestSpanRateLimitTag(t *testing.T) {

assert.Equal(t, 0.5, outputTraces[0].Traces[0].Spans[0].Metrics["_sample_rate"])
}

func TestTracesSpanNamingOption(t *testing.T) {
hostname := "testhostname"
denylister := newDenylister([]string{})

// generate mock trace, span and parent span ids
mockTraceID := [16]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}
mockSpanID := [8]byte{0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8}
mockParentSpanID := [8]byte{0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8}

mockEndTime := time.Now().Round(time.Second)

// create mock resource span data
// toggle on errors and custom service naming to test edge case code paths
rs := NewResourceSpansData(mockTraceID, mockSpanID, mockParentSpanID, pdata.StatusCodeUnset, false, mockEndTime)

// start with span name as resource name set to true
cfgSpanNameAsResourceName := config.Config{
Traces: config.TracesConfig{
SpanNameAsResourceName: true,
},
}

// translate mocks to datadog traces
datadogPayloadSpanNameAsResourceName := resourceSpansToDatadogSpans(rs, hostname, &cfgSpanNameAsResourceName, denylister, map[string]string{})

// ensure the resource name is replaced with the span name when the option is set
assert.Equal(t, "End-To-End Here", datadogPayloadSpanNameAsResourceName.Traces[0].Spans[0].Name)
}