NLog

module
v0.1.0-pre Latest Latest
Warning

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

Go to latest
Published: Feb 18, 2026 License: MIT

README

Go Logging Framework

A lightweight, high-performance structured logging framework for Go with zero-allocation optimizations, async processing, and flexible configuration.

The framework is designed around immutable logger instances using the Builder pattern, making it inherently thread-safe. Logging is async by default with configurable overflow policies, and the hot path achieves zero allocations.

Installation

go get github.com/Philipp01105/logging-framework

Requires Go 1.22 or later.

Example

The simplest way to use the framework is the package-level default logger:

package main

import (
	"github.com/Philipp01105/logging-framework/logger"
)

func main() {
	logger.Info("Application started")
	logger.Info("User login",
		logger.String("username", "alice"),
		logger.Int("user_id", 123),
	)
}

For more advanced usage, create a custom logger instance with the Builder:

package main

import (
	"github.com/Philipp01105/logging-framework/formatter"
	"github.com/Philipp01105/logging-framework/handler"
	"github.com/Philipp01105/logging-framework/logger"
)

func main() {
	consoleHandler := handler.NewConsoleHandler(handler.ConsoleConfig{
		Async:      true,
		BufferSize: 1000,
		Formatter: formatter.NewTextFormatter(formatter.Config{
			IncludeCaller: true,
		}),
	})

	myLogger := logger.NewBuilder().
		WithHandler(consoleHandler).
		WithLevel(logger.DebugLevel).
		WithCaller(true).
		WithFields(logger.String("service", "api")).
		Build()

	myLogger.Debug("Debug message with caller info")
	myLogger.Info("Info message", logger.Int("count", 42))
}

With formatter.NewJSONFormatter, for easy parsing by logstash or Splunk:

{"level":"INFO","message":"JSON formatted log","response_time":0.123,"service":"api","time":"2026-02-18T13:00:00Z","timestamp":"2026-02-18T13:00:00Z"}
Fields

The framework encourages structured logging through type-safe field constructors instead of format strings:

logger.Info("User action",
	logger.String("username", "alice"),
	logger.Int("age", 30),
	logger.Int64("user_id", 123456789),
	logger.Float64("score", 98.5),
	logger.Bool("admin", true),
	logger.Time("login_time", time.Now()),
	logger.Duration("elapsed", 5*time.Second),
	logger.Err(err),
	logger.Any("custom", customObject),
)
Default Fields

Often it's helpful to have fields always attached to log statements in an application or parts of one. Instead of repeating fields on every line, use With() to create a child logger with persistent context (immutable operation):

requestLogger := logger.With(
	logger.String("request_id", "req-12345"),
	logger.String("method", "GET"),
)

requestLogger.Info("Processing request", logger.String("path", "/api/users"))
requestLogger.Info("Request completed", logger.Int("status", 200))
Logging Method Name

If you wish to add the calling method as a field, enable caller reporting:

myLogger := logger.NewBuilder().
	WithCaller(true).
	Build()

Note that this does add measurable overhead.

Level Logging

The framework has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.

logger.Debug("Useful debugging information.")
logger.Info("Something noteworthy happened!")
logger.Warn("You should probably take a look at this.")
logger.Error("Something failed but I'm not quitting.")
// Calls os.Exit(1) after logging
logger.Fatal("Bye.")
// Calls panic() after logging
logger.Panic("I'm bailing.")

You can set the logging level on a Logger, then it will only log entries with that severity or anything above it:

myLogger := logger.NewBuilder().
	WithLevel(logger.InfoLevel). // Default. Will log Info and above.
	Build()
Formatters

The built-in logging formatters are:

  • formatter.NewTextFormatter — Human-readable text output with optional caller info.
  • formatter.NewJSONFormatter — Logs fields as JSON.

Both formatters support the zero-copy WriterFormatter interface for zero-allocation formatting.

You can define your own formatter by implementing the Formatter interface.

Handlers

The framework ships with multiple handler implementations:

  • ConsoleHandler — Writes to stdout/stderr. Async by default.
  • FileHandler — Writes to files with built-in rotation (by size, age, or interval).
  • MultiHandler — Fan-out to multiple handlers simultaneously.
  • SlogHandler — Drop-in slog.Handler adapter for log/slog compatibility.
consoleHandler := handler.NewConsoleHandler(handler.ConsoleConfig{Async: true})

fileHandler, _ := handler.NewFileHandler(handler.FileConfig{
	Filename: "/var/log/app.log",
	Async:    true,
})

