logging

package module
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 4, 2025 License: Apache-2.0 Imports: 17 Imported by: 1

README

Logging

Testing

Run all tests in logging package using one of the following commands

go test ./... 
go test -race ./... 
go test -race -coverprofile=coverage.out ./... 
go test -race -coverprofile=coverage.out ./... && go tool cover -html=coverage.out
Benchmarks

Run all Benchmarks

go test -bench=. -benchmem

Documentation

Overview

Package logging provides a high-performance, flexible logging framework compatible with log/slog, designed for modern Go applications. It supports multiple adapters with distinct behaviors (e.g., buffered with drop for metrics, block for reliable logging, or synchronous for console output), enabling tailored log handling.

Features:

  • Slog Compatibility: Implements slog.Handler, supporting all standard methods (Log, Debug, Info, With, etc.).
  • Multi-Adapter Support: Assign multiple adapters (e.g., BufferedTextAdapter, BufferedJSONAdapter, ConsoleAdapter) to log to different outputs with custom behaviors (e.g., Drop for metrics, Block for audits). Buffered logs are processed in batches for efficiency.
  • Hot-Swappable Writers: Swap adapter writers at runtime (e.g., from os.Stdout to a file for log rotation or daemonizing) without recreating adapters or affecting other adapters. Utility functions support swapping os.Stdout/os.Stderr for all relevant adapters, leaving buffered or custom adapters unchanged.
  • BufferedAdapter: Offers high throughput (~3x faster than slog.Logger difault handlerers with Drop policy, ~10x in concurrent workloads) or reliable logging (~24% faster with Block policy).
  • Configurability: AdapterConfig tunes BufferSize (default 8192, ~5-10 MiB), BatchSize (default 2048), FlushInterval (default 512µs), and Policy (default Block).
  • Resource Management: Dispose and Flush ensure proper cleanup and log syncing. Dispose MUST be called when application exits on primary logger to signal all adapters gracefully release resources.
  • Derived Loggers: WithGroup/With create lightweight loggers sharing state, no separate Dispose needed.

Usage:

config := DefaultConfig()
config.Level = LevelInfo
logger := New(config,
    NewBufferedTextAdapter(os.Stdout, nil), // Block policy for reliable logs
    NewBufferedJSONAdapter(os.Stderr, &AdapterConfig{Policy: AdapterPolicyDrop}), // Drop for metrics
    adapters.NewConsoleAdapter(os.Stdout, adapters.ConsoleAdapterDefaultTheme()), // Synchronous
)
defer logger.Dispose()
logger.Info("message", "key", "value")
// Swap writer for BufferedTextAdapter (e.g., for log rotation)
logger.ReplaceWriter(0, os.Stdout, newLogFile)
logger.Flush()

For memory-constrained environments, set BufferSize=2048 (~1.5 MiB) for minimal performance impact (~8% slower). See benchmarks in the repository for details.

Index

Constants

View Source
const (
	// DefaultAdapterBufferSize is the default buffer size for buffered adapters (power of 2).
	DefaultAdapterBufferSize int = 8192 // records
	// DefaultAdapterBatchSize is the default batch size for buffered adapters.
	DefaultAdapterBatchSize int = 2048 // records
	// DefaultAdapterFlushInterval is the default flush interval (0 = immediate flush).
	DefaultAdapterFlushInterval time.Duration = time.Duration(time.Microsecond * 256)

	DefaultAdapterFlushTimeout time.Duration = time.Duration(time.Second * 5)
	// DefaultAdapterRetryTimeout is the max timeout for retries in AdapterPolicyBlock.
	DefaultAdapterRetryTimeout = time.Second
	// DefaultAdapterMaxRetries is the max retry attempts in AdapterPolicyBlock.
	DefaultAdapterMaxRetries = 10
	// DefaultAttrProcessorPoolSize is the default pool size for attribute processors.
	DefaultAttrProcessorPoolSize uint8 = 4
)

Constants for adapter configuration and policies.

Variables

View Source
var (
	// Error is the base error for the logging package.
	Error = errors.New("logging")
	// ErrLoggerDisposed is returned when entire logger and all Adapters are Disposed and Logger is used after disposal.
	ErrLoggerDisposed = fmt.Errorf("%w: logger disposed", Error)
	// ErrAdapter is the base error for adapter-related issues.
	ErrAdapter = fmt.Errorf("%w:adapter", Error)
	// ErrAdapterNotComposed is returned when an adapter is used before composition.
	ErrAdapterNotComposed = fmt.Errorf("%w: not composed", ErrAdapter)
	// ErrAdapterDisposed is returned when an adapter is used after disposal.
	ErrAdapterDisposed = fmt.Errorf("%w: disposed", ErrAdapter)
	// ErrAdapterSwappingOutput is returned when swapping adapter output fails.
	ErrAdapterSwappingOutput = fmt.Errorf("%w: swapping output", ErrAdapter)
	// ErrAdapterBufferFull is returned when a record is dropped due to a full buffer.
	ErrAdapterBufferFull = fmt.Errorf("%w: buffer full, record dropped", ErrAdapter)
	// ErrAdapterBufferFullRetry is returned when a buffer is full but a retry is needed.
	ErrAdapterBufferFullRetry = fmt.Errorf("%w: buffer full, should retry", ErrAdapter)
	// ErrWriter is the base error for writer-related issues.
	ErrWriter = fmt.Errorf("%w:writer", Error)
	// ErrWriterIO is returned when an I/O error occurs during a write operation.
	ErrWriterIO = fmt.Errorf("%w:io", ErrWriter)
	// ErrLevel is returned when a logging level is invalid or unsupported.
	ErrLevel = fmt.Errorf("%w:level", Error)
)

