From 2894e66be7ff7536f725ede453d1834586a361bd Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Tue, 22 Nov 2022 18:51:03 +0000 Subject: [PATCH] fix(logging): fix stdout log http request format (#7083) --- logging/logging.go | 35 +++++++++++++++++++++++++++++++++++ logging/logging_test.go | 19 +++++++++++-------- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/logging/logging.go b/logging/logging.go index f889ddae643f..7b7176ae103a 100644 --- a/logging/logging.go +++ b/logging/logging.go @@ -920,6 +920,41 @@ type structuredLogEntry struct { TraceSampled bool `json:"logging.googleapis.com/trace_sampled,omitempty"` } +func convertSnakeToMixedCase(snakeStr string) string { + words := strings.Split(snakeStr, "_") + mixedStr := words[0] + for _, word := range words[1:] { + mixedStr += strings.Title(word) + } + return mixedStr +} + +func (s structuredLogEntry) MarshalJSON() ([]byte, error) { + // extract structuredLogEntry into json map + type Alias structuredLogEntry + var mapData map[string]interface{} + data, err := json.Marshal(Alias(s)) + if err == nil { + err = json.Unmarshal(data, &mapData) + } + if err == nil { + // ensure all inner dicts use mixed case instead of snake case + innerDicts := [3]string{"httpRequest", "logging.googleapis.com/operation", "logging.googleapis.com/sourceLocation"} + for _, field := range innerDicts { + if fieldData, ok := mapData[field]; ok { + formattedFieldData := make(map[string]interface{}) + for k, v := range fieldData.(map[string]interface{}) { + formattedFieldData[convertSnakeToMixedCase(k)] = v + } + mapData[field] = formattedFieldData + } + } + // serialize json map into raw bytes + return json.Marshal(mapData) + } + return data, err +} + func serializeEntryToWriter(entry *logpb.LogEntry, w io.Writer) error { jsonifiedEntry := structuredLogEntry{ Severity: entry.Severity.String(), diff --git a/logging/logging_test.go b/logging/logging_test.go index bd01c3b54331..4dbf2148d60e 100644 --- a/logging/logging_test.go +++ b/logging/logging_test.go @@ -1281,12 +1281,14 @@ func TestRedirectOutputFormats(t *testing.T) { Method: "POST", }, }, + Payload: "this is text payload", }, - want: `{"message":"this is text payload","severity":"DEBUG","httpRequest":{"request_method":"POST","request_url":"https://example.com/test"},` + - `"timestamp":"seconds:1000","logging.googleapis.com/labels":{"key1":"value1","key2":"value2"},"logging.googleapis.com/insertId":"0000AAA01",` + - `"logging.googleapis.com/operation":{"id":"0123456789","producer":"test"},"logging.googleapis.com/sourceLocation":{"file":"acme.go","line":100,"function":"main"},` + - `"logging.googleapis.com/spanId":"000000000001","logging.googleapis.com/trace":"projects/P/ABCD12345678AB12345678","logging.googleapis.com/trace_sampled":true}`, + want: `{"httpRequest":{"requestMethod":"POST","requestUrl":"https://example.com/test"},"logging.googleapis.com/insertId":"0000AAA01",` + + `"logging.googleapis.com/labels":{"key1":"value1","key2":"value2"},"logging.googleapis.com/operation":{"id":"0123456789","producer":"test"},` + + `"logging.googleapis.com/sourceLocation":{"file":"acme.go","function":"main","line":100},"logging.googleapis.com/spanId":"000000000001",` + + `"logging.googleapis.com/trace":"projects/P/ABCD12345678AB12345678","logging.googleapis.com/trace_sampled":true,` + + `"message":"this is text payload","severity":"DEBUG","timestamp":"seconds:1000"}`, }, { name: "full data redirect with json payload", @@ -1318,10 +1320,11 @@ func TestRedirectOutputFormats(t *testing.T) { "Latency": 321, }, }, - want: `{"message":{"Latency":321,"Message":"message part of the payload"},"severity":"DEBUG","httpRequest":{"request_method":"POST","request_url":"https://example.com/test"},` + - `"timestamp":"seconds:1000","logging.googleapis.com/labels":{"key1":"value1","key2":"value2"},"logging.googleapis.com/insertId":"0000AAA01",` + - `"logging.googleapis.com/operation":{"id":"0123456789","producer":"test"},"logging.googleapis.com/sourceLocation":{"file":"acme.go","line":100,"function":"main"},` + - `"logging.googleapis.com/spanId":"000000000001","logging.googleapis.com/trace":"projects/P/ABCD12345678AB12345678","logging.googleapis.com/trace_sampled":true}`, + want: `{"httpRequest":{"requestMethod":"POST","requestUrl":"https://example.com/test"},"logging.googleapis.com/insertId":"0000AAA01",` + + `"logging.googleapis.com/labels":{"key1":"value1","key2":"value2"},"logging.googleapis.com/operation":{"id":"0123456789","producer":"test"},` + + `"logging.googleapis.com/sourceLocation":{"file":"acme.go","function":"main","line":100},"logging.googleapis.com/spanId":"000000000001",` + + `"logging.googleapis.com/trace":"projects/P/ABCD12345678AB12345678","logging.googleapis.com/trace_sampled":true,` + + `"message":{"Latency":321,"Message":"message part of the payload"},"severity":"DEBUG","timestamp":"seconds:1000"}`, }, { name: "error on redirect with proto payload",