Skip to content

API Logger

iKrypto edited this page May 1, 2026 · 4 revisions

API: Logger

Logger is the framework's small structured logging utility: per-instance history buffer, runtime severity gating, timestamped console lines, and optional operation correlation via OperationId.

Important

Docs audit note (2026-05): This page was re-audited against FSM/Orchestrator/Core/Logger.luau and FSM/Orchestrator/Core/Settings.luau.


🎯 Overview

The module has two layers:

  1. static bootstrap β€” Logger.Initialize(Util) caches Util.Settings.Logger
  2. per-instance logging β€” Logger.new({ Name? }) creates a logger with its own History

Implementation constants in the current source:

  • SHOW_TIMESTAMP = true
  • USE_RICH_TEXT = false
  • MAX_LOG_HISTORY = 500

Important runtime rules:

  • every call to :Log(...) is appended to history before output filtering
  • console output is controlled by Settings.Logger.DebuggingEnabled
  • severity gating is controlled by Settings.Logger.MinimumLoggingLevel
  • ERROR uses warn(), not Lua error()

πŸ”§ API reference

Logger.Initialize(Util: { Settings: { Logger: { DebuggingEnabled: boolean, MinimumLoggingLevel: number } } }) -> ()

Must run before any logger instance calls :Log(...).

Side effects

  • sets the module-local Settings = Util.Settings.Logger
  • marks the module as initialized

Edge cases

  • second call is a no-op
  • Logger.new(...) can be called before initialization, but :Log(...) will assert until initialization happened

Logger.new(params: { Name: string? }) -> Logger

Creates a logger instance.

Fields created on the instance

  • Source
  • History

Name resolution

  • if params.Name is provided, it is used directly
  • otherwise the module inspects debug.info(2, "s") and keeps the final dotted path segment
  • if source detection fails, Source may be nil
local log = Logger.new({ Name = "InventoryService" })
local auto = Logger.new({})

Logger:Log(params: { Level: string, Message: string, OperationId: string?, Data: any? }) -> ()

Records an entry and optionally prints it.

Stored history shape

{
    Timestamp = os.time(),
    OperationId = params.OperationId,
    Level = params.Level or "INFO",
    Message = params.Message or "",
    Data = params.Data,
}

Console formatting

  • printed prefix is [HH:MM:SS] [LEVEL] [Source]
  • OperationId is appended as (<id>) when it is a string
  • INFO and DEBUG print with print()
  • WARN and ERROR print with warn()
  • unknown levels print as [UNKNOWN (<level>)]

Severity gate

Level Printed when MinimumLoggingLevel >=
ERROR 1
WARN 2
INFO 3
DEBUG 4

Side effects

  • appends to self.History
  • trims oldest entry when history exceeds 500 items
  • may print or warn

Failure mode

  • asserts if Logger.Initialize(...) never ran or Settings.Logger has the wrong shape
log:Log({ Level = "INFO", Message = "Entity spawned" })
log:Log({ Level = "ERROR", Message = "Save failed", OperationId = "user:42", Data = { key = "Player_42" } })

Logger:SetMinimumLoggingLevel(level: number) -> ()

Mutates the shared logger settings table at runtime.

Important

  • this affects all logger instances because they all read the same Settings.Logger table
  • history collection is unaffected; only console gating changes
log:SetMinimumLoggingLevel(4) -- enable DEBUG output globally

Logger:GetHistory() -> { LogEntry }

Returns the live history array for this logger.

Edge cases

  • returns the actual internal table, not a copy
  • empty logger => {}
  • each logger instance has its own independent history
local history = table.clone(log:GetHistory())

πŸ“‹ Method inventory

Method Signature Returns Notes
Initialize (Util) -> () () one-time bootstrap
new ({ Name: string? }) -> Logger Logger auto-detects source if omitted
Log ({ Level, Message, OperationId?, Data? }) -> () () always writes to history first
SetMinimumLoggingLevel (level: number) -> () () global setting mutation
GetHistory () -> {LogEntry} {LogEntry} live reference

βš™οΈ Settings reference

Settings live in FSM/Orchestrator/Core/Settings.luau under Logger.

Key Default Meaning
DebuggingEnabled true master on/off switch for console output
MinimumLoggingLevel 3 prints INFO, WARN, and ERROR by default; DEBUG stays hidden

πŸš€ Real examples

Example 1: Framework bootstrap + named logger

local Logger = require(path.to.Logger)
local Settings = require(path.to.Settings)

Logger.Initialize({ Settings = Settings })

local log = Logger.new({ Name = "Matchmaking" })
log:Log({ Level = "INFO", Message = "Queue opened" })

Example 2: Correlating one operation across several log calls

local opId = "user:42"
log:Log({ Level = "INFO", Message = "Save started", OperationId = opId })
log:Log({ Level = "WARN", Message = "Retrying write", OperationId = opId })
log:Log({ Level = "INFO", Message = "Save finished", OperationId = opId })

Example 3: Assert against history in tests

local last = log:GetHistory()[#log:GetHistory()]
assert(last.Level == "INFO")
assert(last.Message == "Queue opened")

⚠️ Edge cases and pitfalls

  1. History is always written. Disabling console output does not disable history collection.

  2. ERROR does not stop execution. If you need hard failure semantics, log first and call error(...) separately.

  3. History trimming is O(n). Once the buffer is full, every new entry removes index 1. Avoid frame-by-frame logging.

  4. SetMinimumLoggingLevel is global. It is not scoped to one logger instance.

  5. GetHistory() returns a live reference. Clone it before filtering or mutating.


πŸ”— See also

🏠 Home


πŸš€ Getting Started


πŸ—οΈ Architecture


πŸ”§ API Reference


πŸ“š Guides


βš™οΈ Advanced


πŸ› οΈ Development


πŸ“– Reference

Clone this wiki locally