Wanderland

Wanderland Core: Logging

Block-based lazy logging mixin. Extracted from kremis and dark-lantern where it was duplicated verbatim (only the module namespace differed).

Pattern

Log methods take blocks, not strings. The block is only evaluated if the log level is enabled. This matters when the log message involves expensive computation (serializing objects, string interpolation with method calls).

include Wanderland::Logging

debug { "Expensive #{JSON.generate(large_object)} only runs at debug" }
info  { "Processing #{slug}" }
warn  { "Something looks off: #{details}" }
error { "Failed: #{exception.message}" }

Configuration

# At boot time
Wanderland.configure_logging(
  level: :info,          # :debug, :info, :warn, :error, :fatal
  output: nil,           # nil/:stdout, :stderr, "/path/to/file", "/path/to/dir/"
  name: "lantern"        # used for log filename when output is a directory
)

Output resolution:

Format

[2026-04-01 21:26:17] INFO  [Lantern::RouteMatch] Matched /node/:slug

[timestamp] SEVERITY [class_name] message

The class name comes from self.class.name on the including class. Falls back to "Wanderland" if anonymous. Classes that include Wanderland::Boundary get a more specific prefix — see Boundary log prefix below.

Glyph constants

Single-character glyphs commonly used in log lines. Reference them by short name from any class that includes Wanderland::Logging (or fully qualified as Wanderland::Logging::PLAY from outside) so glyph use stays consistent across the codebase.

Constant Glyph Used for
PLAY entering a phase / starting work
DONE completed / returning
OK success outcome
FAIL failure outcome
ARROW transition / mapping (in prose, not in code)
WARN warning / caution
PAUSE awaiting / paused / yielded
class CompileJar
  include Wanderland::Boundary  # transitively includes Wanderland::Logging

  def call(input)
    info { "#{PLAY} mvn package #{source_path}" }
    # logs: [compile_jar] ▶ mvn package /path/to/repo
  end
end

Boundary log prefix

Wanderland::Boundary prepends a small BoundaryLogPrefix module to every including class so the log prefix becomes the registered boundary name (compile_jar) rather than the Ruby class name (WanderlandPipelinesPack::Boundaries::CompileJar). The prepend sits above Wanderland::Logging in the lookup chain, so calls to info, debug, warn, error from inside a boundary tag the log line with the boundary's registry name automatically — no hardcoded namespace strings, no copy-paste of the boundary name into every log call.

When a class that uses Wanderland::Logging directly (without Wanderland::Boundary), the prefix falls back to self.class.name as before.

Mixin Mechanics

module Wanderland::Logging
  def self.included(base)
    base.extend(ClassMethods)     # class-level .logger
  end

  def logger = Wanderland.logger  # instance-level
  def debug(&block)               # delegates to logger with lazy eval
    logger.debug(log_prefix) { block.call } if logger.debug?
  end
end

Both class methods and instance methods delegate to the singleton Wanderland.logger. The singleton is configured once at boot and shared across the process.

Site Audit

wanderland.dev

oculus-view: fence: fence execute HTTP 404