Skip to content

Commit f075815

Browse files
authored
feat: support default reverse mode in the config (#134)
1 parent a007fc7 commit f075815

File tree

6 files changed

+98
-14
lines changed

6 files changed

+98
-14
lines changed

example.jlv.jsonc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
// AM/PM mark: "PM"
3434
//
3535
// More details: https://go.dev/src/time/format.go.
36-
"time_format": "2006-01-02T15:04:05Z07:00"
36+
"timeFormat": "2006-01-02T15:04:05Z07:00"
3737
},
3838
{
3939
"title": "Level",
@@ -65,13 +65,15 @@
6565
"width": 0
6666
}
6767
],
68+
// Show logs in reverse order by default.
69+
"isReverseDefault": true,
6870
// Time layouts to reformat.
6971
//
7072
// If the time field has been parsed to any of the specified layouts,
71-
// it will be formatted according to "time_format" configuration.
73+
// it will be formatted according to "timeFormat" configuration.
7274
//
7375
// See: https://pkg.go.dev/time#pkg-constants.
74-
"time_layouts": [
76+
"timeLayouts": [
7577
"01/02 03:04:05PM '06 -0700",
7678
"Mon Jan _2 15:04:05 2006",
7779
"Mon Jan _2 15:04:05 MST 2006",

internal/app/app_test.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,26 @@ import (
1919

2020
const testVersion = "v0.0.1"
2121

22-
func newTestModel(tb testing.TB, content []byte) tea.Model {
22+
type configSetter func(*config.Config)
23+
24+
func newTestModel(
25+
tb testing.TB,
26+
content []byte,
27+
configSetters ...configSetter,
28+
) tea.Model {
2329
tb.Helper()
2430

2531
testFile := tests.RequireCreateFile(tb, content)
2632

27-
inputSource, err := source.File(testFile, config.GetDefaultConfig())
33+
cfg := config.GetDefaultConfig()
34+
35+
for _, set := range configSetters {
36+
set(cfg)
37+
}
38+
39+
inputSource, err := source.File(testFile, cfg)
2840
require.NoError(tb, err)
29-
model := app.NewModel(testFile, config.GetDefaultConfig(), testVersion)
41+
model := app.NewModel(testFile, cfg, testVersion)
3042

3143
entries, err := inputSource.ParseLogEntries()
3244
require.NoError(tb, err)

internal/app/stateloaded.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ func newStateViewLogs(
2626
table := newLogsTableModel(
2727
application,
2828
logEntries,
29-
true, // follow.
30-
true, // reverse.
29+
true, // follow.
30+
application.Config.IsReverseDefault, // reverse.
3131
)
3232

3333
return StateLoadedModel{

internal/app/stateloaded_test.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ func TestStateLoadedEmpty(t *testing.T) {
3232
func TestStateLoaded(t *testing.T) {
3333
t.Parallel()
3434

35-
setup := func() tea.Model {
35+
setup := func(configSetters ...configSetter) tea.Model {
3636
const jsonFile = `{"time":"1970-01-01T00:00:00.00","level":"INFO","message": "test"}`
3737

38-
model := newTestModel(t, []byte(jsonFile))
38+
model := newTestModel(t, []byte(jsonFile), configSetters...)
3939

4040
_, ok := model.(app.StateLoadedModel)
4141
require.Truef(t, ok, "%s", model)
@@ -111,6 +111,17 @@ func TestStateLoaded(t *testing.T) {
111111
assert.Contains(t, view, "reverse")
112112
})
113113

114+
t.Run("label_reverse_disabled_in_config", func(t *testing.T) {
115+
t.Parallel()
116+
117+
model := setup(func(cfg *config.Config) {
118+
cfg.IsReverseDefault = false
119+
})
120+
121+
view := model.View()
122+
assert.NotContains(t, view, "reverse")
123+
})
124+
114125
t.Run("label_not_reverse", func(t *testing.T) {
115126
t.Parallel()
116127

internal/pkg/config/config.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@ type Config struct {
2525
Path string `json:"-"`
2626

2727
Fields []Field `json:"fields" validate:"min=1"`
28+
29+
TimeLayoutsDeprecated []string `json:"time_layouts,omitempty"`
2830
// TimeLayouts to reformat.
29-
TimeLayouts []string `json:"time_layouts"`
31+
TimeLayouts []string `json:"timeLayouts"`
32+
33+
IsReverseDefault bool `json:"isReverseDefault"`
3034

3135
CustomLevelMapping map[string]string `json:"customLevelMapping"`
3236

@@ -55,7 +59,9 @@ type Field struct {
5559
Kind FieldKind `json:"kind" validate:"required,oneof=time message numerictime secondtime millitime microtime level any"`
5660
References []string `json:"ref" validate:"min=1,dive,required"`
5761
Width int `json:"width" validate:"min=0"`
58-
TimeFormat *string `json:"time_format,omitempty"`
62+
63+
TimeFormatDeprecated *string `json:"time_format,omitempty"`
64+
TimeFormat *string `json:"timeFormat,omitempty"`
5965
}
6066

6167
// GetDefaultConfig returns the configuration with default values.
@@ -102,6 +108,7 @@ func GetDefaultConfig() *Config {
102108
Kind: FieldKindMessage,
103109
References: []string{"$.message", "$.msg", "$.error", "$.err"},
104110
}},
111+
IsReverseDefault: true,
105112
}
106113
}
107114

@@ -165,6 +172,18 @@ func readConfigFromFile(path string) (cfg *Config, err error) {
165172

166173
cfg.Path = path
167174

175+
if len(cfg.TimeLayoutsDeprecated) != 0 {
176+
cfg.TimeLayouts = cfg.TimeLayoutsDeprecated
177+
}
178+
179+
for i, f := range cfg.Fields {
180+
if f.TimeFormatDeprecated != nil && *f.TimeFormatDeprecated != "" {
181+
f.TimeFormat = f.TimeFormatDeprecated
182+
}
183+
184+
cfg.Fields[i] = f
185+
}
186+
168187
return cfg, nil
169188
}
170189

internal/pkg/config/config_test.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func ExampleGetDefaultConfig() {
114114
// "$[\"@timestamp\"]"
115115
// ],
116116
// "width": 30,
117-
// "time_format": "2006-01-02T15:04:05Z07:00"
117+
// "timeFormat": "2006-01-02T15:04:05Z07:00"
118118
// },
119119
// {
120120
// "title": "Level",
@@ -138,7 +138,7 @@ func ExampleGetDefaultConfig() {
138138
// "width": 0
139139
// }
140140
// ],
141-
// "time_layouts": [
141+
// "timeLayouts": [
142142
// "01/02 03:04:05PM '06 -0700",
143143
// "Mon Jan _2 15:04:05 2006",
144144
// "Mon Jan _2 15:04:05 MST 2006",
@@ -157,6 +157,7 @@ func ExampleGetDefaultConfig() {
157157
// "2006-01-02 15:04:05",
158158
// "2006-01-02"
159159
// ],
160+
// "isReverseDefault": true,
160161
// "customLevelMapping": {
161162
// "10": "trace",
162163
// "20": "debug",
@@ -395,3 +396,42 @@ func TestByteSizeParseFailed(t *testing.T) {
395396
require.Error(t, err)
396397
})
397398
}
399+
400+
func TestReadTimeLayoutsDeprecated(t *testing.T) {
401+
t.Parallel()
402+
403+
cfg := config.GetDefaultConfig()
404+
cfg.TimeLayoutsDeprecated = []string{time.Layout}
405+
cfg.TimeLayouts = nil
406+
407+
configJSON := tests.RequireEncodeJSON(t, cfg)
408+
fileFirst := tests.RequireCreateFile(t, configJSON)
409+
410+
actual, err := config.Read(fileFirst)
411+
if assert.NoError(t, err) {
412+
assert.ElementsMatch(t, actual.TimeLayouts, cfg.TimeLayoutsDeprecated)
413+
}
414+
}
415+
416+
func TestReadTimeFormatDeprecated(t *testing.T) {
417+
t.Parallel()
418+
419+
timeFormat := time.Layout
420+
421+
cfg := config.GetDefaultConfig()
422+
cfg.Fields = []config.Field{{
423+
Title: "Time",
424+
Kind: config.FieldKindNumericTime,
425+
References: []string{"$.timestamp", "$.time", "$.t", "$.ts", "$[\"@timestamp\"]"},
426+
Width: 30,
427+
TimeFormatDeprecated: &timeFormat,
428+
}}
429+
430+
configJSON := tests.RequireEncodeJSON(t, cfg)
431+
fileFirst := tests.RequireCreateFile(t, configJSON)
432+
433+
actual, err := config.Read(fileFirst)
434+
if assert.NoError(t, err) {
435+
assert.Equal(t, timeFormat, *actual.Fields[0].TimeFormat)
436+
}
437+
}

0 commit comments

Comments
 (0)