Functions

func GetAdaptersFromHandler added in v0.3.0

func GetAdaptersFromHandler[T Adapter](h slog.Handler) []T

GetAdaptersFromHandler retrieves Adapters of type T from a slog.Handler.

func NewHttpRecord added in v0.3.0

func NewHttpRecord(t time.Time, method string, statusCode int, path string, args ...any) slog.Record

NewHttpRecord returns special slog.Record to log http logs. This record is passed ONLY to Adapters acepting it otherwise record is dropped without Handlerer or Adapter error

func ReplaceAdaptersStderr added in v0.3.0

func ReplaceAdaptersStderr(l *Logger, w io.Writer) error

ReplaceAdaptersStderr replaces stderr writers for adapters using os.Stderr.

This must be called BEFORE any system-level file descriptor duplication (e.g. unix.Dup2(fd, 2)), as the method checks the original stderr to determine which adapters need updating.

Returns ErrAdapterSwappingOutput if no adapters using os.Stderr are found, which typically indicates the method was called after system-level FD duplication. This method never fails due to writer close errors since os.Stderr is never actually closed during the swap operation.

Designed for hot-swapping stderr in daemonized applications (e.g., log rotation). The operation is thread-safe as it locks the logger's handler.

func ReplaceAdaptersStdout added in v0.3.0

func ReplaceAdaptersStdout(l *Logger, w io.Writer) error

ReplaceAdaptersStdout replaces stdout writers for adapters using os.Stdout.

This must be called BEFORE any system-level file descriptor duplication (e.g. unix.Dup2(fd, 1)), as the method checks the original stdout to determine which adapters need updating.

Returns ErrAdapterSwappingOutput if no adapters using os.Stdout are found, which typically indicates the method was called after system-level FD duplication. This method never fails due to writer close errors since os.Stdout is never actually closed during the swap operation.

Designed for hot-swapping stdout in daemonized applications (e.g., log rotation). The operation is thread-safe as it locks the logger's shared handler.

func ReplaceAttrLevel added in v0.3.0

func ReplaceAttrLevel(groups []string, a slog.Attr) slog.Attr

ReplaceAttrLevel creates a ReplaceAttrFunc to format level attributes.

Types

type Adapter added in v0.2.0

type Adapter interface {
	slog.Handler
}

Adapter implements slog.Handler

var DiscardAdapter Adapter = discardAdapter{}

DiscardAdapter discards all log output and always returns false for Enabled.

type AdapterComposeFunc added in v0.3.0

type AdapterComposeFunc[A Adapter] func(writer *Writer, config Config) A

AdapterComposeFunc creates an Adapter from a writer and configuration.

type AdapterComposeHandlerFunc added in v0.3.0

type AdapterComposeHandlerFunc[H slog.Handler] func(writer io.Writer, opts *slog.HandlerOptions) H

AdapterComposeHandlerFunc creates a slog.Handler from a writer and options.

type AdapterComposer added in v0.3.0

type AdapterComposer[A Adapter] struct {
	// contains filtered or unexported fields
}

AdapterComposer composes an Adapter from a handler and logger configuration.

func NewAdapter added in v0.3.0

func NewAdapter[A Adapter](w io.Writer, f AdapterComposeFunc[A]) *AdapterComposer[A]

NewAdapter creates an AdapterComposer for the specified Adapter type.

func NewAdapterWithHandler added in v0.3.0

func NewAdapterWithHandler[H slog.Handler](
	w io.Writer,
	f AdapterComposeHandlerFunc[H],
) *AdapterComposer[*DefaultAdapter]

NewAdapterWithHandler creates an AdapterComposer from a slog.Handler creator.

func NewBufferedJSONAdapter added in v0.3.0

func NewBufferedJSONAdapter(w io.Writer, dropped *expvar.Int) *AdapterComposer[*BufferedAdapter[Adapter]]

NewBufferedJSONAdapter creates an AdapterComposer for a buffered JSON adapter.

func NewBufferedTextAdapter added in v0.3.0

