Documentation
¶
Overview ¶
Package slogbuffer provides slog.Handler implementation that is capable of buffering log records until controlling applications flushes them to real handler.
This can be helpful in situations like:
- configuration of real handler is not known until later (e.g. CLI applications that provide user with flags to control log output)
- logs are streamed over network and sink is still not ready to accept log records
- logs should be flushed only if some condition is met (e.g. panic)
This handler handles those cases but buffering log records and re-emits them on command by implementing slog.Handler that stores logs in memory until it receives Handler to wrap, after which it is just a simple wrapping handler.
Index ¶
- type BufferLogHandler
- func (h *BufferLogHandler) Discard()
- func (h *BufferLogHandler) Enabled(ctx context.Context, level slog.Level) bool
- func (h *BufferLogHandler) Handle(ctx context.Context, r slog.Record) error
- func (h *BufferLogHandler) SetRealHandler(ctx context.Context, real slog.Handler) error
- func (h *BufferLogHandler) WithAttrs(attrs []slog.Attr) slog.Handler
- func (h *BufferLogHandler) WithGroup(name string) slog.Handler
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BufferLogHandler ¶
type BufferLogHandler struct {
// contains filtered or unexported fields
}
BufferLogHandler is pkg/log/slog.Handler that buffers records in memory until real log handler is provided, at which point it drains memory buffer and uses real handler from that point. Zero value is useful.
Example ¶
package main import ( "context" "github.com/delicb/slogbuffer" "log/slog" "os" ) func main() { // buffer log message up to 256 messages, drop oldest one is more messages are logged h := slogbuffer.NewBoundBufferLogHandler(slog.LevelInfo, 256) log := slog.New(h) // use logger normally log.Info("some message", slog.Int("key", 11)) log.Debug("discarded message") log.Warn("warn message") // read config, config file, whatever to figure out how real handler looks like realHandler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ ReplaceAttr: func(groups []string, attr slog.Attr) slog.Attr { if attr.Key == slog.TimeKey { // remove time to have constant output return slog.Attr{} } return attr }, }) // after setup is complete, we know the config of real handler err := h.SetRealHandler(context.Background(), realHandler) if err != nil { panic("setting real handler") } // from this point on, log records are not buffered, they are just passed to real handler log.Info("direct logging") }
Output: level=INFO msg="some message" key=11 level=WARN msg="warn message" level=INFO msg="direct logging"
func NewBoundBufferLogHandler ¶
func NewBoundBufferLogHandler(level slog.Level, maxRecords int) *BufferLogHandler
NewBoundBufferLogHandler creates instance of log handler that stores log records with upper limit on number of records, thus providing some level of memory consumption control.
func NewBufferLogHandler ¶
func NewBufferLogHandler(level slog.Level) *BufferLogHandler
NewBufferLogHandler returns unbound instance of log handler that stores log records until such time when SetRealHandler is called, at which point messages get flushed and all subsequent calls are just proxy calls to real handler.
func (*BufferLogHandler) Discard ¶
func (h *BufferLogHandler) Discard()
Discard removers all stored records.
func (*BufferLogHandler) SetRealHandler ¶
SetRealHandler set real slog.Handler for this buffer handler. This will cause all buffered log records to be emitted to provided handler. Also, from this point on, current handler behaves as simple wrapper and all handling is passed to real handler (thus this instance is still usable, in case reference to it is held somewhere).