Skip to content

Commit

Permalink
feat(sumologicexporter): add merge_body option to json logs
Browse files Browse the repository at this point in the history
Signed-off-by: Dominik Rosiek <drosiek@sumologic.com>
  • Loading branch information
Dominik Rosiek committed Oct 8, 2021
1 parent b3e3deb commit 29e52d9
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 2 deletions.
4 changes: 4 additions & 0 deletions pkg/exporter/sumologicexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ exporters:
# of the timestamp key.
# default = "timestamp".
timestamp_key: <timestamp_key>
# When flatten_body is set to true and log is a map,
# log's body is going to be flatten and `log_key` won't be used
# default = false
flatten_body: {true, false}

# translate_attributes specifies whether attributes should be translated
# from OpenTelemetry to Sumo conventions;
Expand Down
6 changes: 6 additions & 0 deletions pkg/exporter/sumologicexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ type JSONLogs struct {
// of the timestamp key.
// By default this is "timestamp".
TimestampKey string `mapstructure:"timestamp_key"`
// When flatten_body is set to true and log is a map,
// log's body is going to be flatten and `log_key` won't be used
// By default this is false.
FlattenBody bool `mapstructure:"flatten_body"`
}

// CreateDefaultHTTPClientSettings returns default http client settings
Expand Down Expand Up @@ -197,4 +201,6 @@ const (
DefaultAddTimestamp bool = true
// DefaultTimestampKey defines default TimestampKey value
DefaultTimestampKey string = "timestamp"
// DefaultFlattenBody defines default FlattenBody value
DefaultFlattenBody bool = false
)
1 change: 1 addition & 0 deletions pkg/exporter/sumologicexporter/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func createDefaultConfig() config.Exporter {
LogKey: DefaultLogKey,
AddTimestamp: DefaultAddTimestamp,
TimestampKey: DefaultTimestampKey,
FlattenBody: DefaultFlattenBody,
},
GraphiteTemplate: DefaultGraphiteTemplate,
TraceFormat: OTLPTraceFormat,
Expand Down
10 changes: 9 additions & 1 deletion pkg/exporter/sumologicexporter/sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,15 @@ func (s *sender) logToJSON(record logPair) (string, error) {

// Only append the body when it's not empty to prevent sending 'null' log.
if body := record.log.Body(); !isEmptyAttributeValue(body) {
data.orig.Upsert(s.jsonLogsConfig.LogKey, body)
if s.jsonLogsConfig.FlattenBody && body.Type() == pdata.AttributeValueTypeMap {
// Cannot use CopyTo, as it overrides data.orig's values
body.MapVal().Range(func(k string, v pdata.AttributeValue) bool {
data.orig.Insert(k, v)
return true
})
} else {
data.orig.Upsert(s.jsonLogsConfig.LogKey, body)
}
}

nextLine, err := json.Marshal(data.orig.AsRaw())
Expand Down
71 changes: 70 additions & 1 deletion pkg/exporter/sumologicexporter/sender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,36 @@ func exampleTwoLogs() []pdata.LogRecord {
return buffer
}

func exampleLogWithComplexBody() []pdata.LogRecord {
buffer := make([]pdata.LogRecord, 1)
buffer[0] = pdata.NewLogRecord()
body := pdata.NewAttributeValueMap().MapVal()
body.InsertString("a", "b")
body.InsertBool("c", false)
body.InsertInt("d", 20)
body.InsertDouble("e", 20.5)

f := pdata.NewAttributeValueArray()
f.ArrayVal().EnsureCapacity(4)
f.ArrayVal().AppendEmpty().SetStringVal("p")
f.ArrayVal().AppendEmpty().SetBoolVal(true)
f.ArrayVal().AppendEmpty().SetIntVal(13)
f.ArrayVal().AppendEmpty().SetDoubleVal(19.3)
body.Insert("f", f)

g := pdata.NewAttributeValueMap()
g.MapVal().InsertString("h", "i")
g.MapVal().InsertBool("j", false)
g.MapVal().InsertInt("k", 12)
g.MapVal().InsertDouble("l", 11.1)

body.Insert("g", g)

buffer[0].Attributes().InsertString("m", "n")
buffer[0].Body().SetMapVal(body)
return buffer
}

func exampleTwoDifferentLogs() []pdata.LogRecord {
buffer := make([]pdata.LogRecord, 2)
buffer[0] = pdata.NewLogRecord()
Expand Down Expand Up @@ -403,6 +433,7 @@ func TestSendLogsJsonConfig(t *testing.T) {
name string
configOpts []func(*Config)
bodyRegex string
logBuffer []logPair
}{
{
name: "default config",
Expand All @@ -412,12 +443,14 @@ func TestSendLogsJsonConfig(t *testing.T) {
LogKey: DefaultLogKey,
AddTimestamp: DefaultAddTimestamp,
TimestampKey: DefaultTimestampKey,
FlattenBody: DefaultFlattenBody,
}
},
},
bodyRegex: `{"key1":"value1","key2":"value2","log":"Example log","timestamp":\d{13}}` +
`\n` +
`{"key1":"value1","key2":"value2","log":"Another example log","timestamp":\d{13}}`,
logBuffer: logRecordsToLogPair(exampleTwoLogs()),
},
{
name: "disabled add timestamp",
Expand All @@ -432,6 +465,7 @@ func TestSendLogsJsonConfig(t *testing.T) {
bodyRegex: `{"key1":"value1","key2":"value2","log":"Example log"}` +
`\n` +
`{"key1":"value1","key2":"value2","log":"Another example log"}`,
logBuffer: logRecordsToLogPair(exampleTwoLogs()),
},
{
name: "enabled add timestamp with custom timestamp key",
Expand All @@ -447,6 +481,7 @@ func TestSendLogsJsonConfig(t *testing.T) {
bodyRegex: `{"key1":"value1","key2":"value2","log":"Example log","xxyy_zz":\d{13}}` +
`\n` +
`{"key1":"value1","key2":"value2","log":"Another example log","xxyy_zz":\d{13}}`,
logBuffer: logRecordsToLogPair(exampleTwoLogs()),
},
{
name: "custom log key",
Expand All @@ -456,12 +491,46 @@ func TestSendLogsJsonConfig(t *testing.T) {
LogKey: "log_vendor_key",
AddTimestamp: DefaultAddTimestamp,
TimestampKey: DefaultTimestampKey,
FlattenBody: DefaultFlattenBody,
}
},
},
bodyRegex: `{"key1":"value1","key2":"value2","log_vendor_key":"Example log","timestamp":\d{13}}` +
`\n` +
`{"key1":"value1","key2":"value2","log_vendor_key":"Another example log","timestamp":\d{13}}`,
logBuffer: logRecordsToLogPair(exampleTwoLogs()),
},
{
name: "flatten body",
configOpts: []func(*Config){
func(c *Config) {
c.JSONLogs = JSONLogs{
LogKey: "log_vendor_key",
AddTimestamp: DefaultAddTimestamp,
TimestampKey: DefaultTimestampKey,
FlattenBody: true,
}
},
},
bodyRegex: `{"a":"b","c":false,"d":20,"e":20.5,"f":\["p",true,13,19.3\],` +
`"g":{"h":"i","j":false,"k":12,"l":11.1},"m":"n","timestamp":\d{13}}`,
logBuffer: logRecordsToLogPair(exampleLogWithComplexBody()),
},
{
name: "complex body",
configOpts: []func(*Config){
func(c *Config) {
c.JSONLogs = JSONLogs{
LogKey: "log_vendor_key",
AddTimestamp: DefaultAddTimestamp,
TimestampKey: DefaultTimestampKey,
FlattenBody: DefaultFlattenBody,
}
},
},
bodyRegex: `{"log_vendor_key":{"a":"b","c":false,"d":20,"e":20.5,"f":\["p",true,13,19.3\],` +
`"g":{"h":"i","j":false,"k":12,"l":11.1}},"m":"n","timestamp":\d{13}}`,
logBuffer: logRecordsToLogPair(exampleLogWithComplexBody()),
},
}

Expand All @@ -475,7 +544,7 @@ func TestSendLogsJsonConfig(t *testing.T) {
}, tc.configOpts...)

test.s.config.LogFormat = JSONFormat
test.s.logBuffer = logRecordsToLogPair(exampleTwoLogs())
test.s.logBuffer = tc.logBuffer

_, err := test.s.sendLogs(context.Background(), newFields(pdata.NewAttributeMap()))
assert.NoError(t, err)
Expand Down

0 comments on commit 29e52d9

Please sign in to comment.