From e73d47713579f4fb627ce9305874dd51768d49a7 Mon Sep 17 00:00:00 2001 From: Martin Majlis Date: Fri, 20 Oct 2023 09:08:04 +0200 Subject: [PATCH] Extract exportSettings into structure + add more tests --- exporter/datasetexporter/README.md | 9 +- exporter/datasetexporter/config.go | 40 +-- exporter/datasetexporter/config_test.go | 19 +- .../datasetexporter/datasetexporter_test.go | 7 + exporter/datasetexporter/factory_test.go | 14 +- .../datasetexporter/logs_exporter_test.go | 252 +++++++++++++----- .../datasetexporter/traces_exporter_test.go | 162 ++++++++++- 7 files changed, 394 insertions(+), 109 deletions(-) diff --git a/exporter/datasetexporter/README.md b/exporter/datasetexporter/README.md index 7cae6cb9dc45..8ac481490d15 100644 --- a/exporter/datasetexporter/README.md +++ b/exporter/datasetexporter/README.md @@ -76,10 +76,11 @@ Make sure to provide the appropriate server host value in the `serverHost` attri Enabled attributes are exported in the order: -1. Body -2. Resource attributes -3. Scope attributes -4. Log attributes +1. Log properties +2. Body +3. Resource attributes +4. Scope attributes +5. Log attributes If there is a name conflict, the `export_distinguishing_suffix` value is appended to the later attribute's name. If the `export_distinguishing_suffix` value is an empty string, then the value from the last attribute is used. diff --git a/exporter/datasetexporter/config.go b/exporter/datasetexporter/config.go index 983760ad5e4d..c497086434be 100644 --- a/exporter/datasetexporter/config.go +++ b/exporter/datasetexporter/config.go @@ -17,23 +17,37 @@ import ( "go.opentelemetry.io/collector/exporter/exporterhelper" ) -const tracesExportSeparatorDefault = "." -const tracesExportDistinguishingSuffix = "_" +const exportSeparatorDefault = "." +const exportDistinguishingSuffix = "_" -type TracesSettings struct { +// exportSettings configures separator and distinguishing suffixes for all exported fields +type exportSettings struct { // ExportSeparator is separator used when flattening exported attributes // Default value: . ExportSeparator string `mapstructure:"export_separator"` + // ExportDistinguishingSuffix is suffix used to be appended to the end of attribute name in case of collision // Default value: _ ExportDistinguishingSuffix string `mapstructure:"export_distinguishing_suffix"` } +// newDefaultExportSettings returns the default settings for exportSettings. +func newDefaultExportSettings() exportSettings { + return exportSettings{ + ExportSeparator: exportSeparatorDefault, + ExportDistinguishingSuffix: exportDistinguishingSuffix, + } +} + +type TracesSettings struct { + // exportSettings configures separator and distinguishing suffixes for all exported fields + exportSettings `mapstructure:",squash"` +} + // newDefaultTracesSettings returns the default settings for TracesSettings. func newDefaultTracesSettings() TracesSettings { return TracesSettings{ - ExportSeparator: tracesExportSeparatorDefault, - ExportDistinguishingSuffix: tracesExportDistinguishingSuffix, + exportSettings: newDefaultExportSettings(), } } @@ -41,8 +55,6 @@ const logsExportResourceInfoDefault = false const logsExportResourcePrefixDefault = "resource.attributes." const logsExportScopeInfoDefault = true const logsExportScopePrefixDefault = "scope.attributes." -const logsExportSeparatorDefault = "." -const logsExportDistinguishingSuffix = "_" const logsDecomposeComplexMessageFieldDefault = false const logsDecomposedComplexMessageFieldPrefixDefault = "body.map." @@ -65,14 +77,6 @@ type LogsSettings struct { // Default value: scope.attributes. ExportScopePrefix string `mapstructure:"export_scope_prefix"` - // ExportSeparator is separator used when flattening exported attributes - // Default value: . - ExportSeparator string `mapstructure:"export_separator"` - - // ExportDistinguishingSuffix is suffix used to be appended to the end of attribute name in case of collision - // Default value: _ - ExportDistinguishingSuffix string `mapstructure:"export_distinguishing_suffix"` - // DecomposeComplexMessageField is an optional flag to signal that message / body of complex types (e.g. a map) should be // decomposed / deconstructed into multiple fields. This is usually done outside of the main DataSet integration on the // client side (e.g. as part of the attribute processor or similar) or on the server side (DataSet server side JSON parser @@ -82,6 +86,9 @@ type LogsSettings struct { // DecomposedComplexMessagePrefix is prefix for the decomposed complex message (see DecomposeComplexMessageField). // Default value: body.map. DecomposedComplexMessagePrefix string `mapstructure:"decomposed_complex_message_prefix"` + + // exportSettings configures separator and distinguishing suffixes for all exported fields + exportSettings `mapstructure:",squash"` } // newDefaultLogsSettings returns the default settings for LogsSettings. @@ -91,10 +98,9 @@ func newDefaultLogsSettings() LogsSettings { ExportResourcePrefix: logsExportResourcePrefixDefault, ExportScopeInfo: logsExportScopeInfoDefault, ExportScopePrefix: logsExportScopePrefixDefault, - ExportSeparator: logsExportSeparatorDefault, - ExportDistinguishingSuffix: logsExportDistinguishingSuffix, DecomposeComplexMessageField: logsDecomposeComplexMessageFieldDefault, DecomposedComplexMessagePrefix: logsDecomposedComplexMessageFieldPrefixDefault, + exportSettings: newDefaultExportSettings(), } } diff --git a/exporter/datasetexporter/config_test.go b/exporter/datasetexporter/config_test.go index 8ab0b5dad1ba..44470519ad53 100644 --- a/exporter/datasetexporter/config_test.go +++ b/exporter/datasetexporter/config_test.go @@ -46,8 +46,11 @@ func TestConfigUseDefaults(t *testing.T) { assert.Equal(t, logsExportResourcePrefixDefault, config.LogsSettings.ExportResourcePrefix) assert.Equal(t, logsExportScopeInfoDefault, config.LogsSettings.ExportScopeInfo) assert.Equal(t, logsExportScopePrefixDefault, config.LogsSettings.ExportScopePrefix) - assert.Equal(t, logsExportSeparatorDefault, config.LogsSettings.ExportSeparator) assert.Equal(t, logsDecomposeComplexMessageFieldDefault, config.LogsSettings.DecomposeComplexMessageField) + assert.Equal(t, exportSeparatorDefault, config.LogsSettings.exportSettings.ExportSeparator) + assert.Equal(t, exportDistinguishingSuffix, config.LogsSettings.exportSettings.ExportDistinguishingSuffix) + assert.Equal(t, exportSeparatorDefault, config.TracesSettings.exportSettings.ExportSeparator) + assert.Equal(t, exportDistinguishingSuffix, config.TracesSettings.exportSettings.ExportDistinguishingSuffix) } func TestConfigValidate(t *testing.T) { @@ -110,18 +113,22 @@ func TestConfigString(t *testing.T) { GroupBy: []string{"field1", "field2"}, }, TracesSettings: TracesSettings{ - ExportSeparator: "TTT", - ExportDistinguishingSuffix: "UUU", + exportSettings: exportSettings{ + ExportSeparator: "TTT", + ExportDistinguishingSuffix: "UUU", + }, }, LogsSettings: LogsSettings{ ExportResourceInfo: true, ExportResourcePrefix: "AAA", ExportScopeInfo: true, ExportScopePrefix: "BBB", - ExportSeparator: "CCC", - ExportDistinguishingSuffix: "DDD", DecomposeComplexMessageField: true, DecomposedComplexMessagePrefix: "EEE", + exportSettings: exportSettings{ + ExportSeparator: "CCC", + ExportDistinguishingSuffix: "DDD", + }, }, ServerHostSettings: ServerHostSettings{ ServerHost: "foo-bar", @@ -133,7 +140,7 @@ func TestConfigString(t *testing.T) { } assert.Equal(t, - "DatasetURL: https://example.com; BufferSettings: {MaxLifetime:123ns GroupBy:[field1 field2] RetryInitialInterval:0s RetryMaxInterval:0s RetryMaxElapsedTime:0s RetryShutdownTimeout:0s}; LogsSettings: {ExportResourceInfo:true ExportResourcePrefix:AAA ExportScopeInfo:true ExportScopePrefix:BBB ExportSeparator:CCC ExportDistinguishingSuffix:DDD DecomposeComplexMessageField:true DecomposedComplexMessagePrefix:EEE}; TracesSettings: {ExportSeparator:TTT ExportDistinguishingSuffix:UUU}; ServerHostSettings: {UseHostName:false ServerHost:foo-bar}; RetrySettings: {Enabled:true InitialInterval:5s RandomizationFactor:0.5 Multiplier:1.5 MaxInterval:30s MaxElapsedTime:5m0s}; QueueSettings: {Enabled:true NumConsumers:10 QueueSize:1000 StorageID:}; TimeoutSettings: {Timeout:5s}", + "DatasetURL: https://example.com; BufferSettings: {MaxLifetime:123ns GroupBy:[field1 field2] RetryInitialInterval:0s RetryMaxInterval:0s RetryMaxElapsedTime:0s RetryShutdownTimeout:0s}; LogsSettings: {ExportResourceInfo:true ExportResourcePrefix:AAA ExportScopeInfo:true ExportScopePrefix:BBB DecomposeComplexMessageField:true DecomposedComplexMessagePrefix:EEE exportSettings:{ExportSeparator:CCC ExportDistinguishingSuffix:DDD}}; TracesSettings: {exportSettings:{ExportSeparator:TTT ExportDistinguishingSuffix:UUU}}; ServerHostSettings: {UseHostName:false ServerHost:foo-bar}; RetrySettings: {Enabled:true InitialInterval:5s RandomizationFactor:0.5 Multiplier:1.5 MaxInterval:30s MaxElapsedTime:5m0s}; QueueSettings: {Enabled:true NumConsumers:10 QueueSize:1000 StorageID:}; TimeoutSettings: {Timeout:5s}", config.String(), ) } diff --git a/exporter/datasetexporter/datasetexporter_test.go b/exporter/datasetexporter/datasetexporter_test.go index 08019c8c8946..09a7fb5bb1f5 100644 --- a/exporter/datasetexporter/datasetexporter_test.go +++ b/exporter/datasetexporter/datasetexporter_test.go @@ -6,6 +6,7 @@ package datasetexporter import "go.opentelemetry.io/collector/pdata/pcommon" func fillAttributes(attr pcommon.Map, allTypes bool, valueSuffix string) { + // simple types attr.PutStr("string", "string"+valueSuffix) if allTypes { attr.PutDouble("double", 2.0) @@ -14,6 +15,7 @@ func fillAttributes(attr pcommon.Map, allTypes bool, valueSuffix string) { attr.PutInt("int", 3) } + // map attr.PutEmptyMap("empty_map") mVal := attr.PutEmptyMap("map") mVal.PutStr("map_string", "map_string"+valueSuffix) @@ -21,8 +23,13 @@ func fillAttributes(attr pcommon.Map, allTypes bool, valueSuffix string) { mVal2 := mVal.PutEmptyMap("map_map") mVal2.PutStr("map_map_string", "map_map_string"+valueSuffix) + // slice attr.PutEmptySlice("empty_slice") sVal := attr.PutEmptySlice("slice") sVal.AppendEmpty() sVal.At(0).SetStr("slice_string" + valueSuffix) + + // colliding attributes + attr.PutStr("span_id", "filled_span_id"+valueSuffix) + attr.PutStr("name", "filled_name"+valueSuffix) } diff --git a/exporter/datasetexporter/factory_test.go b/exporter/datasetexporter/factory_test.go index ad296af8e98c..2e3d3f0dab65 100644 --- a/exporter/datasetexporter/factory_test.go +++ b/exporter/datasetexporter/factory_test.go @@ -93,18 +93,22 @@ func TestLoadConfig(t *testing.T) { RetryShutdownTimeout: 24 * time.Second, }, TracesSettings: TracesSettings{ - ExportSeparator: "_Y_", - ExportDistinguishingSuffix: "_T_", + exportSettings: exportSettings{ + ExportSeparator: "_Y_", + ExportDistinguishingSuffix: "_T_", + }, }, LogsSettings: LogsSettings{ ExportResourceInfo: true, ExportResourcePrefix: "_resource_", ExportScopeInfo: true, ExportScopePrefix: "_scope_", - ExportSeparator: "_X_", - ExportDistinguishingSuffix: "_L_", DecomposeComplexMessageField: true, DecomposedComplexMessagePrefix: "_body_", + exportSettings: exportSettings{ + ExportSeparator: "_X_", + ExportDistinguishingSuffix: "_L_", + }, }, ServerHostSettings: ServerHostSettings{ UseHostName: false, @@ -156,7 +160,7 @@ func createExporterTests() []CreateTest { { name: "broken", config: &Config{}, - expectedError: fmt.Errorf("cannot get DataSetExpoter: cannot convert config: DatasetURL: ; BufferSettings: {MaxLifetime:0s GroupBy:[] RetryInitialInterval:0s RetryMaxInterval:0s RetryMaxElapsedTime:0s RetryShutdownTimeout:0s}; LogsSettings: {ExportResourceInfo:false ExportResourcePrefix: ExportScopeInfo:false ExportScopePrefix: ExportSeparator: ExportDistinguishingSuffix: DecomposeComplexMessageField:false DecomposedComplexMessagePrefix:}; TracesSettings: {ExportSeparator: ExportDistinguishingSuffix:}; ServerHostSettings: {UseHostName:false ServerHost:}; RetrySettings: {Enabled:false InitialInterval:0s RandomizationFactor:0 Multiplier:0 MaxInterval:0s MaxElapsedTime:0s}; QueueSettings: {Enabled:false NumConsumers:0 QueueSize:0 StorageID:}; TimeoutSettings: {Timeout:0s}; config is not valid: api_key is required"), + expectedError: fmt.Errorf("cannot get DataSetExpoter: cannot convert config: DatasetURL: ; BufferSettings: {MaxLifetime:0s GroupBy:[] RetryInitialInterval:0s RetryMaxInterval:0s RetryMaxElapsedTime:0s RetryShutdownTimeout:0s}; LogsSettings: {ExportResourceInfo:false ExportResourcePrefix: ExportScopeInfo:false ExportScopePrefix: DecomposeComplexMessageField:false DecomposedComplexMessagePrefix: exportSettings:{ExportSeparator: ExportDistinguishingSuffix:}}; TracesSettings: {exportSettings:{ExportSeparator: ExportDistinguishingSuffix:}}; ServerHostSettings: {UseHostName:false ServerHost:}; RetrySettings: {Enabled:false InitialInterval:0s RandomizationFactor:0 Multiplier:0 MaxInterval:0s MaxElapsedTime:0s}; QueueSettings: {Enabled:false NumConsumers:0 QueueSize:0 StorageID:}; TimeoutSettings: {Timeout:0s}; config is not valid: api_key is required"), }, { name: "valid", diff --git a/exporter/datasetexporter/logs_exporter_test.go b/exporter/datasetexporter/logs_exporter_test.go index 2a458f74ee62..a0a7f62f3929 100644 --- a/exporter/datasetexporter/logs_exporter_test.go +++ b/exporter/datasetexporter/logs_exporter_test.go @@ -209,15 +209,17 @@ var testLEventReq = &add_events.Event{ func TestBuildEventFromLog(t *testing.T) { tests := []struct { - name string - settings LogsSettings - complexBody bool - expected add_events.EventAttrs + name string + settings LogsSettings + complexBody bool + includeSpanID bool + expected add_events.EventAttrs }{ { - name: "DefaultSimpleBody", - settings: newDefaultLogsSettings(), - complexBody: false, + name: "DefaultSimpleBody", + settings: newDefaultLogsSettings(), + complexBody: false, + includeSpanID: false, expected: add_events.EventAttrs{ "message": "This is a log message", @@ -226,44 +228,83 @@ func TestBuildEventFromLog(t *testing.T) { "map.map_string": "map_stringA", "map.map_map.map_map_string": "map_map_stringA", "slice.0": "slice_stringA", + "name": "filled_nameA", + "span_id": "filled_span_idA", "scope.attributes.string": "stringS", "scope.attributes.map.map_empty": nil, "scope.attributes.map.map_string": "map_stringS", "scope.attributes.map.map_map.map_map_string": "map_map_stringS", "scope.attributes.slice.0": "slice_stringS", + "scope.attributes.name": "filled_nameS", + "scope.attributes.span_id": "filled_span_idS", }, }, { - name: "DefaultComplexBody", - settings: newDefaultLogsSettings(), - complexBody: true, + name: "DefaultComplexBody", + settings: newDefaultLogsSettings(), + complexBody: true, + includeSpanID: false, expected: add_events.EventAttrs{ - "message": "{\"empty_map\":{},\"empty_slice\":[],\"map\":{\"map_empty\":null,\"map_map\":{\"map_map_string\":\"map_map_stringM\"},\"map_string\":\"map_stringM\"},\"slice\":[\"slice_stringM\"],\"string\":\"stringM\"}", + "message": "{\"empty_map\":{},\"empty_slice\":[],\"map\":{\"map_empty\":null,\"map_map\":{\"map_map_string\":\"map_map_stringM\"},\"map_string\":\"map_stringM\"},\"name\":\"filled_nameM\",\"slice\":[\"slice_stringM\"],\"span_id\":\"filled_span_idM\",\"string\":\"stringM\"}", "string": "stringA", "map.map_empty": nil, "map.map_string": "map_stringA", "map.map_map.map_map_string": "map_map_stringA", "slice.0": "slice_stringA", + "name": "filled_nameA", + "span_id": "filled_span_idA", "scope.attributes.string": "stringS", "scope.attributes.map.map_empty": nil, "scope.attributes.map.map_string": "map_stringS", "scope.attributes.map.map_map.map_map_string": "map_map_stringS", "scope.attributes.slice.0": "slice_stringS", + "scope.attributes.name": "filled_nameS", + "scope.attributes.span_id": "filled_span_idS", }, }, { - name: "FullSimpleBody", - complexBody: false, + name: "DefaultComplexBodyWithSpanID", + settings: newDefaultLogsSettings(), + complexBody: true, + includeSpanID: true, + expected: add_events.EventAttrs{ + "message": "{\"empty_map\":{},\"empty_slice\":[],\"map\":{\"map_empty\":null,\"map_map\":{\"map_map_string\":\"map_map_stringM\"},\"map_string\":\"map_stringM\"},\"name\":\"filled_nameM\",\"slice\":[\"slice_stringM\"],\"span_id\":\"filled_span_idM\",\"string\":\"stringM\"}", + + "span_id": "0101010101010101", + + "string": "stringA", + "map.map_empty": nil, + "map.map_string": "map_stringA", + "map.map_map.map_map_string": "map_map_stringA", + "slice.0": "slice_stringA", + "name": "filled_nameA", + "span_id_": "filled_span_idA", + + "scope.attributes.string": "stringS", + "scope.attributes.map.map_empty": nil, + "scope.attributes.map.map_string": "map_stringS", + "scope.attributes.map.map_map.map_map_string": "map_map_stringS", + "scope.attributes.slice.0": "slice_stringS", + "scope.attributes.name": "filled_nameS", + "scope.attributes.span_id": "filled_span_idS", + }, + }, + { + name: "FullSimpleBody", + complexBody: false, + includeSpanID: false, settings: LogsSettings{ - ExportResourceInfo: true, - ExportResourcePrefix: "__R__", - ExportScopeInfo: true, - ExportScopePrefix: "__S__", - ExportSeparator: ".SEP.", - ExportDistinguishingSuffix: ".SUF.", + ExportResourceInfo: true, + ExportResourcePrefix: "__R__", + ExportScopeInfo: true, + ExportScopePrefix: "__S__", + exportSettings: exportSettings{ + ExportSeparator: ".SEP.", + ExportDistinguishingSuffix: ".SUF.", + }, DecomposeComplexMessageField: true, DecomposedComplexMessagePrefix: "__M__", }, @@ -275,74 +316,94 @@ func TestBuildEventFromLog(t *testing.T) { "map.SEP.map_string": "map_stringA", "map.SEP.map_map.SEP.map_map_string": "map_map_stringA", "slice.SEP.0": "slice_stringA", + "name": "filled_nameA", + "span_id": "filled_span_idA", "__S__string": "stringS", "__S__map.SEP.map_empty": nil, "__S__map.SEP.map_string": "map_stringS", "__S__map.SEP.map_map.SEP.map_map_string": "map_map_stringS", "__S__slice.SEP.0": "slice_stringS", + "__S__name": "filled_nameS", + "__S__span_id": "filled_span_idS", "__R__string": "stringR", "__R__map.SEP.map_empty": nil, "__R__map.SEP.map_string": "map_stringR", "__R__map.SEP.map_map.SEP.map_map_string": "map_map_stringR", "__R__slice.SEP.0": "slice_stringR", + "__R__name": "filled_nameR", + "__R__span_id": "filled_span_idR", "__R__resource-attr": "resource-attr-val-1", }, }, { - name: "FullComplexBody", - complexBody: true, + name: "FullComplexBody", + complexBody: true, + includeSpanID: false, settings: LogsSettings{ - ExportResourceInfo: true, - ExportResourcePrefix: "__R__", - ExportScopeInfo: true, - ExportScopePrefix: "__S__", - ExportSeparator: ".SEP.", - ExportDistinguishingSuffix: ".SUF.", + ExportResourceInfo: true, + ExportResourcePrefix: "__R__", + ExportScopeInfo: true, + ExportScopePrefix: "__S__", + exportSettings: exportSettings{ + ExportSeparator: ".SEP.", + ExportDistinguishingSuffix: ".SUF.", + }, DecomposeComplexMessageField: true, DecomposedComplexMessagePrefix: "__M__", }, expected: add_events.EventAttrs{ - "message": "{\"empty_map\":{},\"empty_slice\":[],\"map\":{\"map_empty\":null,\"map_map\":{\"map_map_string\":\"map_map_stringM\"},\"map_string\":\"map_stringM\"},\"slice\":[\"slice_stringM\"],\"string\":\"stringM\"}", + "message": "{\"empty_map\":{},\"empty_slice\":[],\"map\":{\"map_empty\":null,\"map_map\":{\"map_map_string\":\"map_map_stringM\"},\"map_string\":\"map_stringM\"},\"name\":\"filled_nameM\",\"slice\":[\"slice_stringM\"],\"span_id\":\"filled_span_idM\",\"string\":\"stringM\"}", "__M__string": "stringM", "__M__map.SEP.map_empty": nil, "__M__map.SEP.map_string": "map_stringM", "__M__map.SEP.map_map.SEP.map_map_string": "map_map_stringM", "__M__slice.SEP.0": "slice_stringM", + "__M__name": "filled_nameM", + "__M__span_id": "filled_span_idM", "string": "stringA", "map.SEP.map_empty": nil, "map.SEP.map_string": "map_stringA", "map.SEP.map_map.SEP.map_map_string": "map_map_stringA", "slice.SEP.0": "slice_stringA", + "name": "filled_nameA", + "span_id": "filled_span_idA", "__S__string": "stringS", "__S__map.SEP.map_empty": nil, "__S__map.SEP.map_string": "map_stringS", "__S__map.SEP.map_map.SEP.map_map_string": "map_map_stringS", "__S__slice.SEP.0": "slice_stringS", + "__S__name": "filled_nameS", + "__S__span_id": "filled_span_idS", "__R__string": "stringR", "__R__map.SEP.map_empty": nil, "__R__map.SEP.map_string": "map_stringR", "__R__map.SEP.map_map.SEP.map_map_string": "map_map_stringR", "__R__slice.SEP.0": "slice_stringR", + "__R__name": "filled_nameR", + "__R__span_id": "filled_span_idR", "__R__resource-attr": "resource-attr-val-1", }, }, { - name: "Minimal", - complexBody: false, + name: "Minimal", + complexBody: false, + includeSpanID: false, settings: LogsSettings{ - ExportResourceInfo: false, - ExportResourcePrefix: "__R__", - ExportScopeInfo: false, - ExportScopePrefix: "__S__", - ExportSeparator: ".SEP.", - ExportDistinguishingSuffix: ".SUP.", + ExportResourceInfo: false, + ExportResourcePrefix: "__R__", + ExportScopeInfo: false, + ExportScopePrefix: "__S__", + exportSettings: exportSettings{ + ExportSeparator: ".SEP.", + ExportDistinguishingSuffix: ".SUF.", + }, DecomposeComplexMessageField: false, }, expected: add_events.EventAttrs{ @@ -353,18 +414,23 @@ func TestBuildEventFromLog(t *testing.T) { "map.SEP.map_string": "map_stringA", "map.SEP.map_map.SEP.map_map_string": "map_map_stringA", "slice.SEP.0": "slice_stringA", + "name": "filled_nameA", + "span_id": "filled_span_idA", }, }, { - name: "EmptyPrefixesAndNonEmptySuffixSimpleBody", - complexBody: false, + name: "EmptyPrefixesAndNonEmptySuffixSimpleBody", + complexBody: false, + includeSpanID: false, settings: LogsSettings{ - ExportResourceInfo: true, - ExportResourcePrefix: "", - ExportScopeInfo: true, - ExportScopePrefix: "", - ExportSeparator: ".SEP.", - ExportDistinguishingSuffix: ".SUF.", + ExportResourceInfo: true, + ExportResourcePrefix: "", + ExportScopeInfo: true, + ExportScopePrefix: "", + exportSettings: exportSettings{ + ExportSeparator: ".SEP.", + ExportDistinguishingSuffix: ".SUF.", + }, DecomposeComplexMessageField: true, }, expected: add_events.EventAttrs{ @@ -375,75 +441,95 @@ func TestBuildEventFromLog(t *testing.T) { "map.SEP.map_string": "map_stringR", "map.SEP.map_map.SEP.map_map_string": "map_map_stringR", "slice.SEP.0": "slice_stringR", + "name": "filled_nameR", + "span_id": "filled_span_idR", "string.SUF.": "stringS", "map.SEP.map_empty.SUF.": nil, "map.SEP.map_string.SUF.": "map_stringS", "map.SEP.map_map.SEP.map_map_string.SUF.": "map_map_stringS", "slice.SEP.0.SUF.": "slice_stringS", + "name.SUF.": "filled_nameS", + "span_id.SUF.": "filled_span_idS", "string.SUF..SUF.": "stringA", "map.SEP.map_empty.SUF..SUF.": nil, "map.SEP.map_string.SUF..SUF.": "map_stringA", "map.SEP.map_map.SEP.map_map_string.SUF..SUF.": "map_map_stringA", "slice.SEP.0.SUF..SUF.": "slice_stringA", + "name.SUF..SUF.": "filled_nameA", + "span_id.SUF..SUF.": "filled_span_idA", "resource-attr": "resource-attr-val-1", }, }, { - name: "EmptyPrefixesAndNonEmptySuffixComplexBody", - complexBody: true, + name: "EmptyPrefixesAndNonEmptySuffixComplexBody", + complexBody: true, + includeSpanID: false, settings: LogsSettings{ - ExportResourceInfo: true, - ExportResourcePrefix: "", - ExportScopeInfo: true, - ExportScopePrefix: "", - ExportSeparator: ".SEP.", - ExportDistinguishingSuffix: ".SUF.", + ExportResourceInfo: true, + ExportResourcePrefix: "", + ExportScopeInfo: true, + ExportScopePrefix: "", + exportSettings: exportSettings{ + ExportSeparator: ".SEP.", + ExportDistinguishingSuffix: ".SUF.", + }, DecomposeComplexMessageField: true, DecomposedComplexMessagePrefix: "", }, expected: add_events.EventAttrs{ - "message": "{\"empty_map\":{},\"empty_slice\":[],\"map\":{\"map_empty\":null,\"map_map\":{\"map_map_string\":\"map_map_stringM\"},\"map_string\":\"map_stringM\"},\"slice\":[\"slice_stringM\"],\"string\":\"stringM\"}", + "message": "{\"empty_map\":{},\"empty_slice\":[],\"map\":{\"map_empty\":null,\"map_map\":{\"map_map_string\":\"map_map_stringM\"},\"map_string\":\"map_stringM\"},\"name\":\"filled_nameM\",\"slice\":[\"slice_stringM\"],\"span_id\":\"filled_span_idM\",\"string\":\"stringM\"}", "string": "stringM", "map.SEP.map_empty": nil, "map.SEP.map_string": "map_stringM", "map.SEP.map_map.SEP.map_map_string": "map_map_stringM", "slice.SEP.0": "slice_stringM", + "name": "filled_nameM", + "span_id": "filled_span_idM", "string.SUF.": "stringR", "map.SEP.map_empty.SUF.": nil, "map.SEP.map_string.SUF.": "map_stringR", "map.SEP.map_map.SEP.map_map_string.SUF.": "map_map_stringR", "slice.SEP.0.SUF.": "slice_stringR", + "name.SUF.": "filled_nameR", + "span_id.SUF.": "filled_span_idR", "string.SUF..SUF.": "stringS", "map.SEP.map_empty.SUF..SUF.": nil, "map.SEP.map_string.SUF..SUF.": "map_stringS", "map.SEP.map_map.SEP.map_map_string.SUF..SUF.": "map_map_stringS", "slice.SEP.0.SUF..SUF.": "slice_stringS", + "name.SUF..SUF.": "filled_nameS", + "span_id.SUF..SUF.": "filled_span_idS", "string.SUF..SUF..SUF.": "stringA", "map.SEP.map_empty.SUF..SUF..SUF.": nil, "map.SEP.map_string.SUF..SUF..SUF.": "map_stringA", "map.SEP.map_map.SEP.map_map_string.SUF..SUF..SUF.": "map_map_stringA", "slice.SEP.0.SUF..SUF..SUF.": "slice_stringA", + "name.SUF..SUF..SUF.": "filled_nameA", + "span_id.SUF..SUF..SUF.": "filled_span_idA", "resource-attr": "resource-attr-val-1", }, }, { - name: "EmptyPrefixesAndEmptySuffixSimpleBody", - complexBody: false, + name: "EmptyPrefixesAndEmptySuffixSimpleBody", + complexBody: false, + includeSpanID: false, settings: LogsSettings{ - ExportResourceInfo: true, - ExportResourcePrefix: "", - ExportScopeInfo: true, - ExportScopePrefix: "", - ExportSeparator: ".SEP.", - ExportDistinguishingSuffix: "", + ExportResourceInfo: true, + ExportResourcePrefix: "", + ExportScopeInfo: true, + ExportScopePrefix: "", + exportSettings: exportSettings{ + ExportSeparator: ".SEP.", + ExportDistinguishingSuffix: "", + }, DecomposeComplexMessageField: true, DecomposedComplexMessagePrefix: "", }, @@ -455,31 +541,38 @@ func TestBuildEventFromLog(t *testing.T) { "map.SEP.map_string": "map_stringA", "map.SEP.map_map.SEP.map_map_string": "map_map_stringA", "slice.SEP.0": "slice_stringA", + "name": "filled_nameA", + "span_id": "filled_span_idA", "resource-attr": "resource-attr-val-1", }, }, { - name: "EmptyPrefixesAndEmptySuffixSimpleBody", - complexBody: true, + name: "EmptyPrefixesAndEmptySuffixComplexBody", + complexBody: true, + includeSpanID: false, settings: LogsSettings{ - ExportResourceInfo: true, - ExportResourcePrefix: "", - ExportScopeInfo: true, - ExportScopePrefix: "", - ExportSeparator: ".SEP.", - ExportDistinguishingSuffix: "", + ExportResourceInfo: true, + ExportResourcePrefix: "", + ExportScopeInfo: true, + ExportScopePrefix: "", + exportSettings: exportSettings{ + ExportSeparator: ".SEP.", + ExportDistinguishingSuffix: "", + }, DecomposeComplexMessageField: true, DecomposedComplexMessagePrefix: "", }, expected: add_events.EventAttrs{ - "message": "{\"empty_map\":{},\"empty_slice\":[],\"map\":{\"map_empty\":null,\"map_map\":{\"map_map_string\":\"map_map_stringM\"},\"map_string\":\"map_stringM\"},\"slice\":[\"slice_stringM\"],\"string\":\"stringM\"}", + "message": "{\"empty_map\":{},\"empty_slice\":[],\"map\":{\"map_empty\":null,\"map_map\":{\"map_map_string\":\"map_map_stringM\"},\"map_string\":\"map_stringM\"},\"name\":\"filled_nameM\",\"slice\":[\"slice_stringM\"],\"span_id\":\"filled_span_idM\",\"string\":\"stringM\"}", "string": "stringA", "map.SEP.map_empty": nil, "map.SEP.map_string": "map_stringA", "map.SEP.map_map.SEP.map_map_string": "map_map_stringA", "slice.SEP.0": "slice_stringA", + "name": "filled_nameA", + "span_id": "filled_span_idA", "resource-attr": "resource-attr-val-1", }, @@ -497,6 +590,9 @@ func TestBuildEventFromLog(t *testing.T) { fillAttributes(scope.Attributes(), false, "S") fillAttributes(ld.Attributes(), false, "A") ld.SetTimestamp(testdata.TestLogTimestamp) + if tt.includeSpanID { + ld.SetSpanID([8]byte{1, 1, 1, 1, 1, 1, 1, 1}) + } if tt.complexBody { m := ld.Body().SetEmptyMap() @@ -721,10 +817,16 @@ func TestConsumeLogsShouldSucceed(t *testing.T) { ExportResourcePrefix: "R#", ExportScopeInfo: true, ExportScopePrefix: "S#", - ExportSeparator: "#", + exportSettings: exportSettings{ + ExportSeparator: "#", + ExportDistinguishingSuffix: "_", + }, }, TracesSettings: TracesSettings{ - ExportSeparator: "?", + exportSettings: exportSettings{ + ExportSeparator: "?", + ExportDistinguishingSuffix: "-", + }, }, ServerHostSettings: ServerHostSettings{ ServerHost: testServerHost, @@ -888,6 +990,8 @@ func TestConsumeLogsShouldSucceed(t *testing.T) { "map#map_string": "map_stringA", "map#map_map#map_map_string": "map_map_stringA", "slice#0": "slice_stringA", + "name": "filled_nameA", + "span_id_": "filled_span_idA", "S#string": "stringS", "S#double": 2.0, @@ -898,6 +1002,8 @@ func TestConsumeLogsShouldSucceed(t *testing.T) { "S#map#map_string": "map_stringS", "S#map#map_map#map_map_string": "map_map_stringS", "S#slice#0": "slice_stringS", + "S#name": "filled_nameS", + "S#span_id": "filled_span_idS", "R#string": "stringR", "R#double": 2.0, @@ -908,6 +1014,8 @@ func TestConsumeLogsShouldSucceed(t *testing.T) { "R#map#map_string": "map_stringR", "R#map#map_map#map_map_string": "map_map_stringR", "R#slice#0": "slice_stringR", + "R#name": "filled_nameR", + "R#span_id": "filled_span_idR", "R#resource-attr": "resource-attr-val-1", }, diff --git a/exporter/datasetexporter/traces_exporter_test.go b/exporter/datasetexporter/traces_exporter_test.go index 94aedb351cb2..4f268ff7bb41 100644 --- a/exporter/datasetexporter/traces_exporter_test.go +++ b/exporter/datasetexporter/traces_exporter_test.go @@ -247,11 +247,15 @@ func TestBuildEventsFromSpanAttributesDifferentTypes(t *testing.T) { "status_message": "", "resource_name": "", "resource_type": "process", - "string": "stringA", - "double": 2.0, - "bool": true, - "empty": nil, - "int": int64(3), + + "name_": "filled_nameA", + "span_id_": "filled_span_idA", + + "string": "stringA", + "double": 2.0, + "bool": true, + "empty": nil, + "int": int64(3), "map.map_empty": nil, "map.map_string": "map_stringA", @@ -276,6 +280,154 @@ func TestBuildEventsFromSpanAttributesDifferentTypes(t *testing.T) { assert.Equal(t, expected, was) } +func TestBuildEventFromSpan(t *testing.T) { + tests := []struct { + name string + settings TracesSettings + expected add_events.EventAttrs + }{ + { + name: "Default", + settings: newDefaultTracesSettings(), + expected: add_events.EventAttrs{ + "sca:schemVer": 1, + "sca:schema": "tracing", + "sca:type": "span", + + "name": "", + "kind": "unspecified", + + "start_time_unix_nano": "0", + "end_time_unix_nano": "0", + "duration_nano": "0", + + "span_id": "0101010101010101", + "trace_id": "", + "status_code": "unset", + "status_message": "", + "resource_name": "", + "resource_type": "process", + "name_": "filled_nameA", + "span_id_": "filled_span_idA", + + "string": "stringA", + "map.map_empty": nil, + "map.map_string": "map_stringA", + "map.map_map.map_map_string": "map_map_stringA", + "slice.0": "slice_stringA", + }, + }, + { + name: "Custom", + settings: TracesSettings{ + exportSettings{ + ExportSeparator: ".SEP.", + ExportDistinguishingSuffix: ".SUF.", + }, + }, + expected: add_events.EventAttrs{ + "sca:schemVer": 1, + "sca:schema": "tracing", + "sca:type": "span", + + "name": "", + "kind": "unspecified", + + "start_time_unix_nano": "0", + "end_time_unix_nano": "0", + "duration_nano": "0", + + "span_id": "0101010101010101", + "trace_id": "", + "status_code": "unset", + "status_message": "", + "resource_name": "", + "resource_type": "process", + "name.SUF.": "filled_nameA", + "span_id.SUF.": "filled_span_idA", + + "string": "stringA", + "map.SEP.map_empty": nil, + "map.SEP.map_string": "map_stringA", + "map.SEP.map_map.SEP.map_map_string": "map_map_stringA", + "slice.SEP.0": "slice_stringA", + }, + }, + { + name: "EmptySuffix", + settings: TracesSettings{ + exportSettings{ + ExportSeparator: ".SEP.", + ExportDistinguishingSuffix: "", + }, + }, + expected: add_events.EventAttrs{ + "sca:schemVer": 1, + "sca:schema": "tracing", + "sca:type": "span", + + "name": "filled_nameA", + "kind": "unspecified", + + "start_time_unix_nano": "0", + "end_time_unix_nano": "0", + "duration_nano": "0", + + "span_id": "filled_span_idA", + "trace_id": "", + "status_code": "unset", + "status_message": "", + "resource_name": "", + "resource_type": "process", + + "string": "stringA", + "map.SEP.map_empty": nil, + "map.SEP.map_string": "map_stringA", + "map.SEP.map_map.SEP.map_map_string": "map_map_stringA", + "slice.SEP.0": "slice_stringA", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + td := ptrace.NewTraces() + rs := td.ResourceSpans().AppendEmpty() + rss := rs.ScopeSpans().AppendEmpty() + span := rss.Spans().AppendEmpty() + span.SetSpanID([8]byte{1, 1, 1, 1, 1, 1, 1, 1}) + fillAttributes(span.Attributes(), false, "A") + fillAttributes(rss.Scope().Attributes(), false, "S") + fillAttributes(rs.Resource().Attributes(), false, "R") + + expected := &add_events.EventBundle{ + Event: &add_events.Event{ + Thread: "TT", + Log: "LT", + Sev: 9, + Ts: "0", + Attrs: tt.expected, + ServerHost: testServerHost, + }, + Thread: testTThread, + Log: testTLog, + } + + was := buildEventFromSpan( + spanBundle{ + span, + rs.Resource(), + rss.Scope(), + }, + testServerHost, + tt.settings, + ) + + assert.Equal(t, expected, was) + }) + } +} + func TestBuildEventsFromTracesFromTwoSpansSameResourceOneDifferent(t *testing.T) { traces := testdata.GenerateTracesTwoSpansSameResourceOneDifferent() traces.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).Attributes().PutStr("serverHost", "")