blip

package module
v0.0.0-...-0c4e18e Latest Latest
Warning

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

Go to latest
Published: Sep 15, 2025 License: MIT Imports: 13 Imported by: 0

README

Blip

Blip is a high-performance, generic logging library for Go. It is designed to be fast, allocation-free, and simple to use, without compromising on performance or relying on hacks.

log.Info("Callback received", log.F{
	"device_unique_id": "G4000E-1000-F",
	"task_id":          123456,
	"status":           "success",
	"template_name":    "index.tpl",
})
Demo

Blip does not provide Printf-like methods, instead it encourages the use of fields. Fields are defined as a map, making it look nicely indented with gofmt. There is also a standardized helper for the error type: log.Cause(err).

log.Error("Failed to process task", log.Cause(err), log.F{
	"task_id": 123456,
})

The use of map[string]any to define fields is optimized by the compiler and avoids stressing the garbage collector thanks to memory pooling, making it an ergonomic and worry-free way to log values without concern for their types.

Context

Fields can be added to context allowing them to be propagated along with it. Such fields will be logged with every message.

ctx := context.Background()
ctx = log.ContextWithFields(ctx, log.F{
	"task_id": task.ID,
})

if err := runTask(ctx, task); err != nil {
	log.Error(ctx, "Task failed", log.Cause(err))
}

Use

Blip offers both an instance-based API and a package-level API. In fact, two package-level variants: one with context, one without. These can be used directly or copied into a project as a template for a custom logging package.

Instance Based
import "github.com/localhots/blip"

ctx := context.Background()
logger := blip.New(blip.DefaultConfig())
logger.Info(ctx, "Callback received", log.F{
	"task_id": 123456,
})
With Context
import "github.com/localhots/blip/ctx/log"

ctx := context.Background()
log.Info(ctx, "Callback received", log.F{
	"task_id": 123456,
})
Without Context
import "github.com/localhots/blip/noctx/log"

log.Info("Callback received", log.F{
	"task_id": 123456,
})

Configuration

The logger can be configured with:

  • Level — minimum logging level (Info by default)
  • Output — log destination (stderr by default)
  • Encoder — console, JSON, or a custom encoder (console by default)
  • StackTraceLevel — minimum level at which stack traces are logged (Panic by default)

Blip includes two built-in encoders: console and JSON, both are further customizable.

Console Encoder
  • TimeFormat
  • TimePrecision — when positive, caches timestamps until they change by the given amount
  • MinMessageWidth — controls padding between the message and fields
  • SortFields — enables sorting of fields
  • Color — enables color and bold text for messages

Fields are sorted using insertion sort, which is highly efficient for small collections.

JSON Encoder
  • TimeFormat
  • TimePrecision — same behavior as in the console encoder
  • Base64Encoding — customizes how byte slices are base64-encoded
  • KeyTime, KeyLevel, KeyMsg, KeyStackTrace — controls the JSON keys for corresponding values

Performance

Blip makes a few intentional compromises in favor of ergonomics and developer productivity: fields are passed as a map, and reflection is used instead of specialized functions to log field values. However, it mitigates most drawbacks through memory pooling for both messages and fields, and by caching timestamps to avoid expensive time serialization.

Overall, if developer productivity matters more than chasing the absolute lowest latency, and a slight performance tradeoff per log call isn't that critical, Blip might be the right choice.

Comparison to Other Loggers

While it's impossible to make a perfectly fair comparison, here are a few notes on how Blip fares against other popular logging libraries.

The main motivation behind Blip was to build a logger that is nicer than Logrus and is as fast as Zerolog.

log/slog

Slog is a structured logger introduced in Go 1.21. It accepts fields as variadic any arguments or as typed attributes, and supports both console and JSON encoders. It's allocation-free, fast (still ~2x slower than Blip) but not particularly pretty.

zerolog

Zerolog is an excellent logger and among the fastest available. Its performance comes from using typed functions to provide fields efficiently. When used as intended, Zerolog is roughly 25% faster than Blip.

However, if the Any method is used instead of Str, Int, and other typed functions, it starts allocating memory and falls behind, performing about twice as slow as Blip.

In pretty mode, Zerolog first encodes messages as JSON, then parses and re-formats them for console output, which absolutely tanks its performance compared to the competition. Clearly an afterthought.

zap

Zap is reasonably fast but doesn't offer a true pretty mode. It achieves most of its performance gains through message sampling. With sampling disabled, its performance drops and it becomes much slower than Blip in all use cases.

logrus

Logrus offers some of the nicest console formatting and was a major inspiration for Blip's console encoder. Unfortunately, it doesn't perform well, and active development has effectively stopped.

phuslog

Phuslog appears to be the absolute fastest logger available. It employs a lot of complex low-level code to achieve its performance, demonstrating the significant effort that went into it.

One reason for its speed is its highly optimized time serialization. Unfortunately, it accomplishes this by linking to unexported functions from the time package, which has caused some grief for the Go language developers.

