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:

  1. Simple usage with default format:

    let handler = json.handler()
    
  2. 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()
Search Document