func NewBufferedTextAdapter(w io.Writer, dropped *expvar.Int) *AdapterComposer[*BufferedAdapter[Adapter]]

NewBufferedTextAdapter creates an AdapterComposer for a buffered text adapter.

func NewJSONAdapter added in v0.3.0

func NewJSONAdapter(w io.Writer) *AdapterComposer[*DefaultAdapter]

NewJSONAdapter creates an AdapterComposer for a slog.JSONHandler.

func NewTextAdapter added in v0.2.0

func NewTextAdapter(w io.Writer) *AdapterComposer[*DefaultAdapter]

NewTextAdapter creates an AdapterComposer for a slog.TextHandler.

func (*AdapterComposer[A]) Compose added in v0.3.0

func (c *AdapterComposer[A]) Compose(config Config) Adapter

Compose creates an Adapter using the provided configuration.

func (*AdapterComposer[A]) Enabled added in v0.3.0

func (c *AdapterComposer[A]) Enabled(ctx context.Context, l slog.Level) bool

Enabled always returns false until the adapter is composed.

func (*AdapterComposer[A]) Err added in v0.3.0

func (c *AdapterComposer[A]) Err() error

Err returns always ErrAdapterNotComposed.

func (*AdapterComposer[A]) Handle added in v0.3.0

func (c *AdapterComposer[A]) Handle(ctx context.Context, record slog.Record) error

Handle returns always ErrAdapterNotComposed.

func (*AdapterComposer[A]) WithAttrs added in v0.3.0

func (c *AdapterComposer[A]) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs returns the composer unchanged.

func (*AdapterComposer[A]) WithGroup added in v0.3.0

func (c *AdapterComposer[A]) WithGroup(name string) slog.Handler

WithGroup returns the composer unchanged.

type AdapterConfig added in v0.3.0

type AdapterConfig struct {
	BufferSize    int           // Buffer size (adjusted to power of 2).
	Policy        AdapterPolicy // Policy for full buffers (Block or Drop).
	BatchSize     int           // Max records per batch.
	FlushInterval time.Duration // Interval for flushing batches (0 = immediate).
	FlushTimeout  time.Duration // Timout after flush fails if not completed
	MaxRetries    int           // Max retries for AdapterPolicyBlock.
	RetryTimeout  time.Duration // Max timeout for retries in AdapterPolicyBlock.
}

AdapterConfig defines settings for buffered adapters, controlling buffering and retry behavior.

func DefaultAdapterConfig added in v0.3.0

func DefaultAdapterConfig() AdapterConfig

DefaultAdapterConfig returns an AdapterConfig with default settings.

type AdapterDisposeFunc added in v0.3.0

type AdapterDisposeFunc func() error

AdapterDisposeFunc closes an Adapter and releases its resources.

type AdapterError added in v0.3.0

type AdapterError struct {
	// contains filtered or unexported fields
}

AdapterError wraps errors for storage in atomic.Value by Adapters.

func NewAdapterError added in v0.3.0

func NewAdapterError(err error) *AdapterError

NewAdapterError wraps an error for use in an Adapter, avoiding double-wrapping.

func (*AdapterError) Err added in v0.3.0

func (e *AdapterError) Err() error

Err returns the wrapped error.

func (*AdapterError) Error added in v0.3.0

func (e *AdapterError) Error() string

Error returns the string representation of the wrapped error.

type AdapterPolicy added in v0.3.0

type AdapterPolicy uint8

AdapterPolicy defines the behavior for handling full buffers in buffered adapters.

const (
	// AdapterPolicyBlock blocks the handler until the record is written or times out.
	AdapterPolicyBlock AdapterPolicy = iota
	// AdapterPolicyDrop discards records immediately when the buffer is full.
	AdapterPolicyDrop
)

func (AdapterPolicy) String added in v0.3.0

func (p AdapterPolicy) String() string

String returns the string representation of the adapter policy.

type AdapterReady added in v0.3.0

type AdapterReady interface {
	// Logger calls Ready to signal that the adapter is initialized and attached to a logger.
	Ready()
}

AdapterReady is an Adapter that needs signaling when it is initialized and attached.

type AdapterWithBatchHandle added in v0.3.0

type AdapterWithBatchHandle interface {
	// BatchHandle processes a batch of log records.
	BatchHandle(records []Record) error
}

AdapterWithBatchHandle processes bursts of log records efficiently.

type AdapterWithHTTPBatchHandle added in v0.3.0

type AdapterWithHTTPBatchHandle interface {
	// HTTPBatchHandle processes a batch of HTTP records.
	HTTPBatchHandle(records []HttpRecord) error
}

AdapterWithHTTPBatchHandle defines adapters batch-handling HTTP records.

type AdapterWithHTTPHandle added in v0.3.0

type AdapterWithHTTPHandle interface {
	// HTTP handles an HTTP-specific log record.
	HTTP(ctx context.Context, method string, statusCode int, path string, r slog.Record) error
}

