birch/scope

Scoped context for temporary, request-scoped metadata.

Scoped context allows you to attach metadata that automatically applies to all logs within a scope, without needing to pass context explicitly.

Example

import birch/scope

pub fn handle_request(request_id: String) {
  scope.with_scope([#("request_id", request_id)], fn() {
    // All logs in this block include request_id
    log.info("processing request")
    do_work()
    log.info("request complete")
  })
}

Platform Support

Values

pub fn get_context() -> List(#(String, String))

Get the current scope context.

Returns the metadata from all active scopes, with inner scope values taking precedence (appearing first in the list).

Returns an empty list if called outside of any scope.

pub fn get_depth() -> Int

Get the current scope depth (nesting level).

Returns 0 if no scope is active, 1 for one level of nesting, etc.

This can be used to determine visual indentation level or to track how deeply nested the current execution context is.

pub fn is_available() -> Bool

Check if scoped context is available on the current platform.

  • On Erlang: Always returns True (uses process dictionary)
  • On Node.js: Returns True (uses AsyncLocalStorage)
  • On other JavaScript runtimes: Returns False

When not available, with_scope still works but context won’t propagate to nested async operations.

pub fn with_scope(
  context: List(#(String, String)),
  work: fn() -> a,
) -> a

Execute a function with the given context applied.

All logs made within the scope (directly or through nested calls) will include the scoped context metadata.

Scopes can be nested, with inner scopes adding to (and potentially shadowing) the outer scope’s context.

Example

with_scope([#("request_id", "123")], fn() {
  log.info("processing")  // Includes request_id=123
  with_scope([#("step", "validation")], fn() {
    log.info("validating")  // Includes request_id=123 AND step=validation
  })
  log.info("done")  // Only request_id=123
})
Search Document