Skip to content
Snippets Groups Projects
Commit 4bb09063 authored by Jack Robertson's avatar Jack Robertson
Browse files

refactor: move slog package to root, add configuration options and tests

parent 5d7a7776
No related branches found
No related tags found
1 merge request!1Refactor library to idiomatic go
package slog
import (
"golang.org/x/exp/slog"
"io"
)
type Options struct {
Leveler slog.Leveler
Writer io.Writer
}
type Option func(*Options)
func WithLeveler(leveler slog.Leveler) Option {
return func(o *Options) {
o.Leveler = leveler
}
}
func WithWriter(writer io.Writer) Option {
return func(o *Options) {
o.Writer = writer
}
}
...@@ -6,36 +6,46 @@ import ( ...@@ -6,36 +6,46 @@ import (
"strings" "strings"
) )
func InitLogger() *slog.Logger { func New(opts ...Option) *slog.Logger {
// Could set logger level via ENV vars in future. options := &Options{
programLevel := new(slog.LevelVar) Leveler: slog.LevelDebug,
programLevel.Set(slog.LevelDebug) Writer: os.Stdout,
}
for _, opt := range opts {
opt(options)
}
// Attributes modified for datadog schema via HandlerOptions.ReplaceAttr // Attributes modified for datadog schema via HandlerOptions.ReplaceAttr
// Per recommendation at https://pkg.go.dev/golang.org/x/exp/slog#JSONHandler // Per recommendation at https://pkg.go.dev/golang.org/x/exp/slog#JSONHandler
// See datadog: https://docs.datadoghq.com/logs/log_configuration/attributes_naming_convention/#reserved-attributes // See datadog: https://docs.datadoghq.com/logs/log_configuration/attributes_naming_convention/#reserved-attributes
loggerReplace := func(groups []string, a slog.Attr) slog.Attr { replaceAttr := func(groups []string, attr slog.Attr) slog.Attr {
if a.Key == "msg" { if attr.Key == "msg" {
a.Key = "message" attr.Key = "message"
} }
if a.Key == "time" { if attr.Key == "time" {
a.Key = "date" attr.Key = "date"
} }
if a.Key == "level" { if attr.Key == "level" {
a.Key = "status" attr.Key = "status"
a.Value = slog.StringValue(strings.ToLower(a.Value.String())) attr.Value = slog.StringValue(strings.ToLower(attr.Value.String()))
} }
return a return attr
} }
logger := slog.New(slog.NewJSONHandler(os.Stdout,
&slog.HandlerOptions{Level: programLevel, AddSource: true, ReplaceAttr: loggerReplace})) handlerOptions := &slog.HandlerOptions{
hostname, hostnameErr := os.Hostname() Level: options.Leveler,
if hostnameErr == nil { AddSource: true,
logger = logger.With("host", hostname) ReplaceAttr: replaceAttr,
}
logHandler := slog.NewJSONHandler(options.Writer, handlerOptions)
logger := slog.New(logHandler)
hostname, err := os.Hostname()
if err != nil {
logger.Error("Failed to get hostname.", slog.String("error", err.Error()))
} else { } else {
logger.Error("Failed to get hostname.", slog.String("error", hostnameErr.Error())) logger = logger.With("host", hostname)
} }
logger.Info("Initialised.")
return logger return logger
} }
package slog
import (
"bufio"
"bytes"
"encoding/json"
"golang.org/x/exp/slog"
"testing"
)
func TestNew(t *testing.T) {
var buf bytes.Buffer
logger := New(WithWriter(&buf))
logger.Info("Foo", slog.String("bar", "baz"))
logger.Error("Bar", slog.String("baz", "qux"))
scanner := bufio.NewScanner(&buf)
// Scan the first log.
scanner.Scan()
infoLog := scanner.Bytes()
var infoLogMap map[string]any
if err := json.Unmarshal(infoLog, &infoLogMap); err != nil {
t.Errorf("Failed to unmarshal info log: %s", err.Error())
}
t.Log(infoLogMap)
if infoLogMap["status"] != "info" {
t.Errorf("Expected info log level, got %s", infoLogMap["level"])
}
if infoLogMap["bar"] != "baz" {
t.Errorf("Expected bar=baz, got %s", infoLogMap["bar"])
}
}
package main
import (
"gitlab.nexdev.uk/pub/go-slog/src/slog"
)
func main() {
logger := slog.InitLogger()
logger.Info("Logger test.")
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment