Logging — Log
Burnsie.Common.Logging.Log is a prefixed, leveled logger that writes to the
RagePluginHook log (via Game.LogTrivial), with an optional dedicated diagnostics file
sink. It is safe to call from any thread and at any point in the plugin lifecycle —
logging never throws, even when the game console is unavailable.
Quick start
var log = new Log("MyPlugin"); // lines appear as "[MyPlugin] ..." in RagePluginHook.log
log.DebugEnabled = config.DebugLogging; // gate debug lines behind a user setting
log.Info("loaded");
log.Warn("something odd");
log.Error("operation failed");
log.Error("operation failed", exception); // includes formatted exception details
log.Debug("verbose detail"); // console only when DebugEnabled
Line format: [Prefix] message, with [WARN], [ERROR] or [DEBUG] markers inserted for
those levels.
Levels
| Method | Console | Diagnostics file | Use for |
|---|---|---|---|
Info | always | always (when attached) | Decisions, lifecycle milestones |
Warn | always | always | Degraded-but-continuing situations |
Error / Error(msg, ex) | always | always | Failures; the exception overload formats the message chain and stack |
Debug | only when DebugEnabled | always | High-volume detail, state snapshots |
The key property of Debug: it always reaches the diagnostics file when one is attached,
regardless of DebugEnabled. A shipped build can keep a clean console while still
producing a full, reviewable trace on request.
The diagnostics file sink
The file sink is static and shared across all Log instances in the session — one
file for the whole plugin (or several cooperating plugins).
// At startup (e.g. duty start):
Log.AttachFile("plugins/LSPDFR/MyPlugin/diagnostics.log");
// Free-form lines (no prefix/level) — e.g. section separators in a trace:
Log.File("---- session start ----");
// At teardown (Finally()):
Log.DetachFile();
Behavior you get for free:
- Appending, not truncating — a duty toggle doesn't wipe the previous session's trace.
- Size-capped: when the file passes 4 MB it is rolled to a single
.1backup, so it can't grow without bound. - Every line is stamped with a UTC
HH:mm:ss.ffftimestamp. - The file is opened with
FileShare.ReadWrite, so the user can open it while the game is still writing. AttachFilenever throws; it returnstruewhen the file is open. Diagnostics logging is best-effort — the plugin runs fine without it.
Formatting exceptions
Log.Format(Exception) is public and produces a single log-friendly line: the exception
type and message, up to four inner exceptions (<- InnerType: message), and the stack
trace flattened onto one line. Use it anywhere you need an exception as a string.
Rules
- Create one
Logper plugin or subsystem; the prefix is how users tell plugins apart in a shared RagePluginHook.log. - The logger name must be non-empty (constructor throws
ArgumentExceptionotherwise — the only place this class throws). - Call
Log.DetachFile()in your teardown path so the file handle doesn't outlive the session.