multiHandler := handler.NewMultiHandler(consoleHandler, fileHandler)

myLogger := logger.NewBuilder().
	WithHandler(multiHandler).
	Build()

myLogger.Info("This goes to both console and file")
Synchronous Logging

Async is the default. To opt out, disable it per handler:

syncHandler := handler.NewConsoleHandler(handler.ConsoleConfig{
	Async: false,
})
File Rotation

Unlike many logging libraries, file rotation is built-in. Multiple rotation triggers and backup management are supported:

handler.NewFileHandler(handler.FileConfig{
	Filename:       "/var/log/app.log",
	MaxSize:        100 * 1024 * 1024,   // Rotate at 100MB
	MaxAge:         7 * 24 * time.Hour,   // Rotate after 7 days
	RotateInterval: 24 * time.Hour,       // Also rotate daily
	MaxBackups:     30,                    // Keep 30 old files
})
Overflow Policies

Control what happens when async queues fill up:

h := handler.NewConsoleHandler(handler.ConsoleConfig{
	OverflowPolicy: map[core.Level]handler.OverflowPolicy{
		core.DebugLevel: handler.DropNewest,
		core.ErrorLevel: handler.Block,
	},
	BlockTimeout: 100 * time.Millisecond,
	DrainTimeout: 5 * time.Second,
})

Available policies:

  • DropNewest — Drop incoming log entry (default for DEBUG/INFO/WARN)
  • DropOldest — Remove oldest entry from queue
  • Block — Block caller with timeout, fallback to sync write (default for ERROR)
Telemetry

Monitor logging behavior in real-time to detect slow I/O, tune buffer sizes, and observe application load:

stats := handler.Stats()
fmt.Printf("Processed: %d\n", stats.ProcessedTotal)
fmt.Printf("Dropped: %d\n", stats.DroppedTotal[core.InfoLevel])
fmt.Printf("Blocked: %d\n", stats.BlockedTotal)
log/slog Compatibility

The framework provides a drop-in slog.Handler adapter for seamless integration with Go's standard log/slog package:

package main

import (
	"log/slog"

	"github.com/Philipp01105/NLog/core"
	"github.com/Philipp01105/NLog/formatter"
	"github.com/Philipp01105/NLog/handler"
)

func main() {
	consoleHandler := handler.NewConsoleHandler(handler.ConsoleConfig{
		Async:     false,
		Formatter: formatter.NewTextFormatter(formatter.Config{}),
	})

	slogHandler := handler.NewSlogHandler(consoleHandler, core.InfoLevel)
	logger := slog.New(slogHandler)

	logger.Info("Hello from slog", "user", "alice", "count", 42)
	logger.Warn("Something might be wrong", "component", "auth")

	consoleHandler.Close()
}
Thread Safety

Logger instances are immutable after construction via the Builder pattern, making them inherently safe for concurrent use. Async handlers use bounded queues with configurable overflow policies. Shutdown is handled via an idempotent Close() with timeout-based queue draining.

Performance

The framework achieves zero allocations on the hot path through entry pooling, level-check-before-allocation, and the WriterFormatter zero-copy interface.

BenchmarkInfoNoFields              144 ns/op       0 B/op    0 allocs/op
BenchmarkInfoWith2Fields           202 ns/op       0 B/op    0 allocs/op
BenchmarkJSON                      445 ns/op       0 B/op    0 allocs/op
BenchmarkZeroAllocFiltered         0.3 ns/op       0 B/op    0 allocs/op
BenchmarkFilteredDebug             8.8 ns/op       0 B/op    0 allocs/op
BenchmarkMultiGoroutineContention   29 ns/op       5 B/op    0 allocs/op
BenchmarkQueueFullStress            18 ns/op       0 B/op    0 allocs/op

Filtered logs (level too low) cause zero allocations — the level check happens before GetEntry():

myLogger := logger.NewBuilder().
	WithLevel(logger.InfoLevel).
	Build()

myLogger.Debug("filtered") // 0.3 ns/op, 0 allocs
Package Structure
Package Description
core/ Core types (Entry, Field, Level) shared across packages
logger/ Main Logger API, Builder, and convenience functions
handler/ Handler interface and implementations (Console, File, Multi, SlogHandler)
formatter/ Formatter interface and implementations (Text, JSON, WriterFormatter)
Testing

Run tests:

go test ./...

Run benchmarks:

go test -bench=. -benchmem ./...
License

This project is open source and available under the MIT License.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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