AdapterWithHTTPHandle defines adapters handling HTTP records.

type Buffer added in v0.3.0

type Buffer struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Buffer is a concurrency-safe buffer designed for application developers to use as an io.Writer for logging adapters. It implements io.Writer, io.Reader, io.Closer, and sync.Locker, ensuring thread-safe operations. Unlike bytes.Buffer, it prevents data races when used with logging adapters that take ownership of the writer. Use this when passing a buffer to a logging adapter to safely accumulate and read log data concurrently.

Example:

buf := logging.NewBuffer()
logger := someAdapter(buf)
buf.Write([]byte("log message"))
data, _ := buf.ReadAll()

func NewBuffer added in v0.3.0

func NewBuffer() *Buffer

NewBuffer creates a new concurrency-safe Buffer.

func (*Buffer) Cap added in v0.3.0

func (b *Buffer) Cap() int

func (*Buffer) Len added in v0.3.0

func (b *Buffer) Len() int

func (*Buffer) Read added in v0.3.0

func (b *Buffer) Read(p []byte) (n int, err error)

Read reads bytes from the buffer, thread-safe.

func (*Buffer) ReadAll added in v0.3.0

func (b *Buffer) ReadAll() ([]byte, error)

ReadAll reads all data from the buffer, thread-safe, returning a copy of the buffer's contents.

func (*Buffer) Reset added in v0.3.0

func (b *Buffer) Reset()

Reset clears the buffer's contents, thread-safe.

func (*Buffer) String added in v0.3.0

func (b *Buffer) String() string

func (*Buffer) Write added in v0.3.0

func (b *Buffer) Write(p []byte) (n int, err error)

Write writes bytes to the buffer, thread-safe.

type BufferedAdapter added in v0.3.0

type BufferedAdapter[A Adapter] struct {
	// contains filtered or unexported fields
}

BufferedAdapter provides high-performance buffering for adapters used by Logger. It wraps an Adapter implementing slog.Handler, using a lock-free ring buffer to handle burst logging without blocking the caller.

func NewBufferedAdapter added in v0.3.0

func NewBufferedAdapter[A Adapter](adapter A, adapterConfig AdapterConfig, droppedCounter *expvar.Int) *BufferedAdapter[A]

NewBufferedAdapter creates a BufferedAdapter wrapping the given adapter.

func (*BufferedAdapter[A]) AcceptsHTTP added in v0.3.0

func (b *BufferedAdapter[A]) AcceptsHTTP() bool

AcceptsHTTP returns true if the adapter accepts HTTP records.

func (*BufferedAdapter[A]) Dispose added in v0.3.0

func (b *BufferedAdapter[A]) Dispose() error

Dispose stops the processing goroutine and disposes the underlying adapter.

func (*BufferedAdapter[A]) Dropped added in v0.3.0

func (b *BufferedAdapter[A]) Dropped() int64

Dropped returns the number of records dropped due to buffer overflow.

func (*BufferedAdapter[A]) Enabled added in v0.3.0

func (b *BufferedAdapter[A]) Enabled(ctx context.Context, l slog.Level) bool

Enabled checks if the underlying adapter handles the given level.

func (*BufferedAdapter[A]) Err added in v0.3.0

func (b *BufferedAdapter[A]) Err() error

Err returns the last error encountered by the adapter, or nil if none.

func (*BufferedAdapter[A]) Flush added in v0.3.0

func (b *BufferedAdapter[A]) Flush() error

Flush triggers processing of all buffered records and flushes the underlying adapter.

func (*BufferedAdapter[A]) GetBufferedAdapterName added in v0.3.0

func (b *BufferedAdapter[A]) GetBufferedAdapterName() string

GetBufferedAdapterName returns the name of the adapter being buffered.

func (*BufferedAdapter[A]) Handle added in v0.3.0

func (b *BufferedAdapter[A]) Handle(ctx context.Context, record slog.Record) error

Handle buffers a log record based on the configured policy.

func (*BufferedAdapter[A]) RecordHandle added in v0.3.0

func (b *BufferedAdapter[A]) RecordHandle(record Record) error

RecordHandle handles a single record with retry semantics.

func (*BufferedAdapter[A]) WithAttrs added in v0.3.0

func (b *BufferedAdapter[A]) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs returns a lightweight derived adapter with added attributes.

func (*BufferedAdapter[A]) WithGroup added in v0.3.0

func (b *BufferedAdapter[A]) WithGroup(name string) slog.Handler

WithGroup returns a lightweight derived adapter with the specified group name.

type ComposableAdapter added in v0.3.0

type ComposableAdapter interface {
	// Compose creates an Adapter using the provided configuration.
	Compose(Config) Adapter
}

ComposableAdapter is an Adapter that must be composed with logger config.

type Config added in v0.3.0

