Skip to content

Commit fcdef6a

Browse files
committed
Parse ts and datetime fields as timestamps
1 parent 0a55a96 commit fcdef6a

File tree

4 files changed

+72
-16
lines changed

4 files changed

+72
-16
lines changed

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ require (
66
github.com/fatih/color v1.16.0
77
github.com/go-logfmt/logfmt v0.6.0
88
github.com/jessevdk/go-flags v1.5.0
9+
github.com/stretchr/testify v1.10.0
910
)
1011

1112
require (
13+
github.com/davecgh/go-spew v1.1.1 // indirect
1214
github.com/mattn/go-colorable v0.1.13 // indirect
1315
github.com/mattn/go-isatty v0.0.20 // indirect
16+
github.com/pmezard/go-difflib v1.0.0 // indirect
1417
golang.org/x/sys v0.14.0 // indirect
18+
gopkg.in/yaml.v3 v3.0.1 // indirect
1519
)

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
13
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
24
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
35
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
@@ -9,8 +11,16 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
911
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
1012
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
1113
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
14+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
15+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
16+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
17+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
1218
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1319
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1420
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1521
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
1622
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
23+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
24+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
25+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
26+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

parser/parser_test.go

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,61 @@
11
package parser_test
22

33
import (
4-
"os"
4+
"bytes"
5+
"strings"
56
"testing"
67

8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
711
"github.com/TheEdgeOfRage/logfmt/config"
812
"github.com/TheEdgeOfRage/logfmt/parser"
913
)
1014

11-
func TestParseInvalidFile(t *testing.T) {
12-
f, err := os.Open("../testdata/log.txt")
13-
if err != nil {
14-
t.Fatal(err)
15-
}
16-
p := parser.NewParser(&config.Config{}, f, os.Stdout)
17-
if err := p.Start(); err == nil {
18-
t.Error("expected error, got nil")
19-
}
15+
func TestParseLevels(t *testing.T) {
16+
data := strings.NewReader(`time="2025-03-15T10:32:23Z" level=debug msg="bar"
17+
time="2025-03-15T10:32:24Z" level=info msg="foo"
18+
time="2025-03-15T10:32:25Z" level=warn msg="oopsie"
19+
time="2025-03-15T10:32:26Z" level=error msg="oh no"
20+
time="2025-03-15T10:32:27Z" level=fatal msg="AAAAAA"`)
21+
w := &bytes.Buffer{}
22+
23+
p := parser.NewParser(&config.Config{}, data, w)
24+
err := p.Start()
25+
require.NoError(t, err)
26+
27+
assert.Equal(t, `2025-03-15 10:32:23 [DEBUG] msg=bar
28+
2025-03-15 10:32:24 [INFO] msg=foo
29+
2025-03-15 10:32:25 [WARN] msg=oopsie
30+
2025-03-15 10:32:26 [ERROR] msg="oh no"
31+
2025-03-15 10:32:27 [FATAL] msg=AAAAAA
32+
`, w.String())
33+
}
34+
35+
func TestParseTimestamps(t *testing.T) {
36+
data := strings.NewReader(`timestamp="2025-03-15T10:32:23Z" level=info
37+
time="2025-03-15T10:32:24Z" level=info
38+
ts="2025-03-15T10:32:25Z" level=info
39+
datetime="2025-03-15T10:32:26Z" level=info`)
40+
w := &bytes.Buffer{}
41+
42+
p := parser.NewParser(&config.Config{}, data, w)
43+
err := p.Start()
44+
require.NoError(t, err)
45+
46+
assert.Equal(t, `2025-03-15 10:32:23 [INFO]
47+
2025-03-15 10:32:24 [INFO]
48+
2025-03-15 10:32:25 [INFO]
49+
2025-03-15 10:32:26 [INFO]
50+
`, w.String())
51+
}
52+
53+
func TestParseInvalidLogs(t *testing.T) {
54+
data := strings.NewReader(`
55+
time="2025-03-15T10:32:23Z" level=info msg="loading"
56+
time="`)
57+
w := &bytes.Buffer{}
58+
p := parser.NewParser(&config.Config{}, data, w)
59+
err := p.Start()
60+
require.Error(t, err)
2061
}

parser/record.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import (
1313
)
1414

1515
var (
16-
levelStrings map[int]string
17-
levelColors map[int]*color.Color
16+
levelStrings map[int]string
17+
levelColors map[int]*color.Color
18+
timestampLabels = []string{"time", "timestamp", "datetime", "ts"}
1819
)
1920

2021
func init() {
@@ -58,7 +59,7 @@ func NewRecord(decoder *logfmt.Decoder) (*Record, error) {
5859
record.parseLevel(value)
5960
continue
6061
}
61-
if key == "time" || key == "timestamp" {
62+
if slices.Contains(timestampLabels, key) {
6263
err := record.parseTime(value)
6364
if err != nil {
6465
return nil, err
@@ -151,7 +152,7 @@ func (r *Record) String(cfg *config.Config) string {
151152
}
152153
value := r.fields[key]
153154
key = color.HiBlueString(key)
154-
line += fmt.Sprintf("%s=%s ", key, getFormattedValue(value))
155+
line += fmt.Sprintf(" %s=%s", key, getFormattedValue(value))
155156
}
156157

157158
var fmtString strings.Builder
@@ -160,9 +161,9 @@ func (r *Record) String(cfg *config.Config) string {
160161
}
161162

162163
if color.NoColor {
163-
fmtString.WriteString("%7s %s")
164+
fmtString.WriteString("%7s%s")
164165
} else {
165-
fmtString.WriteString("%26s %s")
166+
fmtString.WriteString("%26s%s")
166167
}
167168

168169
if cfg.NoTime {

0 commit comments

Comments
 (0)