Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions internal/scraper/scraper.go
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,10 @@ RECORD:

switch key := dec.Key(); string(key) {
case "ts":
if !t.IsZero() {
continue // already set by the 'time' field
}

var err error
t, err = time.Parse(time.RFC3339Nano, string(value))
if err != nil {
Expand All @@ -816,6 +820,15 @@ RECORD:
continue RECORD
}

// k6 sets a 'time' field on its logs using RFC3339; if present, report it instead of the default timestamp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be misunderstanding something here.

In principle, it's possible for the ts and time to show up in any order. I think L809 is trying to cover that and prefer the time field over the ts one. There's no test for that, though.

Question: why is it better to handle that here and not in the extension? Or is it the case that it was handled in the extension and that is no longer true?

case "time":
var err error
t, err = time.Parse(time.RFC3339, string(value))
if err != nil {
s.logger.Warn().Err(err).Bytes("value", value).Msg("invalid timestamp scanning logs")
continue RECORD
}

default:
if err := enc.EncodeKeyval(key, value); err != nil {
// We should never hit this because all the entries are valid.
Expand Down
56 changes: 56 additions & 0 deletions internal/scraper/scraper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2035,3 +2035,59 @@ func TestTickWithOffset(t *testing.T) {
})
}
}

func TestExtractLogsK6TimeOverridesDefaultTimestamp(t *testing.T) {
// Test that k6's "time" field overrides the default "ts" timestamp from the logger
testCases := []struct {
name string
logs string
sharedLabels []labelPair
expected func(t *testing.T, streams Streams)
}{
{
name: "k6 time field overrides default ts",
logs: `ts=2023-06-01T20:00:00Z time="2023-06-01T13:40:26-06:00" level=info msg="k6 message"`,
sharedLabels: []labelPair{
{name: "probe", value: "test-probe"},
},
expected: func(t *testing.T, streams Streams) {
require.Len(t, streams, 1)
require.Len(t, streams[0].Entries, 1)
entry := streams[0].Entries[0]

expectedTime, _ := time.Parse(time.RFC3339, "2023-06-01T13:40:26-06:00")
require.Equal(t, expectedTime, entry.Timestamp, "should use k6 time field, not default ts")
require.Equal(t, entry.Line, "level=info msg=\"k6 message\"\n")
},
},
{
name: "ts field only (no k6 time)",
logs: `ts=2023-06-01T20:00:00Z level=info msg="normal message"`,
sharedLabels: []labelPair{
{name: "probe", value: "test-probe"},
},
expected: func(t *testing.T, streams Streams) {
require.Len(t, streams, 1)
require.Len(t, streams[0].Entries, 1)
entry := streams[0].Entries[0]

expectedTime, _ := time.Parse(time.RFC3339Nano, "2023-06-01T20:00:00Z")
require.Equal(t, expectedTime, entry.Timestamp)
require.Equal(t, entry.Line, "level=info msg=\"normal message\"\n")
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

s := Scraper{
logger: testhelper.Logger(t),
}

streams := s.extractLogs(time.Now(), []byte(tc.logs), tc.sharedLabels)
tc.expected(t, streams)
})
}
}
Loading