type Config struct {
	AddSource             bool           // Include source information in logs.
	AttrProcessorPoolSize uint8          // Size of attribute processor pool.
	Adapter               AdapterConfig  // Buffered adapter configuration.
	Level                 Level          // Minimum log level.
	NoTimestamp           bool           // Omit timestamps in logs.
	Secrets               []string       // Keys to redact as secrets.
	SetSlogOutput         bool           // Enable slog output integration.
	TimeFormat            string         // Timestamp format (empty if NoTimestamp).
	TimeLocation          *time.Location // Timezone for timestamps.
	Omit                  []string       // Attribute keys to omit.
	// contains filtered or unexported fields
}

Config defines settings for a logging handler, including level, attributes, and adapter behavior.

func DefaultConfig added in v0.3.0

func DefaultConfig() Config

DefaultConfig returns a Config with default settings for logging.

func (*Config) HandlerOptions added in v0.3.0

func (c *Config) HandlerOptions() *slog.HandlerOptions

HandlerOptions returns slog.HandlerOptions based on the Config.

func (*Config) ReplaceAttr added in v0.3.0

func (c *Config) ReplaceAttr(f ReplaceAttrFunc)

ReplaceAttr adds a function to transform attributes, chaining with existing ones. Ignored if the Config is sealed.

type DefaultAdapter added in v0.3.0

type DefaultAdapter struct {
	slog.Handler
}

DefaultAdapter wraps a slog.Handler to implement the Adapter interface.

func (*DefaultAdapter) BatchHandle added in v0.3.0

func (d *DefaultAdapter) BatchHandle(records []Record) error

BatchHandler processes a batch if the wrapped handler implements AdapterWithBatchHandler.

func (*DefaultAdapter) Dispose added in v0.3.0

func (d *DefaultAdapter) Dispose() error

Dispose closes the wrapped handler if it implements DisposableAdapter

func (*DefaultAdapter) Flush added in v0.3.0

func (d *DefaultAdapter) Flush() error

Flush flushes the wrapped handler if it implements FlushableAdapter.

func (*DefaultAdapter) Ready added in v0.3.0

func (d *DefaultAdapter) Ready()

Ready signals readiness if the wrapped handler implements AdapterReady.

type DisposableAdapter added in v0.3.0

type DisposableAdapter interface {
	Adapter
	// Dispose closes the adapter and releases resources. Idempotent.
	Dispose() error
}

DisposableAdapter is an Adapter that can be closed to release resources.

type FlushableAdapter added in v0.3.0

type FlushableAdapter interface {
	Adapter
	// Flush writes any buffered log entries to the underlying writer.
	Flush() error
}

FlushableAdapter is an Adapter that can flush buffered log entries.

type HttpRecord added in v0.3.0

type HttpRecord struct {
	Ctx    context.Context
	Record slog.Record
	Method string
	Code   int
	Path   string
}

HttpRecord is special record type passed to Adapters implementing either AdapterWithHTTPHandle or AdapterWithHTTPBatchHandle

type Level

type Level slog.Level

Level represents a logging level, extending slog.Level with additional levels specific to the Happy SDK. It supports conversion to and from strings, marshaling for configuration settings, and integration with slog for structured logging. You can call Level.Level() to get the underlying slog.Level.

const (
	// LevelHappy is the lowest level, used for positive application events.
	LevelHappy Level = Level(math.MinInt)
	// LevelDebugPkg is for package-specific debug messages.
	LevelDebugPkg Level = LevelHappy + 1
	// LevelDebugAddon is for addon-specific debug messages.
	LevelDebugAddon Level = LevelDebugPkg + 1
	// LevelTrace is for detailed tracing, lower than standard debug.
	LevelTrace Level = Level(slog.LevelDebug - 4)
	// LevelDebug aligns with slog.LevelDebug for standard debugging.
	LevelDebug Level = Level(slog.LevelDebug)
	// LevelInfo aligns with slog.LevelInfo for informational messages.
	LevelInfo Level = Level(slog.LevelInfo)
	// LevelNotice is for notable events, slightly above Info.
	LevelNotice Level = Level(slog.LevelInfo + 1)
	// LevelSuccess indicates successful operations.
	LevelSuccess Level = Level(slog.LevelInfo + 2)
	// LevelNotImpl warns about unimplemented features.
	LevelNotImpl Level = Level(slog.LevelInfo + 3)
	// LevelWarn aligns with slog.LevelWarn for warnings.
	LevelWarn Level = Level(slog.LevelWarn)
	// LevelDepr indicates deprecated features or hot paths.
	LevelDepr Level = Level(slog.LevelWarn + 1)
	// LevelError aligns with slog.LevelError for error conditions.
	LevelError Level = Level(slog.LevelError)
	// LevelOut is for output that would typically go to stdout/stderr.
	// But application wants to log it e.g. having adapter which only listens to LevelOut.
	LevelOut Level = Level(math.MaxInt - 2)
	// LevelBUG indicates critical bugs in the application.
	LevelBUG Level = Level(math.MaxInt - 1)
	// LevelQuiet is the highest level, used to suppress all logging.
	// This level is not used by Adapters
	LevelQuiet Level = Level(math.MaxInt)
)

