witness

Types

pub opaque type Config

A unit of structured data.

Use these to create them:

witness.string
witness.int
witness.float
witness.bool
pub opaque type Field

The currently available formats

pub type Format {
  Json
  Text
}

Constructors

  • Json

    (Pretty printed for reading convenience)

    {
      "timestamp": "2026-05-28T18:30:40.020522296Z",
      "level": "info",
      "message": "Some log message",
      "example": "you can add structured data",
      "also_bools": true,
      "and_floats": 1.23,
      "ints_as_well": 3
    }
    
  • Text
    [INFO] 20:30:40 Some log message
      example: you can add structured data
      also_bools: True
      and_floats: 1.23
      ints_as_well: 3
    
pub type Level {
  Debug
  Info
  Warning
  Error
}

Constructors

  • Debug
  • Info
  • Warning
  • Error
pub type Sink =
  fn(Level, String) -> Nil

Values

pub fn add_process_fields(fields: List(Field)) -> Nil

Add per process fields into the process dictionary. Does not replace fields from previous calls.

These fields will be prepended to every message logged by that process.

Example

witness.add_process_fields([
  witness.string("process_name", "my special process"),
])
pub fn bool(name name: String, value value: Bool) -> Field

Create a bool field.

Example

witness.this(witness.Info, "Things happened", [witness.bool("really", True)])
pub fn default_config() -> Config

The default config logging to io.println with format witness.Text

pub fn empty_config() -> Config

Get a new empty config

Example

witness.empty_config()
|> with_sink(witness.Json, fn(level, message) { io.println(message) })
|> witness.set_config
pub fn float(name name: String, value value: Float) -> Field

Create a float field.

Example

witness.this(witness.Info, "Things happened", [
  witness.float("how_many", 3.14159),
])
pub fn int(name name: String, value value: Int) -> Field

Create an int field.

Example

witness.this(witness.Info, "Things happened", [witness.int("how_many", 21)])
pub fn level_to_badge(level: Level) -> String

Turn a log level into a “[LEVEL]” string.

pub fn set_config(config: Config) -> Nil

Set your config globally

Example

witness.empty_config()
|> with_sink(witness.Json, fn(level, message) { io.println(message) })
|> witness.set_config
pub fn set_process_fields(fields: List(Field)) -> Nil

Put per process fields into the process dictionary. Overwrites all previously set fields for the process.

These fields will be prepended to every message that process logs.

Example

witness.set_process_fields([
  witness.string("process_name", "my special process"),
])
pub fn string(name name: String, value value: String) -> Field

Create a string field.

Example

witness.this(witness.Info, "Something happened", [
  witness.string("what", "i dont know, honestly"),
])
pub fn this(
  level level: Level,
  message message: String,
  fields fields: List(Field),
) -> Nil

Write a log message of a specific level with some fields to all configured sinks.

witness.this(witness.Info, "Hello", [
  witness.string("who", "is it"),
  witness.bool("the-door", True),
])
pub fn with_global_fields(
  config: Config,
  fields: List(Field),
) -> Config

These fields will be prepended to every message logged through witness. Does not replace fields from previous calls.

Example


witness.empty_config()
|> with_sink(witness.Json, logging.log)
|> witness.with_global_fields([
  witness.string("application", "my_application"),
  witness.string("version", "1.0.0"),
])
|> witness.set_config
pub fn with_sink(
  config: Config,
  format: Format,
  sink: fn(Level, String) -> Nil,
) -> Config

Add a sink with a specific formatting to a config.

Example

witness.empty_config()
|> with_sink(witness.Json, fn(level, message) { io.println(message) })
|> witness.set_config
Search Document