Documentation

Overview

Package blip provides a simple and efficient logging library. It is designed to be easy to use and flexible, allowing to customize the logging output format, level, and other settings. It supports JSON and console output formats and provides an inteface for custom encoders.

Index

Constants

This section is empty.

Variables

View Source
var (

	// DurationFieldPrecision controls how duration values are truncated when
	// logged.
	DurationFieldPrecision = time.Millisecond
	// TimeFieldFormat controls the format used for time field values. Log entry
	// timestamps are configured with the TimeFieldFormat field in the Config
	// struct.
	TimeFieldFormat = time.RFC3339
)

Functions

func ContextWithFields

func ContextWithFields(ctx context.Context, fields F) context.Context

ContextWithFields adds fields to the context. If the context already has fields, it merges the new fields with the existing ones.

Types

type Buffer

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

Buffer is a byte buffer used for encoding log entries. WARNING: Buffer should not be initialized manually. It is pooled to reduce allocations.

func (*Buffer) Write

func (buf *Buffer) Write(b []byte) (int, error)

Write implements the io.Writer interface.

func (*Buffer) WriteBase64

func (buf *Buffer) WriteBase64(b64enc *base64.Encoding, data []byte)

WriteBase64 writes a byte slice to the buffer as a base64-encoded string.

func (*Buffer) WriteBool

func (buf *Buffer) WriteBool(b bool)

WriteBool writes a boolean value to the buffer.

func (*Buffer) WriteBytes

func (buf *Buffer) WriteBytes(b ...byte)

WriteBytes writes a byte slice to the buffer.

func (*Buffer) WriteDuration

func (buf *Buffer) WriteDuration(d time.Duration)

WriteDuration writes a time.Duration value to the buffer.

func (*Buffer) WriteEscapedString

func (buf *Buffer) WriteEscapedString(str string)

WriteEscapedString writes a string to the buffer, escaping special characters as needed. It handles both ASCII and Unicode characters. The string is enclosed in double quotes.

func (*Buffer) WriteFloat

func (buf *Buffer) WriteFloat(f float64, bitSize int)

WriteFloat writes a float64 value to the buffer with the specified bit size.

func (*Buffer) WriteInt

func (buf *Buffer) WriteInt(i int64)

WriteInt writes an int64 value to the buffer.

func (*Buffer) WriteRune

func (buf *Buffer) WriteRune(r rune)

WriteRune writes a rune to the buffer. It encodes the rune as UTF-8.

func (*Buffer) WriteString

func (buf *Buffer) WriteString(str string)

WriteString writes a string to the buffer.

func (*Buffer) WriteTime

func (buf *Buffer) WriteTime(t time.Time, format string)

WriteTime writes a time.Time value to the buffer using the specified format.

func (*Buffer) WriteUint

func (buf *Buffer) WriteUint(i uint64)

WriteUint writes a uint64 value to the buffer.

type Config

type Config struct {
	Level           Level
	Output          io.Writer
	Encoder         Encoder
	StackTraceLevel Level
	StackTraceSkip  int
}

Config is the configuration structure for the logger.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a default configuration for the logger.

type ConsoleEncoder

type ConsoleEncoder struct {
	TimeFormat      string
	TimePrecision   time.Duration
	MinMessageWidth int
	SortFields      bool
	Color           bool
	// contains filtered or unexported fields
}

ConsoleEncoder is a console encoder that formats log messages in a human-readable format.

func NewConsoleEncoder

func NewConsoleEncoder() *ConsoleEncoder

NewConsoleEncoder creates a new console encoder with the given configuration. The encoder formats log messages in a human-readable format, with colorized levels and optional field sorting. The encoder also supports a minimum message width for padding.

func (*ConsoleEncoder) EncodeFields

func (e *ConsoleEncoder) EncodeFields(buf *Buffer, lev Level, fields *[]Field)

EncodeFields encodes the fields of the log message.

func (*ConsoleEncoder) EncodeLevel

func (e *ConsoleEncoder) EncodeLevel(buf *Buffer, lev Level)

EncodeLevel encodes the log level of the message.

func (*ConsoleEncoder) EncodeMessage

func (e *ConsoleEncoder) EncodeMessage(buf *Buffer, msg string)

EncodeMessage encodes the log message.

func (*ConsoleEncoder) EncodeStackTrace

func (e *ConsoleEncoder) EncodeStackTrace(buf *Buffer, skip int)

EncodeStackTrace encodes the stack trace of the log message.

func (*ConsoleEncoder) EncodeTime

func (e *ConsoleEncoder) EncodeTime(buf *Buffer)

EncodeTime encodes the time of the log message.

func (*ConsoleEncoder) End

func (e *ConsoleEncoder) End(buf *Buffer)

End writes the end of the log message.

func (*ConsoleEncoder) Start

