Skip to content

Commit f0d7e7f

Browse files
authored
[exporter/elasticsearch] Add OTel mapping mode for traces (#34472)
**Description:** <Describe what has changed.> <!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> Add OTel mapping mode for traces. OTel mapping mode is a new mapping mode described in https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/elasticsearchexporter#elasticsearch-document-mapping Update logs and metrics OTel mapping mode to always emit "scope" and zero int, but not emit empty strings for known fields. Breaking change to remove `trace_flags` from logs. **Link to tracking Issue:** <Issue number if applicable> Fixes #34588 #34590 **Testing:** <Describe what testing was performed and which tests were added.> Added exporter tests **Documentation:** <Describe the documentation added.>
1 parent a367136 commit f0d7e7f

File tree

6 files changed

+261
-158
lines changed

6 files changed

+261
-158
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: elasticsearchexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add OTel mapping mode for traces
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [34588, 34590]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
Add OTel mapping mode support for traces, without span events.
20+
21+
# If your change doesn't affect end users or the exported elements of any package,
22+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
23+
# Optional: The change log or logs in which this entry should be included.
24+
# e.g. '[user]' or '[user, api]'
25+
# Include 'user' if the change is relevant to end users.
26+
# Include 'api' if there is a change to a library API.
27+
# Default: '[user]'
28+
change_logs: [user]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: breaking
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: elasticsearchexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Update OTel mapping mode for logs and metrics; Remove trace_flags
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [34472]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
Update logs and metrics OTel mapping mode to always emit "scope" and zero int, but not emit empty strings for known fields.
20+
Breaking change to remove trace_flags from logs.
21+
22+
# If your change doesn't affect end users or the exported elements of any package,
23+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
24+
# Optional: The change log or logs in which this entry should be included.
25+
# e.g. '[user]' or '[user, api]'
26+
# Include 'user' if the change is relevant to end users.
27+
# Include 'api' if there is a change to a library API.
28+
# Default: '[user]'
29+
change_logs: [user]

exporter/elasticsearchexporter/exporter.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ func (e *elasticsearchExporter) pushTraceData(
355355
spans := scopeSpan.Spans()
356356
for k := 0; k < spans.Len(); k++ {
357357
span := spans.At(k)
358-
if err := e.pushTraceRecord(ctx, resource, span, scope, session); err != nil {
358+
if err := e.pushTraceRecord(ctx, resource, il.SchemaUrl(), span, scope, scopeSpan.SchemaUrl(), session); err != nil {
359359
if cerr := ctx.Err(); cerr != nil {
360360
return cerr
361361
}
@@ -377,8 +377,10 @@ func (e *elasticsearchExporter) pushTraceData(
377377
func (e *elasticsearchExporter) pushTraceRecord(
378378
ctx context.Context,
379379
resource pcommon.Resource,
380+
resourceSchemaURL string,
380381
span ptrace.Span,
381382
scope pcommon.InstrumentationScope,
383+
scopeSchemaURL string,
382384
bulkIndexerSession bulkIndexerSession,
383385
) error {
384386
fIndex := e.index
@@ -394,7 +396,7 @@ func (e *elasticsearchExporter) pushTraceRecord(
394396
fIndex = formattedIndex
395397
}
396398

397-
document, err := e.model.encodeSpan(resource, span, scope)
399+
document, err := e.model.encodeSpan(resource, resourceSchemaURL, span, scope, scopeSchemaURL)
398400
if err != nil {
399401
return fmt.Errorf("failed to encode trace record: %w", err)
400402
}

exporter/elasticsearchexporter/exporter_test.go

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ func TestExporterLogs(t *testing.T) {
312312
expected := []itemRequest{
313313
{
314314
Action: []byte(`{"create":{"_index":"logs-attr.dataset.otel-resource.attribute.namespace"}}`),
315-
Document: []byte(`{"@timestamp":"1970-01-01T00:00:00.000000000Z","attributes":{"attr.foo":"attr.foo.value"},"data_stream":{"dataset":"attr.dataset.otel","namespace":"resource.attribute.namespace","type":"logs"},"dropped_attributes_count":0,"observed_timestamp":"1970-01-01T00:00:00.000000000Z","resource":{"attributes":{"resource.attr.foo":"resource.attr.foo.value"},"dropped_attributes_count":0,"schema_url":""},"severity_number":0,"trace_flags":0}`),
315+
Document: []byte(`{"@timestamp":"1970-01-01T00:00:00.000000000Z","attributes":{"attr.foo":"attr.foo.value"},"data_stream":{"dataset":"attr.dataset.otel","namespace":"resource.attribute.namespace","type":"logs"},"dropped_attributes_count":0,"observed_timestamp":"1970-01-01T00:00:00.000000000Z","resource":{"attributes":{"resource.attr.foo":"resource.attr.foo.value"},"dropped_attributes_count":0},"scope":{"dropped_attributes_count":0},"severity_number":0}`),
316316
},
317317
}
318318

@@ -821,19 +821,19 @@ func TestExporterMetrics(t *testing.T) {
821821
expected := []itemRequest{
822822
{
823823
Action: []byte(`{"create":{"_index":"metrics-generic.otel-default","dynamic_templates":{"metrics.metric.foo":"histogram"}}}`),
824-
Document: []byte(`{"@timestamp":"1970-01-01T00:00:00.000000000Z","data_stream":{"dataset":"generic.otel","namespace":"default","type":"metrics"},"metrics":{"metric.foo":{"counts":[1,2,3,4],"values":[0.5,1.5,2.5,3]}},"resource":{"dropped_attributes_count":0,"schema_url":""}}`),
824+
Document: []byte(`{"@timestamp":"1970-01-01T00:00:00.000000000Z","data_stream":{"dataset":"generic.otel","namespace":"default","type":"metrics"},"metrics":{"metric.foo":{"counts":[1,2,3,4],"values":[0.5,1.5,2.5,3]}},"resource":{"dropped_attributes_count":0},"scope":{"dropped_attributes_count":0}}`),
825825
},
826826
{
827827
Action: []byte(`{"create":{"_index":"metrics-generic.otel-default","dynamic_templates":{"metrics.metric.foo":"histogram"}}}`),
828-
Document: []byte(`{"@timestamp":"1970-01-01T01:00:00.000000000Z","data_stream":{"dataset":"generic.otel","namespace":"default","type":"metrics"},"metrics":{"metric.foo":{"counts":[4,5,6,7],"values":[2,4.5,5.5,6]}},"resource":{"dropped_attributes_count":0,"schema_url":""}}`),
828+
Document: []byte(`{"@timestamp":"1970-01-01T01:00:00.000000000Z","data_stream":{"dataset":"generic.otel","namespace":"default","type":"metrics"},"metrics":{"metric.foo":{"counts":[4,5,6,7],"values":[2,4.5,5.5,6]}},"resource":{"dropped_attributes_count":0},"scope":{"dropped_attributes_count":0}}`),
829829
},
830830
{
831831
Action: []byte(`{"create":{"_index":"metrics-generic.otel-default","dynamic_templates":{"metrics.metric.sum":"gauge_double"}}}`),
832-
Document: []byte(`{"@timestamp":"1970-01-01T01:00:00.000000000Z","data_stream":{"dataset":"generic.otel","namespace":"default","type":"metrics"},"metrics":{"metric.sum":1.5},"resource":{"dropped_attributes_count":0,"schema_url":""},"start_timestamp":"1970-01-01T02:00:00.000000000Z"}`),
832+
Document: []byte(`{"@timestamp":"1970-01-01T01:00:00.000000000Z","data_stream":{"dataset":"generic.otel","namespace":"default","type":"metrics"},"metrics":{"metric.sum":1.5},"resource":{"dropped_attributes_count":0},"scope":{"dropped_attributes_count":0},"start_timestamp":"1970-01-01T02:00:00.000000000Z"}`),
833833
},
834834
{
835835
Action: []byte(`{"create":{"_index":"metrics-generic.otel-default","dynamic_templates":{"metrics.metric.summary":"summary_metrics"}}}`),
836-
Document: []byte(`{"@timestamp":"1970-01-01T03:00:00.000000000Z","data_stream":{"dataset":"generic.otel","namespace":"default","type":"metrics"},"metrics":{"metric.summary":{"sum":1.5,"value_count":1}},"resource":{"dropped_attributes_count":0,"schema_url":""},"start_timestamp":"1970-01-01T03:00:00.000000000Z"}`),
836+
Document: []byte(`{"@timestamp":"1970-01-01T03:00:00.000000000Z","data_stream":{"dataset":"generic.otel","namespace":"default","type":"metrics"},"metrics":{"metric.summary":{"sum":1.5,"value_count":1}},"resource":{"dropped_attributes_count":0},"scope":{"dropped_attributes_count":0},"start_timestamp":"1970-01-01T03:00:00.000000000Z"}`),
837837
},
838838
}
839839

@@ -1031,6 +1031,68 @@ func TestExporterTraces(t *testing.T) {
10311031
))
10321032
rec.WaitItems(1)
10331033
})
1034+
1035+
t.Run("otel mode", func(t *testing.T) {
1036+
rec := newBulkRecorder()
1037+
server := newESTestServer(t, func(docs []itemRequest) ([]itemResponse, error) {
1038+
rec.Record(docs)
1039+
return itemsAllOK(docs)
1040+
})
1041+
1042+
exporter := newTestTracesExporter(t, server.URL, func(cfg *Config) {
1043+
cfg.TracesDynamicIndex.Enabled = true
1044+
cfg.Mapping.Mode = "otel"
1045+
})
1046+
1047+
traces := ptrace.NewTraces()
1048+
resourceSpans := traces.ResourceSpans()
1049+
rs := resourceSpans.AppendEmpty()
1050+
1051+
span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty()
1052+
span.SetName("name")
1053+
span.SetTraceID(pcommon.NewTraceIDEmpty())
1054+
span.SetSpanID(pcommon.NewSpanIDEmpty())
1055+
span.SetFlags(1)
1056+
span.SetDroppedAttributesCount(2)
1057+
span.SetDroppedEventsCount(3)
1058+
span.SetDroppedLinksCount(4)
1059+
span.TraceState().FromRaw("foo")
1060+
span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Unix(3600, 0)))
1061+
span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Unix(7200, 0)))
1062+
1063+
scopeAttr := span.Attributes()
1064+
fillResourceAttributeMap(scopeAttr, map[string]string{
1065+
"attr.foo": "attr.bar",
1066+
})
1067+
1068+
resAttr := rs.Resource().Attributes()
1069+
fillResourceAttributeMap(resAttr, map[string]string{
1070+
"resource.foo": "resource.bar",
1071+
})
1072+
1073+
spanLink := span.Links().AppendEmpty()
1074+
spanLink.SetTraceID(pcommon.NewTraceIDEmpty())
1075+
spanLink.SetSpanID(pcommon.NewSpanIDEmpty())
1076+
spanLink.SetFlags(10)
1077+
spanLink.SetDroppedAttributesCount(11)
1078+
spanLink.TraceState().FromRaw("bar")
1079+
fillResourceAttributeMap(spanLink.Attributes(), map[string]string{
1080+
"link.attr.foo": "link.attr.bar",
1081+
})
1082+
1083+
mustSendTraces(t, exporter, traces)
1084+
1085+
rec.WaitItems(1)
1086+
1087+
expected := []itemRequest{
1088+
{
1089+
Action: []byte(`{"create":{"_index":"traces-generic.otel-default"}}`),
1090+
Document: []byte(`{"@timestamp":"1970-01-01T01:00:00.000000000Z","attributes":{"attr.foo":"attr.bar"},"data_stream":{"dataset":"generic.otel","namespace":"default","type":"traces"},"dropped_attributes_count":2,"dropped_events_count":3,"dropped_links_count":4,"duration":3600000000000,"kind":"Unspecified","links":[{"attributes":{"link.attr.foo":"link.attr.bar"},"dropped_attributes_count":11,"span_id":"","trace_id":"","trace_state":"bar"}],"name":"name","resource":{"attributes":{"resource.foo":"resource.bar"},"dropped_attributes_count":0},"scope":{"dropped_attributes_count":0},"status":{"code":"Unset"},"trace_state":"foo"}`),
1091+
},
1092+
}
1093+
1094+
assertItemsEqual(t, expected, rec.Items(), false)
1095+
})
10341096
}
10351097

10361098
// TestExporterAuth verifies that the Elasticsearch exporter supports

0 commit comments

Comments
 (0)