viva_telemetry/log

viva_telemetry/log - Structured logging for Gleam

Inspired by: structlog (Python), zap (Go), tracing (Rust)

Features

Quick Start

import viva_telemetry/log

pub fn main() {
  // Simple logging
  log.info("Server started", [#("port", "8080")])

  // With context
  log.with_context([#("request_id", "abc123")], fn() {
    log.debug("Processing request", [])
  })
}

Values

pub fn add_handler(handler: handler.Handler) -> Nil

Add a handler to the existing configuration

pub fn alert(
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log at alert level

pub fn alert_lazy(
  message_fn: fn() -> String,
  fields: List(#(String, String)),
) -> Nil

Lazy alert

pub const alert_level: level.Level

Alert level (action must be taken immediately)

pub fn bind_context(context: List(#(String, String))) -> Nil

Add context fields that persist for this process

pub fn clear_context() -> Nil

Clear all context

pub fn configure(handlers: List(handler.Handler)) -> Nil

Configure global handlers

pub fn configure_console(lvl: level.Level) -> Nil

Quick setup: console handler with specified level

Example:

log.configure_console(log.debug_level)
pub fn configure_full(
  console_level: level.Level,
  json_path: String,
  json_level: level.Level,
) -> Nil

Quick setup: console + JSON file

Example:

log.configure_full(log.debug_level, "app.jsonl", log.info_level)
pub fn configure_json(path: String, lvl: level.Level) -> Nil

Quick setup: JSON file handler with specified level

Example:

log.configure_json("app.jsonl", log.info_level)
pub fn critical(
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log at critical level

pub fn critical_lazy(
  message_fn: fn() -> String,
  fields: List(#(String, String)),
) -> Nil

Lazy critical

pub const critical_level: level.Level

Critical level

pub fn debug(
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log at debug level

pub fn debug_lazy(
  message_fn: fn() -> String,
  fields: List(#(String, String)),
) -> Nil

Lazy debug - most common use case for lazy logging

Example:

// String only constructed if debug level is enabled
log.debug_lazy(fn() { "Item: " <> int.to_string(i) }, [])
pub const debug_level: level.Level

Debug level

pub fn emergency(
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log at emergency level

pub fn emergency_lazy(
  message_fn: fn() -> String,
  fields: List(#(String, String)),
) -> Nil

Lazy emergency

pub const emergency_level: level.Level

Emergency level (system is unusable)

pub fn error(
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log at error level

pub fn error_lazy(
  message_fn: fn() -> String,
  fields: List(#(String, String)),
) -> Nil

Lazy error

pub const error_level: level.Level

Error level

pub fn handlers() -> List(handler.Handler)

Get current handlers

pub fn info(
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log at info level

pub fn info_lazy(
  message_fn: fn() -> String,
  fields: List(#(String, String)),
) -> Nil

Lazy info

pub const info_level: level.Level

Info level

pub fn log(
  lvl: level.Level,
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log with explicit level

pub fn log_from(
  source: String,
  lvl: level.Level,
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log with source module

pub fn log_lazy(
  lvl: level.Level,
  message_fn: fn() -> String,
  fields: List(#(String, String)),
) -> Nil

Lazy log - only evaluates message function if log will be emitted

Example:

log.debug_lazy(fn() { "Processing " <> expensive_to_string(data) }, [])
pub fn log_lazy_all(
  lvl: level.Level,
  message_fn: fn() -> String,
  fields_fn: fn() -> List(#(String, String)),
) -> Nil

Lazy log with lazy fields - both message and fields evaluated only if needed

pub fn notice(
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log at notice level

pub fn notice_lazy(
  message_fn: fn() -> String,
  fields: List(#(String, String)),
) -> Nil

Lazy notice

pub const notice_level: level.Level

Notice level (normal but significant)

pub fn sampled(
  lvl: level.Level,
  rate: Float,
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log with sampling (only log rate% of messages)

pub fn trace(
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log at trace level

pub fn trace_lazy(
  message_fn: fn() -> String,
  fields: List(#(String, String)),
) -> Nil

Lazy trace - for high-frequency logs that should be cheap when disabled

pub const trace_level: level.Level

Trace level (fine-grained)

pub fn warning(
  message: String,
  fields: List(#(String, String)),
) -> Nil

Log at warning level

pub fn warning_lazy(
  message_fn: fn() -> String,
  fields: List(#(String, String)),
) -> Nil

Lazy warning

pub const warning_level: level.Level

Warning level

pub fn with_context(
  context: List(#(String, String)),
  f: fn() -> a,
) -> a

Execute function with additional context

pub fn would_log(lvl: level.Level) -> Bool

Check if any handler would log at this level Use this to avoid expensive computations when log won’t be emitted

Search Document