Predefined logging levels, ordered by severity from lowest to highest. Each level maps to a specific slog.Level value or a custom value for Happy SDK specific levels.

func LevelFromString

func LevelFromString(levelStr string) (Level, error)

LevelFromString converts a string to a Level value. It returns an error if the string does not correspond to a defined level.

Example:

lvl, err := LevelFromString("info")
if err != nil {
    // Handle error
}
// lvl is LevelInfo

func (Level) Level added in v0.3.0

func (l Level) Level() slog.Level

Level converts the Level to an slog.Level for compatibility with the standard library's logging system.

func (Level) LogValue added in v0.3.0

func (l Level) LogValue() slog.Value

LogValue returns the Level as an slog.Value for use in structured logging. It uses the string representation of the level.

Example:

logger.LogAttrs(context.Background(), LevelInfo, "message", slog.Any("level", LevelInfo.LogValue()))

func (Level) MarshalSetting

func (l Level) MarshalSetting() ([]byte, error)

MarshalSetting serializes the Level to a byte slice for use in configuration settings. It returns an error if the level is not a recognized Happy SDK level. Used by settings package.

Example:

b, err := LevelInfo.MarshalSetting()
if err != nil {
    // Handle error
}
// b is []byte("info")

func (Level) String

func (l Level) String() string

String returns the string representation of the Level. For unrecognized levels, it falls back to the string representation of the underlying slog.Level.

func (*Level) UnmarshalSetting

func (l *Level) UnmarshalSetting(data []byte) error

UnmarshalSetting deserializes a byte slice into a Level value. It returns an error if the input does not correspond to a valid level. Used by settings package.

Example:

var lvl Level
err := lvl.UnmarshalSetting([]byte("error"))
if err != nil {
    // Handle error
}
// lvl is LevelError

type LineBuffer added in v0.3.0

type LineBuffer []byte

LineBuffer is a pooled byte buffer for adapter developers to efficiently build log lines from records without frequent allocations. It uses a sync.Pool to reuse buffers, reducing memory overhead. Use this instead of bytes.Buffer in adapter implementations for constructing log lines. Buffers should be returned to the pool with Free() after use to maintain efficiency.

Example:

buf := logging.NewLineBuffer()
buf.WriteString("log line")
adapter.Write(buf)
buf.Free()

func NewLineBuffer added in v0.3.0

func NewLineBuffer() *LineBuffer

NewLineBuffer retrieves a LineBuffer from the pool with an initial capacity of 1KB. Always call Free() when done to return the buffer to the pool.

func (*LineBuffer) Free added in v0.3.0

func (b *LineBuffer) Free()

Free returns the LineBuffer to the pool if its capacity is ≤ 16KB, resetting its length to 0. Larger buffers are discarded to prevent excessive memory use.

func (*LineBuffer) Len added in v0.3.0

func (b *LineBuffer) Len() int

Len returns the current length of the buffer.

func (*LineBuffer) Reset added in v0.3.0

func (b *LineBuffer) Reset()

Reset clears the buffer's contents by setting its length to 0.

func (*LineBuffer) SetLen added in v0.3.0

func (b *LineBuffer) SetLen(n int)

SetLen sets the buffer's length, truncating or zero-extending as needed.

func (*LineBuffer) String added in v0.3.0

func (b *LineBuffer) String() string

String returns the buffer's contents as a string.

func (*LineBuffer) Write added in v0.3.0

func (b *LineBuffer) Write(p []byte) (int, error)

Write appends bytes to the buffer, implementing io.Writer.

func (*LineBuffer) WriteByte added in v0.3.0

func (b *LineBuffer) WriteByte(c byte) error

WriteByte appends a single byte to the buffer.

func (*LineBuffer) WriteString added in v0.3.0

func (b *LineBuffer) WriteString(s string) (int, error)

WriteString appends a string to the buffer.

type Logger

type Logger struct {
	*slog.Logger // Embedded slog.Logger for standard logging methods.
	// contains filtered or unexported fields
}

Logger is the primary interface for logging in the Happy SDK, fully compatible with slog.Logger. It wraps slog.Logger to provide standard logging methods (e.g., Debug, Info, Error) and manages custom adapters for output handling. Users can treat it as a slog.Logger, with all inherited methods delegating to configured adapters. The only exception is that Dispose must be called before the application exits or when the logger is no longer needed to release adapter resources and close writers.

func New

func New(config Config, adapters ...Adapter) *Logger

New creates a Logger with the given configuration and adapters. If no adapters are provided, a default text adapter writing to os.Stdout is used. The config is sealed to finalize settings (e.g., level, timestamp format), and the logger is set as the default slog.Logger if configured. All adapters are initialized and ready after creation.

