Scriba
A flexible, structured logging library for Go with support for multiple formatters, drivers, and middleware integrations.
Features
- Structured Logging: Add contextual fields to your log entries
- Multiple Log Levels: Debug, Info, Warn, Error, and Fatal
- Flexible Formatters: JSON, Pretty (with customizable themes), and MessagePack
- Pluggable Drivers: Console, OpenTelemetry, and custom drivers
- Chi Integration: Middleware for HTTP request logging and panic recovery
- Context-Aware: Pass context through your application for distributed tracing
- Thread-Safe: Safe for concurrent use
- Zero Dependencies Core: Minimal dependencies in the core library
Installation
go get github.com/ams-tech-fin/scriba
Quick Start
package main
import (
"context"
"errors"
"os"
"github.com/ams-tech-fin/scriba"
"github.com/ams-tech-fin/scriba/driver"
"github.com/ams-tech-fin/scriba/formatter"
)
func main() {
// Create a logger with pretty formatter
logger := scriba.New(
scriba.WithDriver(
driver.NewConsoleDriver(os.Stdout),
formatter.NewPrettyFormatter(),
scriba.LevelDebug,
),
)
ctx := context.Background()
// Log at different levels
logger.Debug(ctx, "Debug message", scriba.F("key", "value"))
logger.Info(ctx, "Application started", scriba.F("port", 8080))
logger.Warn(ctx, "Warning message", scriba.F("threshold", 90))
logger.Error(ctx, "An error occurred", errors.New("example error"))
}
Usage
Creating a Logger
logger := scriba.New(
scriba.WithDriver(
driver.NewConsoleDriver(os.Stdout),
formatter.NewJSONFormatter(),
scriba.LevelInfo,
),
scriba.WithMinLevel(scriba.LevelDebug),
scriba.WithBaseFields(
scriba.F("app", "myapp"),
scriba.F("version", "1.0.0"),
),
)
Log Levels
logger.Debug(ctx, "Debug message")
logger.Info(ctx, "Info message")
logger.Warn(ctx, "Warning message")
logger.Error(ctx, "Error message", err)
logger.Fatal(ctx, "Fatal message", err) // Calls os.Exit(1)
Adding Fields
// Add fields to a single log entry
logger.Info(ctx, "User logged in",
scriba.F("user_id", 12345),
scriba.F("ip", "192.168.1.1"),
)
// Create a child logger with persistent fields
userLogger := logger.WithFields(
scriba.F("user_id", 12345),
scriba.F("session_id", "abc123"),
)
userLogger.Info(ctx, "Action performed") // Will include user_id and session_id
jsonFormatter := formatter.NewJSONFormatter()
Output:
{"time":"2025-12-04T16:00:00Z","level":"INFO","message":"User logged in","fields":{"user_id":12345}}
prettyFormatter := formatter.NewPrettyFormatter()
Output:
[2025-12-04T16:00:00Z] INFO User logged in user_id=12345
theme := formatter.TICDefaultTheme() // Colorful theme using github.com/ams-tech-fin/tic
prettyFormatter := formatter.NewPrettyFormatterWithTheme(theme)
// Disable colors with environment variable
prettyFormatter.DisableColors = os.Getenv("NO_COLOR") == "1"
msgpackFormatter := formatter.NewMsgPackFormatter()
Drivers
Console Driver
consoleDriver := driver.NewConsoleDriver(os.Stdout)
// or
consoleDriver := driver.NewConsoleDriver(os.Stderr)
OpenTelemetry Driver
otelDriver := driver.NewOTELDriver()
Multiple Drivers
You can configure multiple drivers with different formatters and minimum log levels:
logger := scriba.New(
// JSON to stdout for production
scriba.WithDriver(
driver.NewConsoleDriver(os.Stdout),
formatter.NewJSONFormatter(),
scriba.LevelInfo,
),
// Pretty to stderr for debugging
scriba.WithDriver(
driver.NewConsoleDriver(os.Stderr),
formatter.NewPrettyFormatter(),
scriba.LevelDebug,
),
)
Chi Middleware
Request Logger
Log all HTTP requests with detailed information:
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/ams-tech-fin/scriba"
"github.com/ams-tech-fin/scriba/driver"
"github.com/ams-tech-fin/scriba/formatter"
"github.com/ams-tech-fin/scriba/scriba_chi"
)
func main() {
logger := scriba.New(
scriba.WithDriver(
driver.NewConsoleDriver(os.Stdout),
formatter.NewJSONFormatter(),
scriba.LevelInfo,
),
)
r := chi.NewRouter()
// Add request ID middleware (optional but recommended)
r.Use(middleware.RequestID)
// Add Scriba request logger
r.Use(scriba_chi.RequestLogger(logger))
// Add panic recovery
r.Use(scriba_chi.Recoverer(logger))
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
// Access logger from context
log := scriba_chi.FromContext(r.Context())
log.Info(r.Context(), "Handling request")
w.Write([]byte("Hello, World!"))
})
http.ListenAndServe(":8080", r)
}
The request logger automatically logs:
- HTTP method and path
- Host and remote address
- User agent
- Response status code
- Response size in bytes
- Request duration in milliseconds
- Request ID (if using chi's RequestID middleware)
Recoverer Middleware
Automatically recover from panics and log them:
r.Use(scriba_chi.Recoverer(logger))
When a panic occurs, it will:
- Log the panic with stack trace
- Return a 500 Internal Server Error response
- Prevent the server from crashing
Context Logger
Access the request-scoped logger from your handlers:
r.Get("/user/:id", func(w http.ResponseWriter, r *http.Request) {
log := scriba_chi.FromContext(r.Context())
userID := chi.URLParam(r, "id")
log.Info(r.Context(), "Fetching user", scriba.F("user_id", userID))
// Your handler logic here
})
Advanced Usage
Custom Time Function
logger := scriba.New(
scriba.WithNowFunc(func() time.Time {
return time.Now().In(location)
}),
)
Implement the Formatter interface:
type Formatter interface {
Format(entry Entry) ([]byte, error)
}
Custom Driver
Implement the Driver interface:
type Driver interface {
Write(ctx context.Context, entry Entry, formatted []byte) error
}
Examples
See the cmd/demo directory for a basic example and cmd/demo_chi for a Chi integration example.
Run the demos:
# Basic demo
go run cmd/demo/demo.go
# Chi middleware demo
go run cmd/demo_chi/demo_chi.go
License
MIT License - see LICENSE for details
Copyright (c) 2025 AMS Tecnologia e Serviços Financeiros LTDA (AMS Soft)
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.