-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider replacing logging lib sirupsen/logrus
with log/slog
#48
Comments
This feature can be convenient for debuging because it points to the file and the line which corresponds to the log message.
Below is the example corresponding to This feature does not exist as is in package main
import (
"context"
"fmt"
"log/slog"
"os"
"runtime"
"strings"
)
type FilenameHandler struct {
wrapped slog.Handler
Field string
Skip int
Formatter func(file, function string, line int) string
}
// NewFilenameHandler creates a new FilenameHandler wrapping an existing handler.
func NewFilenameHandler(handler slog.Handler, options ...func(*FilenameHandler)) *FilenameHandler {
h := &FilenameHandler{
wrapped: handler,
Field: "source",
Skip: 0,
Formatter: func(file, function string, line int) string {
return fmt.Sprintf("%s:%d", file, line)
},
}
for _, opt := range options {
opt(h)
}
return h
}
// Enabled checks if the logging level is enabled.
func (h *FilenameHandler) Enabled(ctx context.Context, level slog.Level) bool {
return h.wrapped.Enabled(ctx, level)
}
// Handle adds filename and line number attributes, then delegates to the wrapped handler.
func (h *FilenameHandler) Handle(ctx context.Context, record slog.Record) error {
file, function, line := findCaller(h.Skip)
formatted := h.Formatter(file, function, line)
record.AddAttrs(slog.String(h.Field, formatted))
return h.wrapped.Handle(ctx, record)
}
// WithAttrs returns a new handler with additional attributes.
func (h *FilenameHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return NewFilenameHandler(h.wrapped.WithAttrs(attrs))
}
// WithGroup returns a new handler with a group name.
func (h *FilenameHandler) WithGroup(name string) slog.Handler {
return NewFilenameHandler(h.wrapped.WithGroup(name))
}
// findCaller retrieves the file, function name, and line number of the caller.
func findCaller(skip int) (string, string, int) {
var (
pc uintptr
file string
function string
line int
)
for i := 0; i < 10; i++ {
pc, file, line, _ = runtime.Caller(skip + i)
if !strings.Contains(file, "log/slog") { // Avoid internal calls
break
}
}
if pc != 0 {
frames := runtime.CallersFrames([]uintptr{pc})
frame, _ := frames.Next()
function = frame.Function
}
// Trim file path for readability
file = trimFilePath(file)
return file, function, line
}
// trimFilePath trims the file path to show only the last two directories.
func trimFilePath(file string) string {
n := 0
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' {
n++
if n >= 2 {
return file[i+1:]
}
}
}
return file
}
func main() {
// Create a default TextHandler
handler := slog.NewTextHandler(os.Stdout, nil)
// Wrap it with the FilenameHandler, customizing the field name
handlerWithFilename := NewFilenameHandler(handler, func(h *FilenameHandler) {
h.Field = "caller"
h.Skip = 0
h.Formatter = func(file, function string, line int) string {
return fmt.Sprintf("%s:%s:%d", file, function, line)
}
})
// Create a logger using the wrapped handler
logger := slog.New(handlerWithFilename)
newOutput := "ceci est un test"
logger.Info("This is a test log", "clerandome", newOutput)
logger.Info("This is a test log")
} Code below looks like this go build -o test-slog-filename-handler main.go ./test-slog-filename-handler
time=2025-01-23T13:55:44.231+01:00 level=INFO msg="This is a test log" clerandome="ceci est un test" caller=golang-deletemoi/main.go:main.findCaller:67
time=2025-01-23T13:55:44.231+01:00 level=INFO msg="This is a test log" caller=golang-deletemoi/main.go:main.findCaller:67 But this line |
Consider replacing logging lib https://github.com/sirupsen/logrus with golang standard library
log/slog
as described in https://go.dev/blog/slog.Indeed,
github.com/sirupsen/logrus
latest version is from june 2023, and it is not clear if it is still maintained.Whereas
log/slog
is from go standard library (https://cs.opensource.google/go/go/+/master:src/log/slog/;bpv=1). We can expect more maintainance.However, one drawback is the syntax from
log/slog
is different fromgithub.com/sirupsen/logrus
, becauselog/slog
is structured:The output should look like this:
or depending on the
log/slog
output handler format oflog/slog
(text, JSON):Maybe this could be done at the same time than enhancing the CLI with a
--log-level
flag, like suggested in #47The text was updated successfully, but these errors were encountered: