Configuration
Logit is configured using the Logit.configure block. This guide covers all configuration options.
Backends
Backends determine where log events are sent. Logit includes two built-in backends.
Console Backend
Writes to STDOUT with colorized, human-readable output:
Options:
| Parameter | Type | Default | Description |
|---|---|---|---|
level |
LogLevel |
Info |
Minimum log level |
formatter |
Formatter |
Human |
Output formatter |
buffered |
Bool |
false |
Buffer output (improves performance) |
File Backend
Writes to a file with JSON output (for log aggregation):
Options:
| Parameter | Type | Default | Description |
|---|---|---|---|
path |
String |
required | Path to log file |
level |
LogLevel |
Info |
Minimum log level |
buffered |
Bool |
true |
Buffer output |
Security features:
- Files created with mode
0o600(owner read/write only) - Symlinks not followed by default
- Parent directory must exist
OTLP Backend
Exports logs to an OpenTelemetry collector via OTLP/HTTP (JSON):
Logit.configure do |config|
config.otlp(
"http://localhost:4318/v1/logs",
resource_attributes: {"service.name" => "my-app"}
)
end
Options:
| Parameter | Type | Default | Description |
|---|---|---|---|
endpoint |
String |
required | OTLP HTTP endpoint URL |
level |
LogLevel |
Info |
Minimum log level |
batch_size |
Int32 |
512 |
Max events per batch |
flush_interval |
Time::Span |
5.seconds |
Time between flushes |
headers |
Hash(String, String) |
{} |
HTTP headers (for auth) |
timeout |
Time::Span |
30.seconds |
HTTP request timeout |
resource_attributes |
Hash(String, String) |
{} |
Resource attributes |
With authentication:
Logit.configure do |config|
config.otlp(
"https://otlp.example.com/v1/logs",
headers: {"Authorization" => "Bearer #{ENV["OTLP_TOKEN"]}"},
resource_attributes: {
"service.name" => "my-app",
"service.version" => "1.0.0",
"deployment.environment" => "production"
}
)
end
The OTLP backend batches events and flushes them either when the batch size is reached or the flush interval elapses. Failed batches are logged to STDERR and dropped (no retry queue).
Multiple Backends
Use multiple backends simultaneously:
Logit.configure do |config|
# Human-readable for development
config.console(level: Logit::LogLevel::Debug)
# JSON for production log aggregation
config.file("logs/app.log", level: Logit::LogLevel::Info)
end
Formatters
Formatters control how events are rendered as text.
Human Formatter (Default for Console)
Colorized, compact format for terminal viewing:
Color coding:
- TRACE: White
- DEBUG: Cyan
- INFO: Green
- WARN: Yellow
- ERROR: Red
- FATAL: Magenta
JSON Formatter (Default for File)
Structured JSON following OpenTelemetry conventions:
{
"trace_id": "abc123...",
"span_id": "def456...",
"timestamp": "2024-01-15T10:30:00.000000Z",
"duration_ms": 42,
"name": "find_user",
"level": "info",
"status": "ok",
"code": {
"file": "user_service.cr",
"line": 15,
"function": "find_user",
"namespace": "UserService"
},
"attributes": {...}
}
Custom Formatter
Create your own by subclassing Formatter:
class MyFormatter < Logit::Formatter
def format(event : Logit::Event) : String
"[#{event.level.to_s.upcase}] #{event.class_name}##{event.method_name}"
end
end
Logit.configure do |config|
config.console(formatter: MyFormatter.new)
end
Log Levels
Log levels from least to most severe:
| Level | Value | Description |
|---|---|---|
Trace |
0 | Very detailed debugging |
Debug |
1 | Development debugging |
Info |
2 | General operational info (default) |
Warn |
3 | Warning conditions |
Error |
4 | Error conditions |
Fatal |
5 | Severe/fatal errors |
Events are only logged if their level is >= the backend's configured level.
# Parse from string
level = Logit::LogLevel.parse("debug") # => LogLevel::Debug
# Compare levels
Logit::LogLevel::Warn > Logit::LogLevel::Info # => true
Namespace Filtering
Control log levels per-namespace using patterns:
Logit.configure do |config|
console = config.console(level: Logit::LogLevel::Info)
# Reduce noise from database classes
config.bind("MyApp::Database::*", Logit::LogLevel::Warn, console)
# But keep debug for query builder
config.bind("MyApp::Database::QueryBuilder", Logit::LogLevel::Debug, console)
end
Pattern Syntax
| Pattern | Matches |
|---|---|
MyApp::User |
Exactly MyApp::User |
MyApp::* |
MyApp::User, MyApp::Order (direct children) |
MyApp::** |
MyApp::User, MyApp::DB::Query (all descendants) |
More specific patterns take precedence over less specific ones.
Per-Backend Bindings
Different backends can have different namespace rules:
Logit.configure do |config|
console = config.console(level: Logit::LogLevel::Info)
file = config.file("logs/debug.log", level: Logit::LogLevel::Debug)
# Console: only warnings from DB
config.bind("MyApp::DB::*", Logit::LogLevel::Warn, console)
# File: full debug from DB
config.bind("MyApp::DB::*", Logit::LogLevel::Debug, file)
end
Redaction
Prevent sensitive data from appearing in logs.
Global Patterns
Add patterns that apply to all methods:
Logit.configure do |config|
config.console
# Enable common patterns (password, token, api_key, etc.)
config.redact_common_patterns
# Add custom patterns
config.redact_patterns(/ssn/i, /credit_card/i)
end
Per-Method Redaction
Redact specific arguments:
@[Logit::Log(redact: ["password", "pin"])]
def authenticate(username : String, password : String, pin : String) : Bool
# password and pin appear as [REDACTED]
end
Complete Example
require "logit"
Logit.configure do |config|
# Console for development
console = config.console(
level: Logit::LogLevel::Debug,
formatter: Logit::Formatter::Human.new
)
# JSON file for production
file = config.file(
"logs/app.log",
level: Logit::LogLevel::Info
)
# Namespace filtering
config.bind("MyApp::Database::*", Logit::LogLevel::Warn, console)
config.bind("MyApp::HTTP::*", Logit::LogLevel::Debug, file)
# Redaction
config.redact_common_patterns
config.redact_patterns(/ssn/i)
end
Next Steps
- Advanced Usage - Context and custom attributes
- API Reference - Complete API documentation