func (*Logger) BUG

func (l *Logger) BUG(msg string, args ...any)

BUG logs a message at the BUG level, intended for critical bugs.

func (*Logger) BUGContext added in v0.6.0

func (l *Logger) BUGContext(ctx context.Context, msg string, args ...any)

BUGContext logs a message at the BUG level with context.

func (*Logger) Consume added in v0.3.0

func (l *Logger) Consume(queue *QueueLogger) (int, error)

Consume drains all queued records into the Logger. Call *QueueLogger Dispose dont want to use it anymore to release intrnal BufferAdapter It returns the number of records consumed and any error encountered.

func (*Logger) DebugAddon added in v0.5.0

func (l *Logger) DebugAddon(msg string, args ...any)

DebugAddon logs a message at the addon-debug level.

func (*Logger) DebugAddonContext added in v0.6.0

func (l *Logger) DebugAddonContext(ctx context.Context, msg string, args ...any)

DebugAddonContext logs a message at the addon-debug level with context.

func (*Logger) DebugPkg added in v0.5.0

func (l *Logger) DebugPkg(msg string, args ...any)

DebugPkg logs a message at the package-debug level.

func (*Logger) DebugPkgContext added in v0.6.0

func (l *Logger) DebugPkgContext(ctx context.Context, msg string, args ...any)

DebugPkgContext logs a message at the package-debug level with context.

func (*Logger) Deprecated

func (l *Logger) Deprecated(msg string, args ...any)

Deprecated logs a message at the Deprecated level.

func (*Logger) DeprecatedContext added in v0.6.0

func (l *Logger) DeprecatedContext(ctx context.Context, msg string, args ...any)

DeprecatedContext logs a message at the Deprecated level with context.

func (*Logger) Dispose added in v0.2.0

func (l *Logger) Dispose() error

Dispose closes all adapters, releasing their resources and closing writers. It must be called before the application exits or when the logger is no longer needed. Idempotent, safe for concurrent use.

func (*Logger) Flush added in v0.3.0

func (l *Logger) Flush() error

Flush writes buffered log entries to their writers and syncs data. Only affects adapters implementing FlushableAdapter. Safe for concurrent use.

func (*Logger) Happy added in v0.5.0

func (l *Logger) Happy(msg string, args ...any)

Happy logs a message at the Happy SDK "happy" level.

func (*Logger) HappyContext added in v0.6.0

func (l *Logger) HappyContext(ctx context.Context, msg string, args ...any)

HappyContext logs a message at the Happy SDK "happy" level with context.

func (*Logger) Level

func (l *Logger) Level() Level

func (*Logger) LogDepth

func (l *Logger) LogDepth(depth int, lvl Level, msg string, attrs ...slog.Attr) error

LogDepth logs a message with additional context at a given depth. The depth is the number of stack frames to ascend when logging the message. It is useful only when AddSource is enabled.

func (*Logger) NotImpl added in v0.5.0

func (l *Logger) NotImpl(msg string, args ...any)

NotImpl logs a message at the NotImpl level, for unimplemented features.

func (*Logger) NotImplContext added in v0.6.0

func (l *Logger) NotImplContext(ctx context.Context, msg string, args ...any)

NotImplContext logs a message at the NotImpl level with context.

func (*Logger) NotImplemented

func (l *Logger) NotImplemented(msg string, args ...any)

NotImplemented is an alias for NotImpl.

func (*Logger) NotImplementedContext added in v0.6.0

func (l *Logger) NotImplementedContext(ctx context.Context, msg string, args ...any)

NotImplementedContext is an alias for NotImplContext.

func (*Logger) Notice

func (l *Logger) Notice(msg string, args ...any)

Notice logs a message at the notice level.

func (*Logger) NoticeContext added in v0.6.0

func (l *Logger) NoticeContext(ctx context.Context, msg string, args ...any)

NoticeContext logs a message at the notice level with context.

func (*Logger) Out added in v0.5.0

func (l *Logger) Out(msg string, args ...any)

Out logs a message at the Out level, intended for stdout/stderr style output.

func (*Logger) OutContext added in v0.6.0

func (l *Logger) OutContext(ctx context.Context, msg string, args ...any)

OutContext logs a message at the Out level with context.

func (*Logger) SetLevel

func (l *Logger) SetLevel(level Level)

SetLevel updates the logger's minimum log level dynamically, affecting all adapters.

func (*Logger) Success added in v0.5.0

func (l *Logger) Success(msg string, args ...any)

Success logs a message at the success level.

func (*Logger) SuccessContext added in v0.6.0

func (l *Logger) SuccessContext(ctx context.Context, msg string, args ...any)

SuccessContext logs a message at the success level with context.

func (*Logger) Trace added in v0.5.0

func (l *Logger) Trace(msg string, args ...any)

Trace logs a message at the trace level.

func (*Logger) TraceContext added in v0.6.0

