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

[exporter/datadog]: update error formatting for error spans that are not exceptions. #3701

Merged
Merged
24 changes: 17 additions & 7 deletions exporter/datadogexporter/translate_traces.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,17 +549,27 @@ func getSpanErrorAndSetTags(s pdata.Span, tags map[string]string) int32 {

if isError == errorCode {
extractErrorTagsFromEvents(s, tags)
// If we weren't able to pull an error type or message, go ahead and set
// these to the old defaults
if _, ok := tags[ext.ErrorType]; !ok {
tags[ext.ErrorType] = "ERR_CODE_" + strconv.FormatInt(int64(status.Code()), 10)
}

// if the error message doesnt exist, try to infer useful error information from
// the status message, and http status code / http status text.
// if we find useful error.message info, also set a fallback error.type
// otherwise leave these tags unset and allow the UI to handle defaults
if _, ok := tags[ext.ErrorMsg]; !ok {
if status.Message() != "" {
tags[ext.ErrorMsg] = status.Message()
} else {
tags[ext.ErrorMsg] = "ERR_CODE_" + strconv.FormatInt(int64(status.Code()), 10)
// look for useful http metadata if it exists and add that as a fallback for the error message
} else if statusCode, ok := tags[conventions.AttributeHTTPStatusCode]; ok {
if statusText, ok := tags[conventions.AttributeHTTPStatusText]; ok {
tags[ext.ErrorMsg] = fmt.Sprintf("%s %s", statusCode, statusText)
} else {
tags[ext.ErrorMsg] = statusCode
}
}

// If we weren't able to pull an error type, but we do have an error message
// set to a reasonable default
if (tags[ext.ErrorType] == "") && (tags[ext.ErrorMsg] != "") {
tags[ext.ErrorType] = "error"
}
}
}
Expand Down
51 changes: 51 additions & 0 deletions exporter/datadogexporter/translate_traces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,57 @@ func TestTracesTranslationErrorsAndResource(t *testing.T) {
assert.Contains(t, datadogPayload.Traces[0].Spans[0].Meta[tagContainersTags], "container_id:3249847017410247")
assert.Contains(t, datadogPayload.Traces[0].Spans[0].Meta[tagContainersTags], "pod_name:example-pod-name")
assert.Contains(t, datadogPayload.Traces[0].Spans[0].Meta[tagContainersTags], "arn:aws:ecs:ap-southwest-1:241423265983:task/test-environment-test-echo-Cluster-2lrqTJKFjACT/746bf64740324812835f688c30cf1512")

// ensure that span error type uses a fallback of "error" if a status code exists
assert.Equal(t, "error", datadogPayload.Traces[0].Spans[0].Meta["error.type"])
}

func TestTracesFallbackErrorMessage(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)
pdataEndTime := pdata.TimestampFromTime(mockEndTime)
startTime := mockEndTime.Add(-90 * time.Second)
pdataStartTime := pdata.TimestampFromTime(startTime)

rs := pdata.NewResourceSpans()
ilss := rs.InstrumentationLibrarySpans()
ils := ilss.AppendEmpty()
ils.InstrumentationLibrary().SetName("test_il_name")
ils.InstrumentationLibrary().SetVersion("test_il_version")
span := ils.Spans().AppendEmpty()

traceID := pdata.NewTraceID(mockTraceID)
spanID := pdata.NewSpanID(mockSpanID)
parentSpanID := pdata.NewSpanID(mockParentSpanID)
span.SetTraceID(traceID)
span.SetSpanID(spanID)
span.SetParentSpanID(parentSpanID)
span.SetName("End-To-End Here")
span.SetKind(pdata.SpanKindServer)
span.SetStartTimestamp(pdataStartTime)
span.SetEndTimestamp(pdataEndTime)
span.SetTraceState("tracestatekey=tracestatevalue")

status := span.Status()
status.SetCode(pdata.StatusCodeError)

span.Attributes().InsertString(conventions.AttributeHTTPStatusCode, "404")
span.Attributes().InsertString(conventions.AttributeHTTPStatusText, "Not Found")

// translate mocks to datadog traces
datadogPayload := resourceSpansToDatadogSpans(rs, hostname, &config.Config{}, denylister, map[string]string{})

// ensure that span error type uses a fallback of "error"
assert.Equal(t, "error", datadogPayload.Traces[0].Spans[0].Meta["error.type"])

// ensure that span error type uses a fallback of "status_code" and "status_text"
assert.Equal(t, "404 Not Found", datadogPayload.Traces[0].Spans[0].Meta["error.msg"])
}

// Ensures that if more than one error event occurs in a span, the last one is used for translation
Expand Down