func (e *ConsoleEncoder) Start(_ *Buffer)

Start writes the beginning of the log message.

type Encoder

type Encoder interface {
	// Start writes the beginning of the log message.
	Start(buf *Buffer)
	// EncodeTime encodes the time of the log message.
	EncodeTime(buf *Buffer)
	// EncodeLevel encodes the log level of the message.
	EncodeLevel(buf *Buffer, lev Level)
	// EncodeMessage encodes the log message.
	EncodeMessage(buf *Buffer, msg string)
	// EncodeFields encodes the fields of the log message.
	EncodeFields(buf *Buffer, lev Level, fields *[]Field)
	// EncodeStackTrace encodes the stack trace of the log message.
	EncodeStackTrace(buf *Buffer, skip int)
	// End writes the end of the log message.
	End(buf *Buffer)
}

Encoder is an interface for encoding log messages.

type F

type F map[string]any

F is a convenient alias for a map of fields.

func FieldsFromContext

func FieldsFromContext(ctx context.Context) F

FieldsFromContext retrieves fields from the context. If no fields are found, it returns nil.

type Field

type Field struct {
	Key   string
	Value any
}

Field is a key-value pair that is used to add structured data to log entries.

type JSONEncoder

type JSONEncoder struct {
	TimeFormat     string
	TimePrecision  time.Duration
	Base64Encoding *base64.Encoding
	KeyTime        string
	KeyLevel       string
	KeyMessage     string
	KeyStackTrace  string
	// contains filtered or unexported fields
}

JSONEncoder is an encoder that encodes log messages in JSON format.

func NewJSONEncoder

func NewJSONEncoder() *JSONEncoder

NewJSONEncoder creates a new JSON encoder with the given configuration. The encoder formats log messages in JSON format, with optional and fields.

func (*JSONEncoder) EncodeFields

func (e *JSONEncoder) EncodeFields(buf *Buffer, _ Level, fields *[]Field)

EncodeFields encodes the fields of the log message.

func (*JSONEncoder) EncodeLevel

func (e *JSONEncoder) EncodeLevel(buf *Buffer, lev Level)

EncodeLevel encodes the log level of the message.

func (*JSONEncoder) EncodeMessage

func (e *JSONEncoder) EncodeMessage(buf *Buffer, msg string)

EncodeMessage encodes the log message.

func (*JSONEncoder) EncodeStackTrace

func (e *JSONEncoder) EncodeStackTrace(buf *Buffer, skip int)

EncodeStackTrace encodes the stack trace of the log message.

func (*JSONEncoder) EncodeTime

func (e *JSONEncoder) EncodeTime(buf *Buffer)

EncodeTime encodes the time of the log message.

func (*JSONEncoder) End

func (e *JSONEncoder) End(buf *Buffer)

End writes the end of the log message.

func (*JSONEncoder) Start

func (e *JSONEncoder) Start(buf *Buffer)

Start writes the beginning of the log message.

type Level

type Level int

Level is the log level type.

const (
	LevelTrace Level = iota + 1
	LevelDebug
	LevelInfo
	LevelWarn
	LevelError
	LevelPanic
	LevelFatal
)

Supported log levels.

type Logger

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

Logger is a the main structure used to log messages.

func New

func New(cfg Config) *Logger

New creates a new Logger instance with the given configuration.

func (*Logger) Debug

func (l *Logger) Debug(ctx context.Context, msg string, fields ...F)

Debug is used to log a message at the Debug level.

func (*Logger) Error

func (l *Logger) Error(ctx context.Context, msg string, fields ...F)

Error is used to log a message at the Error level.

func (*Logger) Fatal

func (l *Logger) Fatal(ctx context.Context, msg string, fields ...F)

Fatal is used to log a message at the Fatal level and exit the program.

func (*Logger) Info

func (l *Logger) Info(ctx context.Context, msg string, fields ...F)

Info is used to log a message at the Info level.

func (*Logger) Panic

func (l *Logger) Panic(ctx context.Context, msg string, fields ...F)

Panic is used to log a message at the Panic level.

func (*Logger) Trace

func (l *Logger) Trace(ctx context.Context, msg string, fields ...F)

Trace is used to log a message at the Trace level.

func (*Logger) Warn

func (l *Logger) Warn(ctx context.Context, msg string, fields ...F)

Warn is used to log a message at the Warn level.

Directories

Path Synopsis
cmd
demo command
Package main is a demo application for the blip logger.
Package main is a demo application for the blip logger.
pprof command
Package main enables CPU profiling and logs 10M entries.
Package main enables CPU profiling and logs 10M entries.
ctx
log
Package log provides a shim for the blip logger, allowing to use it with context.
Package log provides a shim for the blip logger, allowing to use it with context.
noctx
log
Package log provides a shim for the blip logger, allowing to use it without context.
Package log provides a shim for the blip logger, allowing to use it without context.

Jump to

Keyboard shortcuts

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