func (l *Logger) TraceContext(ctx context.Context, msg string, args ...any)

TraceContext logs a message at the trace level with context.

type QueueLogger

type QueueLogger struct {
	*slog.Logger
	// contains filtered or unexported fields
}

QueueLogger is a lightweight, slog-compatible logger that queues log records in a ring buffer with a Block policy, ensuring no logs are lost. It collects records without writing them until drained via Consume into a configured Logger. It can be set as slog.Default and reused after consumption.

Usage:

queue := NewQueueLogger(1024) // ~0.7 MiB for 1024 records
queue.Info("early log", "key", "value")
config := DefaultConfig()
logger := New(config, NewBufferedTextAdapter(os.Stdout, nil))
logger.Consume(queue) // Drain queued records to logger
defer logger.Dispose()

func NewQueueLogger

func NewQueueLogger(size int) *QueueLogger

NewQueueLogger creates a QueueLogger with the given buffer size (~0.7 MiB for 1024). The Block policy ensures no records are lost. Size must be a power of two.

func (*QueueLogger) Consume

func (ql *QueueLogger) Consume(queue *QueueLogger) (int, error)

Consume drains all queued records into the target Logger. Call *QueueLogger Dispose dont want to use it anymore to release intrnal BufferAdapter It returns the number of records consumed and any error encountered.

func (*QueueLogger) Dispose added in v0.2.0

func (ql *QueueLogger) Dispose() error

func (*QueueLogger) LogDepth

func (ql *QueueLogger) LogDepth(depth int, lvl Level, msg string, attrs ...slog.Attr) error

LogDepth logs a message with additional context at a given depth. The depth is the number of stack frames to ascend when logging the message. It is useful only when AddSource is enabled.

func (*QueueLogger) Records added in v0.3.0

func (ql *QueueLogger) Records() []Record

type Record added in v0.3.0

type Record struct {
	Ctx    context.Context
	Record slog.Record
	// contains filtered or unexported fields
}

type ReplaceAttrFunc added in v0.3.0

type ReplaceAttrFunc func(groups []string, a slog.Attr) slog.Attr

ReplaceAttrFunc transforms a slog.Attr, optionally considering group context.

func ReplaceAttrDefault added in v0.3.0

func ReplaceAttrDefault(timeLocation *time.Location, timeFormat string) ReplaceAttrFunc

ReplaceAttrDefault transforms level and time attributes for slog handlers. It converts levels to custom strings and formats times based on Config.

func ReplaceAttrOmit added in v0.3.0

func ReplaceAttrOmit(omit []string) ReplaceAttrFunc

ReplaceAttrOmit creates a ReplaceAttrFunc to omit specified attribute keys.

func ReplaceAttrSecrets added in v0.3.0

func ReplaceAttrSecrets(secrets []string) ReplaceAttrFunc

ReplaceAttrSecrets creates a ReplaceAttrFunc to redact specified attribute keys.

func ReplaceAttrTime added in v0.3.0

func ReplaceAttrTime(timeLocation *time.Location, timeFormat string) ReplaceAttrFunc

ReplaceAttrTime creates a ReplaceAttrFunc to format time attributes.

type Writer added in v0.3.0

type Writer struct {
	// contains filtered or unexported fields
}

Writer wraps an io.Writer with atomic updates for safe concurrent use. It supports swapping writers and implements io.Closer to close the underlying writer. The Writer takes ownership of the provided writer, closing it when swapped or adapter is disposed, except for os.Stdout and os.Stderr, which are not closed.

func NewWriter added in v0.3.0

func NewWriter(w io.Writer) *Writer

NewWriter creates a Writer wrapping the given io.Writer, taking ownership. The wrapped writer will be closed when the Writer is closed or swapped, unless it is os.Stdout or os.Stderr.

func (*Writer) Close added in v0.3.0

func (w *Writer) Close() error

Close closes the current writer if it implements io.Closer. os.Stdout and os.Stderr are not closed. Safe for concurrent use.

func (*Writer) Get added in v0.3.0

func (w *Writer) Get() io.Writer

Get returns the current writer. Safe for concurrent access.

func (*Writer) Swap added in v0.3.0

func (w *Writer) Swap(new io.Writer) error

Swap replaces the current writer with a new one, closing the old writer. os.Stdout and os.Stderr are not closed. Returns any error from closing.

func (*Writer) Write added in v0.3.0

func (w *Writer) Write(p []byte) (n int, err error)

Write writes p to the current writer, ensuring thread-safe access. If the writer does not implement sync.Locker, a mutex guards the write. Returns ErrWriterIO wrapping any I/O error from the underlying writer.

Directories

Path Synopsis
Package adapters provides adapters for various logging systems.
Package adapters provides adapters for various logging systems.
console module
Package internal contains experimental and undecided APIs for the logging package.
Package internal contains experimental and undecided APIs for the logging package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL