Logger
UntoldEngine includes a thread-safe logger with log-level filtering, per-category toggles, and a sink API for routing log events to custom destinations (e.g. an in-editor console).
Log Levels
Log level controls the minimum severity that is emitted. Set it once at startup:
Logger.logLevel = .debug // emit everything
Logger.logLevel = .info // emit info, warnings, and errors
Logger.logLevel = .warning // emit warnings and errors only
Logger.logLevel = .error // emit errors only
Logger.logLevel = .none // suppress all output
| Level | Value | What emits |
|---|---|---|
.none |
0 | nothing |
.error |
1 | errors |
.warning |
2 | warnings + errors |
.info |
3 | info + warnings + errors |
.debug |
4 | everything |
.test |
5 | everything (used in unit tests) |
The default level is .debug.
Logging Messages
Info / general trace
Requires logLevel >= .info. Suppressed if the category is disabled.
Warnings
Requires logLevel >= .warning. Always emits regardless of category state.
Errors
Requires logLevel >= .error. Always emits regardless of category state.
Note: Messages are lazily evaluated (
@autoclosure), so string interpolation cost is skipped when the log would be suppressed.
Log Categories
Categories let you silence or focus specific subsystems without changing the global log level.
| Category | Raw value | Default state |
|---|---|---|
.general |
"General" |
enabled |
.ecs |
"ECS" |
enabled |
.engineStats |
"EngineStats" |
enabled |
.integration |
"Integration" |
enabled |
.xrCamera |
"XRCamera" |
disabled |
.oocTiming |
"OOCTiming" |
disabled |
.oocStatus |
"OOCStatus" |
disabled |
.assetLoader |
"AssetLoader" |
disabled |
High-volume categories (xrCamera, oocTiming, oocStatus, assetLoader) are off by default to avoid log spam during normal operation.
Enabling and Disabling Categories
// Enable a category
Logger.enable(category: .oocStatus)
// Disable a category
Logger.disable(category: .xrCamera)
// Toggle with a Bool
Logger.set(category: .assetLoader, enabled: true)
// Check current state
if Logger.isEnabled(category: .ecs) { ... }
// Reset all overrides back to defaults
Logger.resetCategoryToggles()
Typical debug session
// Turn on verbose streaming traces for a debug session
Logger.enable(category: .oocStatus)
Logger.enable(category: .oocTiming)
Logger.enable(category: .assetLoader)
// ... reproduce the issue ...
// Clean up after capture
Logger.disable(category: .oocStatus)
Logger.disable(category: .oocTiming)
Logger.disable(category: .assetLoader)
Adding a Custom Sink
Implement LoggerSink to route events to a custom destination such as an editor console or file:
final class ConsoleSink: LoggerSink {
func didLog(_ event: LogEvent) {
print("[\(event.category)] \(event.message)")
}
}
let sink = ConsoleSink()
Logger.addSink(sink)
LogEvent exposes level, message, category, file, function, line, and timestamp.
Sinks are held weakly — the logger will not extend their lifetime.
Sink delivery and backlog replay are available on macOS (
AppKit) builds only.
Category Toggle Notes
Logger.log(...)respects bothlogLeveland category state.Logger.logWarning(...)andLogger.logError(...)respectlogLevelonly — they are never suppressed by category.- Category overrides layer on top of the built-in defaults. Call
resetCategoryToggles()to restore defaults without restarting.