From dc99e20f5f39feed14c744d9245ff95a55ba432f Mon Sep 17 00:00:00 2001 From: Abhishek Saharn <102726227+asaharn@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:16:31 +0530 Subject: [PATCH] [exporter/azuredataexplorer] Status Attributes added to exported traces (#26682) **Description:** Added an optional column in the exported trace data to store the status code and message as a dynamic field. **Link to tracking Issue:** [#26496](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/26496) **Testing:** Performed E2E ingestion tests and added Test Cases for new fields. **Documentation:** --------- Co-authored-by: Ramachandran A G Co-authored-by: Ramachandran A G <106139410+ag-ramachandran@users.noreply.github.com> --- .chloggen/bugfix_26496105-StatusMessage.yaml | 27 +++++++++ exporter/azuredataexplorerexporter/README.md | 7 ++- .../azuredataexplorerexporter/e2e_test.go | 2 + .../tracesdata_to_adx.go | 9 ++- .../tracesdata_to_adx_test.go | 55 ++++++++++++++++++- 5 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 .chloggen/bugfix_26496105-StatusMessage.yaml diff --git a/.chloggen/bugfix_26496105-StatusMessage.yaml b/.chloggen/bugfix_26496105-StatusMessage.yaml new file mode 100644 index 000000000000..b6603fbe8ab2 --- /dev/null +++ b/.chloggen/bugfix_26496105-StatusMessage.yaml @@ -0,0 +1,27 @@ +# 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: azuredataexplorerexporter + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Added an optional column in the exported trace data to store the status code and message as a dynamic field. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [26496] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# 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/exporter/azuredataexplorerexporter/README.md b/exporter/azuredataexplorerexporter/README.md index 31f511a42127..6831e803a85d 100644 --- a/exporter/azuredataexplorerexporter/README.md +++ b/exporter/azuredataexplorerexporter/README.md @@ -92,7 +92,8 @@ This exporter maps OpenTelemetry [trace](https://opentelemetry.io/docs/referenc | SpanId | A valid span identifier is an 8-byte array with at least one non-zero byte. | | ParentId | A parent spanId, for the current span | | SpanName | The span name | -| SpanStatus | [Status](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status) of the Span. | +| SpanStatus | [Status Code](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status) of the Span. | +| SpanStatusMessage | [Status Message](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status) of the Span | | SpanKind | [SpanKind](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#spankind) describes the relationship between the Span, its parents, and its children in a Trace | | StartTime | A start timestamp | | EndTime | An end timestamp | @@ -140,6 +141,10 @@ The following tables need to be created in the database specified in the configu .create-merge table (TraceID:string, SpanID:string, ParentID:string, SpanName:string, SpanStatus:string, SpanKind:string, StartTime:datetime, EndTime:datetime, ResourceAttributes:dynamic, TraceAttributes:dynamic, Events:dynamic, Links:dynamic) +// This is an optional column to store the status code and message as a dynamic field. This augments the status field with Status code and status message + +.alter-merge table (SpanStatusMessage:string) + //Enable streaming ingestion( for managed streaming) for the created tables using .alter table policy streamingingestion enable diff --git a/exporter/azuredataexplorerexporter/e2e_test.go b/exporter/azuredataexplorerexporter/e2e_test.go index b4b896dc5e57..0718c0e04938 100644 --- a/exporter/azuredataexplorerexporter/e2e_test.go +++ b/exporter/azuredataexplorerexporter/e2e_test.go @@ -106,6 +106,7 @@ func TestCreateTracesExporterE2E(t *testing.T) { assert.Equal(t, "", recs[i].ParentID) assert.Equal(t, spanName, recs[i].SpanName) assert.Equal(t, "STATUS_CODE_UNSET", recs[i].SpanStatus) + assert.Equal(t, "STATUS_MESSAGE", recs[i].SpanStatusMessage) assert.Equal(t, "SPAN_KIND_UNSPECIFIED", recs[i].SpanKind) assert.Equal(t, epochTimeString, recs[i].StartTime) assert.Equal(t, epochTimeString, recs[i].EndTime) @@ -258,6 +259,7 @@ func createTraces() (ptrace.Traces, string, map[string]interface{}) { td := ptrace.NewTraces() span := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.SetName(spanName) + span.Status().SetMessage("STATUS_MESSAGE") attrs := map[string]interface{}{ "k0": "v0", "k1": "v1", diff --git a/exporter/azuredataexplorerexporter/tracesdata_to_adx.go b/exporter/azuredataexplorerexporter/tracesdata_to_adx.go index e2aa53cbaa31..3189f0aed4d2 100644 --- a/exporter/azuredataexplorerexporter/tracesdata_to_adx.go +++ b/exporter/azuredataexplorerexporter/tracesdata_to_adx.go @@ -17,7 +17,8 @@ type AdxTrace struct { SpanID string // SpanID associated to the Trace ParentID string // ParentID associated to the Trace SpanName string // The SpanName of the Trace - SpanStatus string // The SpanStatus associated to the Trace + SpanStatus string // The SpanStatus Code associated to the Trace + SpanStatusMessage string // The SpanStatusMessage associated to the Trace SpanKind string // The SpanKind of the Trace StartTime string // The start time of the occurrence. Formatted into string as RFC3339Nano EndTime string // The end time of the occurrence. Formatted into string as RFC3339Nano @@ -40,6 +41,11 @@ type Link struct { SpanLinkAttributes map[string]interface{} } +type Status struct { + Code string + Message string +} + func mapToAdxTrace(resource pcommon.Resource, scope pcommon.InstrumentationScope, spanData ptrace.Span) *AdxTrace { traceAttrib := spanData.Attributes().AsRaw() @@ -52,6 +58,7 @@ func mapToAdxTrace(resource pcommon.Resource, scope pcommon.InstrumentationScope ParentID: traceutil.SpanIDToHexOrEmptyString(spanData.ParentSpanID()), SpanName: spanData.Name(), SpanStatus: traceutil.StatusCodeStr(spanData.Status().Code()), + SpanStatusMessage: spanData.Status().Message(), SpanKind: traceutil.SpanKindStr(spanData.Kind()), StartTime: spanData.StartTimestamp().AsTime().Format(time.RFC3339Nano), EndTime: spanData.EndTimestamp().AsTime().Format(time.RFC3339Nano), diff --git a/exporter/azuredataexplorerexporter/tracesdata_to_adx_test.go b/exporter/azuredataexplorerexporter/tracesdata_to_adx_test.go index acb157834764..337723424894 100644 --- a/exporter/azuredataexplorerexporter/tracesdata_to_adx_test.go +++ b/exporter/azuredataexplorerexporter/tracesdata_to_adx_test.go @@ -33,7 +33,6 @@ func Test_mapToAdxTrace(t *testing.T) { { name: "valid", spanDatafn: func() ptrace.Span { - span := ptrace.NewSpan() span.SetName("spanname") span.Status().SetCode(ptrace.StatusCodeUnset) @@ -84,7 +83,6 @@ func Test_mapToAdxTrace(t *testing.T) { }, { name: "with_events_links", spanDatafn: func() ptrace.Span { - span := ptrace.NewSpan() span.SetName("spanname") span.Status().SetCode(ptrace.StatusCodeUnset) @@ -134,6 +132,59 @@ func Test_mapToAdxTrace(t *testing.T) { }}, }, }, + { + name: "with_status_message_for_error", + spanDatafn: func() ptrace.Span { + span := ptrace.NewSpan() + span.SetName("spanname-status-message") + span.Status().SetCode(ptrace.StatusCodeError) + span.Status().SetMessage("An error occurred") + span.SetTraceID(pcommon.TraceID(traceID)) + span.SetSpanID(pcommon.SpanID(spanID)) + span.SetKind(ptrace.SpanKindServer) + span.SetStartTimestamp(ts) + span.SetEndTimestamp(ts) + span.Attributes().PutStr("traceAttribKey", "traceAttribVal") + event := span.Events().AppendEmpty() + event.SetName("eventName") + event.SetTimestamp(ts) + event.Attributes().PutStr("eventkey", "eventvalue") + + link := span.Links().AppendEmpty() + link.SetSpanID(pcommon.SpanID(spanID)) + link.SetTraceID(pcommon.TraceID(traceID)) + link.TraceState().FromRaw("") + return span + }, + resourceFn: newDummyResource, + insScopeFn: newScopeWithData, + expectedAdxTrace: &AdxTrace{ + TraceID: "00000000000000000000000000000064", + SpanID: "0000000000000032", + ParentID: "", + SpanName: "spanname-status-message", + SpanStatus: "STATUS_CODE_ERROR", + SpanStatusMessage: "An error occurred", + SpanKind: "SPAN_KIND_SERVER", + StartTime: tstr, + EndTime: tstr, + ResourceAttributes: tmap, + TraceAttributes: newMapFromAttr(`{"traceAttribKey":"traceAttribVal", "scope.name":"testscope", "scope.version":"1.0"}`), + Events: []*Event{ + { + EventName: "eventName", + EventAttributes: newMapFromAttr(`{"eventkey": "eventvalue"}`), + Timestamp: tstr, + }, + }, + Links: []*Link{{ + TraceID: "00000000000000000000000000000064", + SpanID: "0000000000000032", + TraceState: "", + SpanLinkAttributes: newMapFromAttr(`{}`), + }}, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {