birch/handler/json
JSON handler for structured log output.
Outputs log records as JSON objects, suitable for log aggregation systems.
This module supports two usage patterns:
-
Simple usage with default format:
let handler = json.handler() -
Builder pattern for custom JSON format:
let custom_handler = json.standard_builder() |> json.add_custom(fn(_) { [#("service", json.string("my-app"))] }) |> json.build() |> json.handler_with_formatter()
Types
A field extractor function that takes a LogRecord and returns JSON fields.
pub type FieldExtractor =
fn(record.LogRecord) -> List(#(String, json.Json))
Builder for customizing JSON output format. Accumulates field extractors that are applied when formatting a log record.
pub opaque type JsonBuilder
Values
pub fn add_custom(
b: JsonBuilder,
extractor: fn(record.LogRecord) -> List(#(String, json.Json)),
) -> JsonBuilder
Add custom fields to the JSON output. The extractor function receives the LogRecord and returns a list of JSON fields.
Example:
json.standard_builder()
|> json.add_custom(fn(_record) {
[
#("service", json.string("my-app")),
#("version", json.string("1.0.0")),
]
})
pub fn add_field(
builder: JsonBuilder,
extractor: fn(record.LogRecord) -> List(#(String, json.Json)),
) -> JsonBuilder
Add a field extractor to the builder. This is a low-level function; prefer using specific add_* functions.
pub fn add_level(b: JsonBuilder) -> JsonBuilder
Add the log level field to the JSON output.
Output: "level": "info"
pub fn add_logger(b: JsonBuilder) -> JsonBuilder
Add the logger name field to the JSON output.
Output: "logger": "myapp.http"
pub fn add_message(b: JsonBuilder) -> JsonBuilder
Add the message field to the JSON output.
Output: "message": "Request complete"
pub fn add_metadata(b: JsonBuilder) -> JsonBuilder
Add all metadata fields to the JSON output.
Each metadata key-value pair becomes a JSON field.
Output: "method": "POST", "path": "/api/users"
pub fn add_timestamp(b: JsonBuilder) -> JsonBuilder
Add the timestamp field to the JSON output.
Output: "timestamp": "2024-12-26T10:30:45.123Z"
pub fn build(b: JsonBuilder) -> fn(record.LogRecord) -> String
Build a formatter from the builder.
The formatter can be used with handler_with_formatter to create a handler.
pub fn builder() -> JsonBuilder
Create a new empty JSON builder. Use this as a starting point to add custom fields.
Example:
let formatter =
json.builder()
|> json.add_timestamp()
|> json.add_level()
|> json.add_message()
|> json.build()
pub fn format_json(record: record.LogRecord) -> String
Format a log record as a JSON string using the default format.
This is equivalent to using standard_builder() |> build().
pub fn handler() -> handler.Handler
Create a JSON console handler with the default format. Outputs JSON-formatted log records to stdout.
Default JSON format includes: timestamp, level, logger, message, and metadata.
pub fn handler_stderr() -> handler.Handler
Create a JSON handler that writes to stderr with the default format.
pub fn handler_stderr_with_formatter(
format: fn(record.LogRecord) -> String,
) -> handler.Handler
Create a JSON handler with a custom formatter that writes to stderr.
pub fn handler_with_formatter(
format: fn(record.LogRecord) -> String,
) -> handler.Handler
Create a JSON handler with a custom formatter. Outputs to stdout.
Example:
let custom_handler =
json.standard_builder()
|> json.add_custom(fn(_) { [#("service", json.string("my-app"))] })
|> json.build()
|> json.handler_with_formatter()
pub fn standard_builder() -> JsonBuilder
Create a standard JSON builder with all common fields. This includes: timestamp, level, logger, message, and metadata.
Use this as a starting point and add custom fields:
json.standard_builder()
|> json.add_custom(fn(_) { [#("env", json.string("production"))] })
|> json.build()
|> json.handler_with_formatter()