Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ func main() {
lecho.WithTimestamp(), // Add timestamp to logs
lecho.WithCaller(), // Add caller information
lecho.WithPrefix("MyApp"), // Add a prefix to logs
lecho.WithDefaultPrintLevel(log.INFO), // Set default level for Echo's Print methods
// lecho.WithHook(myHook), // Add custom hooks
// lecho.WithHookFunc(myHookFunc), // Add hook functions
)
Expand All @@ -126,6 +127,47 @@ func main() {
- **`WithPrefix(prefix string)`** - Add a prefix field to all log entries
- **`WithHook(hook zerolog.Hook)`** - Add a custom zerolog hook
- **`WithHookFunc(hookFunc zerolog.HookFunc)`** - Add a custom hook function
- **`WithDefaultPrintLevel(level log.Lvl)`** - Set default level for Print/Printf methods (replaces "???" with actual level)

### Default Print Level Configuration

When Echo framework uses its internal logging methods (like for server startup messages), it calls the `Print` and `Printf` methods without specifying a log level. By default, this results in logs with a level of `"-"` which may appear as `"???"` in some log viewers.

You can configure a default level for these methods using `WithDefaultPrintLevel`:

```go
package main

import (
"os"
"github.com/labstack/echo/v4"
"github.com/labstack/gommon/log"
"github.com/ziflex/lecho/v3"
)

func main() {
e := echo.New()

// Configure logger with default print level
e.Logger = lecho.New(
os.Stdout,
lecho.WithTimestamp(),
lecho.WithDefaultPrintLevel(log.INFO), // Echo's Print methods will use INFO level
)

e.Start(":8080") // This message will now show as INFO level instead of "???"
}
```

**Before (without WithDefaultPrintLevel):**
```
2024-11-24T18:36:10Z ??? ⇨ http server started on [::]:9151
```

**After (with WithDefaultPrintLevel(log.INFO)):**
```
2024-11-24T18:36:10Z INF ⇨ http server started on [::]:9151
```

## Middleware

Expand Down
39 changes: 26 additions & 13 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import (

// Logger is a wrapper around `zerolog.Logger` that provides an implementation of `echo.Logger` interface
type Logger struct {
log zerolog.Logger
out io.Writer
level log.Lvl
prefix string
setters []Setter
log zerolog.Logger
out io.Writer
level log.Lvl
prefix string
setters []Setter
defaultPrintLevel *log.Lvl
}

// New returns a new Logger instance
Expand All @@ -36,11 +37,12 @@ func newLogger(log zerolog.Logger, setters []Setter) *Logger {
opts := newOptions(log, setters)

return &Logger{
log: opts.context.Logger(),
out: nil,
level: opts.level,
prefix: opts.prefix,
setters: setters,
log: opts.context.Logger(),
out: nil,
level: opts.level,
prefix: opts.prefix,
setters: setters,
defaultPrintLevel: opts.defaultPrintLevel,
}
}

Expand Down Expand Up @@ -117,15 +119,15 @@ func (l Logger) Panicj(j log.JSON) {
}

func (l Logger) Print(i ...interface{}) {
l.log.WithLevel(zerolog.NoLevel).Str("level", "-").Msg(fmt.Sprint(i...))
l.printEvent().Msg(fmt.Sprint(i...))
}

func (l Logger) Printf(format string, i ...interface{}) {
l.log.WithLevel(zerolog.NoLevel).Str("level", "-").Msgf(format, i...)
l.printEvent().Msgf(format, i...)
}

func (l Logger) Printj(j log.JSON) {
l.logJSON(l.log.WithLevel(zerolog.NoLevel).Str("level", "-"), j)
l.logJSON(l.printEvent(), j)
}

func (l Logger) Output() io.Writer {
Expand Down Expand Up @@ -164,12 +166,23 @@ func (l *Logger) SetPrefix(newPrefix string) {

l.prefix = newPrefix
l.log = opts.context.Logger()
l.defaultPrintLevel = opts.defaultPrintLevel
}

func (l *Logger) Unwrap() zerolog.Logger {
return l.log
}

// printEvent returns an appropriate zerolog.Event for Print methods
func (l Logger) printEvent() *zerolog.Event {
if l.defaultPrintLevel != nil {
zlvl, _ := MatchEchoLevel(*l.defaultPrintLevel)
return l.log.WithLevel(zlvl)
}
// Backward compatible behavior: use NoLevel with level field set to "-"
return l.log.WithLevel(zerolog.NoLevel).Str("level", "-")
}

func (l *Logger) logJSON(event *zerolog.Event, j log.JSON) {
for k, v := range j {
event = event.Interface(k, v)
Expand Down
13 changes: 10 additions & 3 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (

type (
Options struct {
context zerolog.Context
level log.Lvl
prefix string
context zerolog.Context
level log.Lvl
prefix string
defaultPrintLevel *log.Lvl
}

Setter func(opts *Options)
Expand Down Expand Up @@ -86,3 +87,9 @@ func WithHookFunc(hook zerolog.HookFunc) Setter {
opts.context = opts.context.Logger().Hook(hook).With()
}
}

func WithDefaultPrintLevel(level log.Lvl) Setter {
return func(opts *Options) {
opts.defaultPrintLevel = &level
}
}
33 changes: 33 additions & 0 deletions options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,39 @@ func TestWithLevel(t *testing.T) {
`)
}

func TestWithDefaultPrintLevel(t *testing.T) {
b := &bytes.Buffer{}
l := lecho.New(b, lecho.WithDefaultPrintLevel(log.INFO))

l.Print("Test message")

assert.Equal(t, b.String(), `{"level":"info","message":"Test message"}
`)

b.Reset()
l.Printf("Formatted %s", "message")

assert.Equal(t, b.String(), `{"level":"info","message":"Formatted message"}
`)

b.Reset()
l.Printj(log.JSON{"message": "JSON message"})

assert.Equal(t, b.String(), `{"level":"info","message":"JSON message"}
`)
}

func TestWithDefaultPrintLevel_BackwardCompatibility(t *testing.T) {
// Test that without WithDefaultPrintLevel, behavior remains the same
b := &bytes.Buffer{}
l := lecho.New(b)

l.Print("Test message")

assert.Equal(t, b.String(), `{"level":"-","message":"Test message"}
`)
}

func TestWithPrefix(t *testing.T) {
b := &bytes.Buffer{}
l := lecho.New(b, lecho.WithPrefix("Test"))
Expand Down
Loading