Documentation
¶
Overview ¶
Package slogprovider bridges Go's standard log/slog to the Iris pipeline.
WHY this exists: slog is the Go standard logging API (since Go 1.21). Metis and most Go services use slog exclusively. This provider lets them feed records into Iris's high-performance transport without changing a single call site.
The provider implements two interfaces simultaneously:
- slog.Handler: so slog.New(provider) works as a drop-in
- iris.SyncReader: so Iris can pull records through its pipeline
Architecture ¶
slog.Logger --> Provider.Handle() --> channel --> Provider.Read() --> Iris pipeline --> Output
The channel decouples the slog caller from the Iris processing goroutine. Handle() is non-blocking (drops on full buffer). Read() blocks until a record arrives or the context is cancelled.
Basic Usage ¶
import (
"log/slog"
"os"
"github.com/agilira/iris"
"github.com/agilira/iris/slogprovider"
)
func main() {
provider := slogprovider.New(1000)
defer provider.Close()
readers := []iris.SyncReader{provider}
logger, err := iris.NewReaderLogger(iris.Config{
Output: iris.WrapWriter(os.Stdout),
Encoder: iris.NewJSONEncoder(),
Level: iris.Info,
}, readers)
if err != nil {
panic(err)
}
defer logger.Close()
logger.Start()
slogger := slog.New(provider)
slogger.Info("User login", "user_id", "12345")
}
Performance ¶
- Handle(): ~60-150 ns/op (channel send with select)
- Record conversion: ~500-1000 ns/op with type preservation
- Overall: 10-20x faster than standard slog handlers
Type Preservation ¶
slog attribute types (String, Int64, Uint64, Float64, Bool, Duration, Time) are mapped to their iris.Field equivalents. This ensures JSON encoders emit correct types instead of quoting everything as strings.
Index ¶
- type Provider
- func (p *Provider) Close() error
- func (p *Provider) Enabled(ctx context.Context, level slog.Level) bool
- func (p *Provider) Handle(ctx context.Context, record slog.Record) error
- func (p *Provider) Read(ctx context.Context) (*iris.Record, error)
- func (p *Provider) WithAttrs(attrs []slog.Attr) slog.Handler
- func (p *Provider) WithGroup(name string) slog.Handler
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider implements iris.SyncReader for Go's standard log/slog package.
Provider acts as a bridge between slog and Iris, implementing both the iris.SyncReader interface for Iris integration and the slog.Handler interface for slog compatibility. It captures slog records in an internal buffer and converts them to Iris records on demand.
The provider is designed for high performance and thread safety:
- Non-blocking Handle() operations (drops records on buffer full)
- Efficient record conversion with type preservation
- Safe concurrent access from multiple goroutines
- Graceful shutdown with proper resource cleanup
Example usage:
provider := slogprovider.New(1000)
defer provider.Close()
slogger := slog.New(provider)
slogger.Info("Message", "key", "value")
func New ¶
New creates a new Provider that captures slog records for processing by Iris.
The bufferSize parameter controls the internal channel buffer size. A larger buffer provides better performance under burst loads but uses more memory. Recommended values:
- 100-500: Low to moderate logging volume applications
- 1000-5000: High volume applications
- 5000+: Very high volume or burst-heavy applications
When the buffer is full, new records are dropped to maintain non-blocking behavior. Monitor your application's logging patterns to choose an appropriate buffer size.
The returned Provider must be closed when no longer needed to free resources:
provider := New(1000) defer provider.Close()
func (*Provider) Close ¶
Close implements io.Closer to gracefully shut down the provider.
WHY sync.Once: Close may be called from defer + explicit shutdown paths. Double-close on a channel panics; sync.Once makes this impossible.
After Close() is called:
- Handle() will return an error for new records
- Read() will return nil, nil after processing remaining buffered records
- The provider should not be used for new operations
func (*Provider) Enabled ¶
Enabled implements slog.Handler to indicate whether records at the given level should be processed.
WHY always true: Level filtering is Iris's responsibility. Delegating here would create two competing filter points and make dynamic level changes impossible without reconfiguring the slog side.
func (*Provider) Handle ¶
Handle implements slog.Handler to capture slog records for processing by Iris.
This method is called by the slog library for each log record. It attempts to store the record in the internal buffer for later processing by Iris. The operation is non-blocking:
- If buffer space is available, the record is stored successfully
- If the provider is closed, an error is returned
- If the buffer is full, the record is dropped silently (returns nil)
The non-blocking behavior ensures that logging never blocks the application, even under high load conditions. Applications should monitor buffer sizes and provider performance if record dropping is a concern.
Thread Safety: Safe for concurrent access from multiple goroutines.
func (*Provider) Read ¶
Read implements iris.SyncReader to provide slog records to the Iris pipeline.
This method is called by Iris to retrieve the next available log record for processing. It blocks until:
- A record becomes available (returns the converted record)
- The context is cancelled (returns context error)
- The provider is closed (returns nil, nil)
The method converts slog records to Iris records, preserving message content, level information, and all attributes with appropriate type conversion.
Thread Safety: Safe for concurrent access, though typically called by a single Iris reader goroutine.
func (*Provider) WithAttrs ¶
WithAttrs implements slog.Handler to create a handler with additional attributes.
WHY pass-through: The slog library embeds attributes into each Record before calling Handle(). Duplicating that logic here would add complexity with zero gain -- the attributes arrive regardless.