Skip to content

Commit

Permalink
feat: add slog writer methods
Browse files Browse the repository at this point in the history
  • Loading branch information
danteay committed Apr 17, 2024
1 parent 865977a commit ec88cae
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 74 deletions.
21 changes: 6 additions & 15 deletions adapters/slog/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ package slog

import (
"io"
"log/slog"

"github.com/danteay/golog/levels"
)

type options struct {
level levels.Level
writer io.Writer
logger *slog.Logger
handler slog.Handler
level levels.Level
writer io.Writer
withTrace bool
}

// Option defines the signature for the options.
Expand All @@ -31,16 +29,9 @@ func WithWriter(writer io.Writer) Option {
}
}

// WithLogger sets the logger for the adapter.
func WithLogger(logger *slog.Logger) Option {
// WithTrace sets the error trace for the logger.
func WithTrace() Option {
return func(opts *options) {
opts.logger = logger
}
}

// WithHandler sets the handler for the logger. If a handler is set, the writer and level options will be ignored.
func WithHandler(handler slog.Handler) Option {
return func(opts *options) {
opts.handler = handler
opts.withTrace = true
}
}
24 changes: 0 additions & 24 deletions adapters/slog/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@ package slog

import (
"bytes"
"log/slog"
"os"
"testing"

"github.com/stretchr/testify/assert"

"github.com/danteay/golog/levels"
)

Expand All @@ -30,16 +26,6 @@ func TestWithWriter(t *testing.T) {
}
}

func TestWithLogger(t *testing.T) {
opts := &options{}

handler := slog.NewJSONHandler(os.Stdout, nil)

WithLogger(slog.New(handler))(opts)

assert.NotNil(t, opts.logger)
}

func TestOptionChaining(t *testing.T) {
opts := &options{}
WithLevel(levels.Error)(opts)
Expand All @@ -54,13 +40,3 @@ func TestOptionChaining(t *testing.T) {
t.Error("Expected writer to be the provided io.Writer, but it's not")
}
}

func TestWithHandler(t *testing.T) {
opts := &options{}

handler := slog.NewTextHandler(os.Stdout, nil)

WithHandler(handler)(opts)

assert.NotNil(t, opts.handler)
}
80 changes: 52 additions & 28 deletions adapters/slog/slog.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@ package slog

import (
"fmt"
"io"
"log/slog"
"os"

"github.com/danteay/golog/fields"
"github.com/danteay/golog/internal/errors"
"github.com/danteay/golog/levels"
)

// Adapter is an slog adapter implementation
// Adapter is a slog adapter implementation
type Adapter struct {
logger *slog.Logger
logger *slog.Logger
level levels.Level
writer io.Writer
withTrace bool
}

func New(opts ...Option) *Adapter {
Expand All @@ -24,15 +29,23 @@ func New(opts ...Option) *Adapter {
opt(&logOpts)
}

if logOpts.logger != nil {
return &Adapter{
logger: logOpts.logger,
}
adapter := &Adapter{
writer: logOpts.writer,
withTrace: logOpts.withTrace,
level: logOpts.level,
}

return &Adapter{
logger: getSlogInstance(logOpts),
}
adapter.logger = getSlogInstance(adapter.level, adapter.writer)

return adapter
}

func (a *Adapter) Writer() io.Writer {
return a.writer
}

func (a *Adapter) SetWriter(w io.Writer) {
a.writer = w
}

// Logger returns the slog logger instance
Expand All @@ -42,6 +55,10 @@ func (a *Adapter) Logger() *slog.Logger {

// Log logs a message with the given level, error, fields, and message
func (a *Adapter) Log(level levels.Level, err error, logFields *fields.Fields, msg string, args ...any) {
if level <= levels.Disabled {
return
}

lenFields := 0
if logFields != nil {
lenFields = logFields.Len()
Expand All @@ -55,13 +72,13 @@ func (a *Adapter) Log(level levels.Level, err error, logFields *fields.Fields, m
}
}

if err != nil {
lf = append(lf, slog.Any("error", err))
}
lf = getErrFields(level, err, lf, a.withTrace)

msg = fmt.Sprintf(msg, args...)

switch level {
case levels.TraceLevel:
a.logger.Debug(msg, lf...)
case levels.Debug:
a.logger.Debug(msg, lf...)
case levels.Info:
Expand All @@ -81,33 +98,40 @@ func (a *Adapter) Log(level levels.Level, err error, logFields *fields.Fields, m
}
}

func getSlogInstance(opts options) *slog.Logger {
if opts.logger != nil {
return opts.logger
func getErrFields(level levels.Level, err error, curFields []any, withTrace bool) []any {
if err == nil {
return curFields
}

curFields = append(curFields, slog.Any("error", err))

if level == levels.TraceLevel || withTrace {
curFields = append(curFields, slog.Any("stacktrace", errors.GetStackTrace()))
}

level := getLevels(opts.level)
return curFields
}

var handler slog.Handler = slog.NewJSONHandler(opts.writer, &slog.HandlerOptions{
func getSlogInstance(level levels.Level, writer io.Writer) *slog.Logger {
handler := slog.NewJSONHandler(writer, &slog.HandlerOptions{
AddSource: false,
Level: level,
Level: getLevels(level),
})

if opts.handler != nil {
handler = opts.handler
}

return slog.New(handler)
}

func getLevels(level levels.Level) slog.Level {
levelList := map[levels.Level]slog.Level{
levels.Debug: slog.LevelDebug,
levels.Info: slog.LevelInfo,
levels.Warn: slog.LevelWarn,
levels.Error: slog.LevelError,
levels.Fatal: slog.LevelError,
levels.Panic: slog.LevelError,
levels.NoLevel: slog.LevelInfo,
levels.Disabled: slog.LevelInfo,
levels.TraceLevel: slog.LevelDebug,
levels.Debug: slog.LevelDebug,
levels.Info: slog.LevelInfo,
levels.Warn: slog.LevelWarn,
levels.Error: slog.LevelError,
levels.Fatal: slog.LevelError,
levels.Panic: slog.LevelError,
}

sl, exists := levelList[level]
Expand Down
18 changes: 11 additions & 7 deletions adapters/slog/slog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import (
"strings"
"testing"

"github.com/stretchr/testify/assert"

"github.com/danteay/golog/fields"
"github.com/danteay/golog/levels"
"github.com/stretchr/testify/assert"
)

type testMsg struct {
Expand Down Expand Up @@ -139,12 +140,15 @@ func TestAdapter_Log(t *testing.T) {

func TestGetLevels(t *testing.T) {
tests := map[levels.Level]slog.Level{
levels.Debug: slog.LevelDebug,
levels.Info: slog.LevelInfo,
levels.Warn: slog.LevelWarn,
levels.Error: slog.LevelError,
levels.Fatal: slog.LevelError,
levels.Panic: slog.LevelError,
levels.NoLevel: slog.LevelInfo,
levels.Disabled: slog.LevelInfo,
levels.TraceLevel: slog.LevelDebug,
levels.Debug: slog.LevelDebug,
levels.Info: slog.LevelInfo,
levels.Warn: slog.LevelWarn,
levels.Error: slog.LevelError,
levels.Fatal: slog.LevelError,
levels.Panic: slog.LevelError,
}

for level, expected := range tests {
Expand Down

0 comments on commit ec88cae

Please sign in to comment.