Skip to content

Commit 3a47497

Browse files
authored
feat: colorize log levels (#10)
1 parent 72dded3 commit 3a47497

File tree

11 files changed

+274
-31
lines changed

11 files changed

+274
-31
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Main features:
1616
4. All non-json logs are captured.
1717
5. It understands different field names: `time`, `timestamp`, `msg`, `message`, `err`, `error` etc.
1818
6. It supports case-insensitive filtering.
19-
7. It is simple.
19+
7. Colorized log levels.
2020

2121
It uses [antonmedv/fx](https://github.com/antonmedv/fx) for viewing JSON records and [charmbracelet/bubbletea](https://github.com/charmbracelet/bubbletea) for organizing the terminal UI. The tool is inspired by the project [json-log-viewer](https://github.com/gistia/json-log-viewer) which is unfortunately outdated and deserted.
2222

assets/example.log

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@
3535
{"time":"1970-01-01T00:00:00.00","level":"INFO","message": "Never mistake activity for achievement.","author": "John Wooden"}
3636
{"time":"1970-01-01T00:00:00.00","level":"INFO","message": "What worries you masters you.","author": "Haddon Robinson"}
3737
{"time":"1970-01-01T00:00:00.00","level":"INFO","message": "One faces the future with ones past.","author": "Pearl Buck"}
38-
{"time":"1970-01-01T00:00:00.00","level":"INFO","message": "Goals are the fuel in the furnace of achievement.","author": "Brian Tracy"}
39-
{"time":"1970-01-01T00:00:00.00","level":"INFO","message": "Who sows virtue reaps honour.","author": "Leonardo da Vinci"}
38+
{"time":"1970-01-01T00:00:00.00","level":"VERBOSE","message": "Goals are the fuel in the furnace of achievement.","author": "Brian Tracy"}
4039
{"time":"1970-01-01T00:00:00.00","level":"FATAL","message": "Be the chief but never the lord.","author": "Lao Tzu"}
4140
{"time":"1970-01-01T00:00:00.00","level":"PANIC","message": "Fate is in your hands and no one elses","author": "Byron Pulsifer"}
4241
{"time":"1970-01-01T00:00:00.00","level":"ERROR","message": "Genius is one percent inspiration and ninety-nine percent perspiration.","author": "Thomas Edison"}
42+
{"time":"1970-01-01T00:00:00.00","level":"WARN","message": "Who sows virtue reaps honour.","author": "Leonardo da Vinci"}
4343
{"time":"1970-01-01T00:00:00.00","level":"INFO","message": "You can observe a lot just by watching.","author": "Yogi Berra"}
4444
{"time":"1970-01-01T00:00:00.00","level":"DEBUG","message": "A house divided against itself cannot stand.","author": "Abraham Lincoln"}
4545
{"time":"1970-01-01T00:00:00.00","level":"TRACE","message": "Difficulties increase the nearer we get to the goal.","author": "Johann Wolfgang von Goethe"}

go.mod

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ go 1.20
44

55
replace github.com/antonmedv/fx => github.com/hedhyw/fx v0.0.1
66

7+
replace github.com/charmbracelet/bubbles => github.com/hedhyw/bubbles v0.0.2
8+
79
require (
810
github.com/antonmedv/fx v0.0.0-20230706101337-4fec4e492a52
911
github.com/charmbracelet/bubbles v0.16.1
@@ -19,20 +21,22 @@ require (
1921
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
2022
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
2123
github.com/davecgh/go-spew v1.1.1 // indirect
24+
github.com/kr/pretty v0.3.0 // indirect
2225
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
23-
github.com/mattn/go-isatty v0.0.18 // indirect
26+
github.com/mattn/go-isatty v0.0.19 // indirect
2427
github.com/mattn/go-localereader v0.0.1 // indirect
2528
github.com/mattn/go-runewidth v0.0.14 // indirect
2629
github.com/mazznoer/colorgrad v0.9.1 // indirect
2730
github.com/mazznoer/csscolorparser v0.1.3 // indirect
2831
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
2932
github.com/muesli/cancelreader v0.2.2 // indirect
30-
github.com/muesli/termenv v0.15.1 // indirect
33+
github.com/muesli/termenv v0.15.2 // indirect
3134
github.com/pmezard/go-difflib v1.0.0 // indirect
3235
github.com/rivo/uniseg v0.4.4 // indirect
33-
golang.org/x/sync v0.1.0 // indirect
34-
golang.org/x/sys v0.7.0 // indirect
35-
golang.org/x/term v0.7.0 // indirect
36-
golang.org/x/text v0.9.0 // indirect
36+
golang.org/x/sync v0.3.0 // indirect
37+
golang.org/x/sys v0.10.0 // indirect
38+
golang.org/x/term v0.10.0 // indirect
39+
golang.org/x/text v0.11.0 // indirect
40+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
3741
gopkg.in/yaml.v3 v3.0.1 // indirect
3842
)

go.sum

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,31 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z
22
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
33
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
44
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
5-
github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY=
6-
github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc=
75
github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY=
86
github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
97
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
108
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
119
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
1210
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
11+
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
1312
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1413
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
14+
github.com/hedhyw/bubbles v0.0.2 h1:OqPNGSunmk2B8wE4RcZ4oQvhWkCZNYt8EY8UXuuXJuw=
15+
github.com/hedhyw/bubbles v0.0.2/go.mod h1:XUdibuVUiMfcfKTRla58bmY3TWsdjgF+Rp8pvimQLck=
1516
github.com/hedhyw/fx v0.0.1 h1:h1jJaDnJ6qewSKiD7yooAGZjQwS+yazFcoRgtWV0Rq8=
1617
github.com/hedhyw/fx v0.0.1/go.mod h1:mT/W/Ln5xzLNEh+wGWAsPITPpQV5w6ne7klykEUS78w=
18+
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
19+
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
20+
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
21+
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
22+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
23+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
24+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
25+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
1726
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
1827
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
19-
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
20-
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
28+
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
29+
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
2130
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
2231
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
2332
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
@@ -34,29 +43,34 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU
3443
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
3544
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
3645
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
37-
github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs=
38-
github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ=
46+
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
47+
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
3948
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4049
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
4150
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
4251
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
4352
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
4453
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
54+
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
55+
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
4556
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
4657
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
4758
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
4859
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
49-
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
50-
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
60+
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
61+
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
5162
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
5263
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
53-
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
54-
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
55-
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
56-
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
57-
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
58-
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
59-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
64+
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
65+
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
66+
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
67+
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
68+
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
69+
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
6070
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
71+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
72+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
73+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
74+
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
6175
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
6276
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/app/handler.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"github.com/hedhyw/json-log-viewer/internal/pkg/source"
77
)
88

9+
const cellIDLogLevel = 1
10+
911
func (m Model) handleKeyMsg(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
1012
switch msg.String() {
1113
case "esc":
@@ -44,12 +46,26 @@ func (m Model) handleWindowSizeMsg(msg tea.WindowSizeMsg) Model {
4446
}
4547

4648
func (m Model) handleLogEntriesMsg(msg source.LogEntries) Model {
47-
m.table.SetRows(msg.Rows())
48-
4949
if len(m.allLogEntries) == 0 {
5050
m.allLogEntries = msg
51+
52+
tableStyles := getTableStyles()
53+
tableStyles.RenderCell = func(value string, rowID, columnID int) string {
54+
style := tableStyles.Cell
55+
56+
if columnID == cellIDLogLevel {
57+
return removeClearSequence(
58+
m.getLogLevelStyle(style, rowID).Render(value),
59+
)
60+
}
61+
62+
return style.Render(value)
63+
}
64+
65+
m.table.SetStyles(tableStyles)
5166
}
5267

68+
m.table.SetRows(msg.Rows())
5369
m.filteredLogEntries = msg
5470

5571
return m

internal/app/helper.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package app
22

3-
import "github.com/charmbracelet/bubbles/table"
3+
import (
4+
"strings"
5+
6+
"github.com/charmbracelet/bubbles/table"
7+
)
48

59
func getColumns(width int) []table.Column {
610
const (
@@ -14,3 +18,8 @@ func getColumns(width int) []table.Column {
1418
{Title: "Message", Width: width - widthTime - widthLevel},
1519
}
1620
}
21+
22+
func removeClearSequence(value string) string {
23+
// https://github.com/charmbracelet/lipgloss/issues/144
24+
return strings.ReplaceAll(value, "\x1b[0", "\x1b[39")
25+
}

internal/app/style.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ package app
33
import (
44
"github.com/charmbracelet/bubbles/table"
55
"github.com/charmbracelet/lipgloss"
6+
7+
"github.com/hedhyw/json-log-viewer/internal/pkg/source"
8+
)
9+
10+
// Possible colors.
11+
const (
12+
colorMagenta lipgloss.Color = "13"
13+
colorYellow lipgloss.Color = "11"
14+
colorGreen lipgloss.Color = "10"
15+
colorOrange lipgloss.Color = "214"
16+
colorRed lipgloss.Color = "9"
617
)
718

819
func getTableStyles() table.Styles {
@@ -29,3 +40,35 @@ func getBaseStyle() lipgloss.Style {
2940
func getFooterStyle() lipgloss.Style {
3041
return lipgloss.NewStyle().Height(footerSize).PaddingLeft(2)
3142
}
43+
44+
func (m Model) getLogLevelStyle(baseStyle lipgloss.Style, rowID int) lipgloss.Style {
45+
if rowID < 0 || rowID >= len(m.filteredLogEntries) {
46+
return baseStyle
47+
}
48+
49+
color := getColorForLogLevel(m.filteredLogEntries[rowID].Level)
50+
if color == "" {
51+
return baseStyle
52+
}
53+
54+
return baseStyle.Copy().Foreground(color)
55+
}
56+
57+
func getColorForLogLevel(level source.Level) lipgloss.Color {
58+
switch level {
59+
case source.LevelTrace:
60+
return colorMagenta
61+
case source.LevelDebug:
62+
return colorYellow
63+
case source.LevelInfo:
64+
return colorGreen
65+
case source.LevelWarning:
66+
return colorOrange
67+
case source.LevelError,
68+
source.LevelFatal,
69+
source.LevelPanic:
70+
return colorRed
71+
default:
72+
return ""
73+
}
74+
}

internal/app/style_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package app
2+
3+
import (
4+
"testing"
5+
6+
"github.com/charmbracelet/lipgloss"
7+
"github.com/stretchr/testify/assert"
8+
9+
"github.com/hedhyw/json-log-viewer/internal/pkg/source"
10+
)
11+
12+
func TestGetColorForLogLevel(t *testing.T) {
13+
t.Parallel()
14+
15+
testCases := [...]struct {
16+
Level source.Level
17+
Expected lipgloss.Color
18+
}{{
19+
Level: source.Level(""),
20+
Expected: "",
21+
}, {
22+
Level: source.LevelUnknown,
23+
Expected: "",
24+
}, {
25+
Level: source.Level("custom"),
26+
Expected: "",
27+
}, {
28+
Level: source.LevelTrace,
29+
Expected: colorMagenta,
30+
}, {
31+
Level: source.LevelDebug,
32+
Expected: colorYellow,
33+
}, {
34+
Level: source.LevelInfo,
35+
Expected: colorGreen,
36+
}, {
37+
Level: source.LevelWarning,
38+
Expected: colorOrange,
39+
}, {
40+
Level: source.LevelError,
41+
Expected: colorRed,
42+
}, {
43+
Level: source.LevelFatal,
44+
Expected: colorRed,
45+
}, {
46+
Level: source.LevelPanic,
47+
Expected: colorRed,
48+
}}
49+
50+
for _, testCase := range testCases {
51+
testCase := testCase
52+
53+
t.Run(testCase.Level.String(), func(t *testing.T) {
54+
t.Parallel()
55+
56+
actual := getColorForLogLevel(testCase.Level)
57+
assert.Equal(t, testCase.Expected, actual)
58+
})
59+
}
60+
}

internal/pkg/source/helper.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,8 @@ func extractTime(value *fastjson.Value) string {
1818

1919
func extractLevel(value *fastjson.Value) Level {
2020
level := extractValue(value, "level", "lvl")
21-
if level != "" {
22-
return Level(strings.TrimSpace(strings.ToLower(level)))
23-
}
2421

25-
return LevelUnknown
22+
return ParseLevel(level)
2623
}
2724

2825
func extractValue(value *fastjson.Value, keys ...string) string {

internal/pkg/source/level.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,34 @@ import "strings"
55
// Level of the logs entity.
66
type Level string
77

8+
// ParseLevel parses level from the text value.
9+
func ParseLevel(value string) Level {
10+
value = strings.ToLower(value)
11+
value = strings.TrimSpace(value)
12+
13+
switch {
14+
case value == "":
15+
return LevelUnknown
16+
case strings.HasPrefix(value, "t"),
17+
strings.HasPrefix(value, "v"): // Verbose.
18+
return LevelTrace
19+
case strings.HasPrefix(value, "d"):
20+
return LevelDebug
21+
case strings.HasPrefix(value, "e"):
22+
return LevelError
23+
case strings.HasPrefix(value, "i"):
24+
return LevelInfo
25+
case strings.HasPrefix(value, "w"):
26+
return LevelWarning
27+
case strings.HasPrefix(value, "f"):
28+
return LevelFatal
29+
case strings.HasPrefix(value, "p"):
30+
return LevelPanic
31+
default:
32+
return Level(value)
33+
}
34+
}
35+
836
// String implement fmt.Stringer interface.
937
func (l Level) String() string {
1038
return strings.ToLower(string(l))
@@ -13,4 +41,11 @@ func (l Level) String() string {
1341
// Possible log levels.
1442
const (
1543
LevelUnknown Level = "none"
44+
LevelTrace Level = "trace"
45+
LevelDebug Level = "debug"
46+
LevelInfo Level = "info"
47+
LevelWarning Level = "warn"
48+
LevelError Level = "error"
49+
LevelPanic Level = "panic"
50+
LevelFatal Level = "fatal"
1651
)

0 commit comments

Comments
 (0)