Skip to content

Commit 3f0249a

Browse files
committed
feat: allow customization of the logger
Added two new global command line flags to the pyrra binary. ``` --log-level="info" Used to set the logging level of the application. Valid options are 'debug', 'info', 'warn' or 'error' --log-format="logfmt" Used to set the logging format. Valid options are 'logfmt' or 'json' ``` We also validate these options with the level.Parse function from go-kit itself and some custom validation about the two options for logging formats. fixes #769
1 parent f80661b commit 3f0249a

File tree

3 files changed

+110
-3
lines changed

3 files changed

+110
-3
lines changed

logger.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
8+
"github.com/go-kit/log"
9+
"github.com/go-kit/log/level"
10+
)
11+
12+
var errInvalidLogFormatFlag = errors.New("--log-format must be either 'json' or 'logfmt'")
13+
14+
type LoggerConfig struct {
15+
LogLevel string `default:"info" help:"Used to set the logging level of the application. Valid options are 'debug', 'info', 'warn' or 'error'"`
16+
LogFormat string `default:"logfmt" help:"Used to set the logging format. Valid options are 'logfmt' or 'json'"`
17+
}
18+
19+
// Validate is a method called automatically by the kong cli framework so this deals with validating our LoggerConfig struct.
20+
func (lc *LoggerConfig) Validate() error {
21+
if _, err := level.Parse(lc.LogLevel); err != nil {
22+
return fmt.Errorf("%w: must be 'debug', 'info', 'warn' or 'error'", err)
23+
}
24+
25+
if lc.LogFormat != "json" && lc.LogFormat != "logfmt" {
26+
return errInvalidLogFormatFlag
27+
}
28+
return nil
29+
}
30+
31+
// configureLogger returns a go-lit logger which is customizable via the loggerConfig struct.
32+
func configureLogger(loggerConfig LoggerConfig) log.Logger {
33+
var logger log.Logger
34+
switch loggerConfig.LogFormat {
35+
case "logfmt":
36+
logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
37+
case "json":
38+
logger = log.NewJSONLogger(log.NewSyncWriter(os.Stderr))
39+
}
40+
41+
logger = level.NewFilter(logger, level.Allow(level.ParseDefault(loggerConfig.LogLevel, level.InfoValue())))
42+
logger = log.WithPrefix(logger, "caller", log.DefaultCaller)
43+
logger = log.WithPrefix(logger, "ts", log.DefaultTimestampUTC)
44+
return logger
45+
}

logger_test.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/go-kit/log/level"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestLoggerConfig_Validate(t *testing.T) {
11+
type fields struct {
12+
LogLevel string
13+
LogFormat string
14+
}
15+
tests := []struct {
16+
name string
17+
fields fields
18+
wantFunc func(t *testing.T, err error)
19+
}{
20+
{
21+
name: "bad log level",
22+
fields: fields{
23+
LogLevel: "notALogLevel",
24+
LogFormat: "logfmt",
25+
},
26+
wantFunc: func(t *testing.T, err error) {
27+
require.ErrorIs(t, err, level.ErrInvalidLevelString, "log level should be invalid")
28+
},
29+
},
30+
{
31+
name: "bad log format",
32+
fields: fields{
33+
LogLevel: "debug",
34+
LogFormat: "notALogFormat",
35+
},
36+
wantFunc: func(t *testing.T, err error) {
37+
require.ErrorIs(t, err, errInvalidLogFormatFlag, "log format flag should be invalid")
38+
},
39+
},
40+
{
41+
name: "good config",
42+
fields: fields{
43+
LogLevel: "debug",
44+
LogFormat: "json",
45+
},
46+
wantFunc: func(t *testing.T, err error) {
47+
require.NoError(t, err)
48+
},
49+
},
50+
}
51+
for _, tt := range tests {
52+
tt := tt
53+
t.Run(tt.name, func(t *testing.T) {
54+
t.Parallel()
55+
lc := &LoggerConfig{
56+
LogLevel: tt.fields.LogLevel,
57+
LogFormat: tt.fields.LogFormat,
58+
}
59+
err := lc.Validate()
60+
tt.wantFunc(t, err)
61+
})
62+
}
63+
}

main.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import (
5050
var ui embed.FS
5151

5252
var CLI struct {
53+
LoggerConfig
5354
API struct {
5455
PrometheusURL *url.URL `default:"http://localhost:9090" help:"The URL to the Prometheus to query."`
5556
PrometheusExternalURL *url.URL `help:"The URL for the UI to redirect users to when opening Prometheus. If empty the same as prometheus.url"`
@@ -82,9 +83,7 @@ var CLI struct {
8283
func main() {
8384
ctx := kong.Parse(&CLI)
8485

85-
logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
86-
logger = log.WithPrefix(logger, "caller", log.DefaultCaller)
87-
logger = log.WithPrefix(logger, "ts", log.DefaultTimestampUTC)
86+
logger := configureLogger(CLI.LoggerConfig)
8887

8988
reg := prometheus.NewRegistry()
9089
reg.MustRegister(

0 commit comments

Comments
 (0)