Logging
Flamigo uses Go's standard log/slog package for framework-internal logs.
Framework records are emitted with structured attributes so you can filter or route them without disabling all debug logging:
library=flamigocomponent=<package area>code=<stable event code>
For example, the event listener type-mismatch debug record includes:
component=eventscode=unsupported_event_type
Use Your App's Default slog Logger
If your application already uses slog, the simplest setup is to configure the default logger once:
package main
import (
"log/slog"
"os"
)
func init() {
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
})))
}Flamigo will pick that up automatically.
Use a Dedicated Logger for Flamigo
If you want Flamigo logs to use a different handler than the rest of your app, set a framework-scoped logger:
package main
import (
flamigo "github.com/amberbyte/flamigo"
"log/slog"
"os"
)
func init() {
flamigo.SetLogger(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
})))
}Filter Specific Framework Records
To suppress a noisy debug record while keeping other debug logs, wrap your handler with flamigo.NewFilterHandler:
package main
import (
"context"
flamigo "github.com/amberbyte/flamigo"
"log/slog"
"os"
)
func init() {
handler := flamigo.NewFilterHandler(
slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}),
func(_ context.Context, record slog.Record) bool {
if record.Message != "unsupported event type" {
return true
}
allow := true
record.Attrs(func(attr slog.Attr) bool {
if attr.Key == "code" && attr.Value.String() == "unsupported_event_type" {
allow = false
return false
}
return true
})
return allow
},
)
flamigo.SetLogger(slog.New(handler))
}If Your App Still Uses Logrus
Your application can continue using logrus. The clean approach is to bridge Flamigo's slog output into a logrus logger with a custom slog.Handler.
package main
import (
"context"
flamigo "github.com/amberbyte/flamigo"
"log/slog"
"github.com/sirupsen/logrus"
)
type logrusHandler struct {
entry *logrus.Entry
attrs []slog.Attr
}
func newLogrusHandler(logger *logrus.Logger) slog.Handler {
return &logrusHandler{entry: logrus.NewEntry(logger)}
}
func (h *logrusHandler) Enabled(_ context.Context, level slog.Level) bool {
switch {
case level >= slog.LevelError:
return h.entry.Logger.IsLevelEnabled(logrus.ErrorLevel)
case level >= slog.LevelWarn:
return h.entry.Logger.IsLevelEnabled(logrus.WarnLevel)
case level >= slog.LevelInfo:
return h.entry.Logger.IsLevelEnabled(logrus.InfoLevel)
default:
return h.entry.Logger.IsLevelEnabled(logrus.DebugLevel)
}
}
func (h *logrusHandler) Handle(_ context.Context, record slog.Record) error {
fields := logrus.Fields{}
for _, attr := range h.attrs {
fields[attr.Key] = attr.Value.Any()
}
record.Attrs(func(attr slog.Attr) bool {
fields[attr.Key] = attr.Value.Any()
return true
})
entry := h.entry.WithFields(fields)
switch {
case record.Level >= slog.LevelError:
entry.Error(record.Message)
case record.Level >= slog.LevelWarn:
entry.Warn(record.Message)
case record.Level >= slog.LevelInfo:
entry.Info(record.Message)
default:
entry.Debug(record.Message)
}
return nil
}
func (h *logrusHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
combined := make([]slog.Attr, 0, len(h.attrs)+len(attrs))
combined = append(combined, h.attrs...)
combined = append(combined, attrs...)
return &logrusHandler{entry: h.entry, attrs: combined}
}
func (h *logrusHandler) WithGroup(string) slog.Handler {
return h
}
func init() {
logger := logrus.New()
logger.SetLevel(logrus.DebugLevel)
flamigo.SetLogger(slog.New(newLogrusHandler(logger)))
}