Burnsies HideoutDocsBurnsie.Common

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

MethodConsoleDiagnostics fileUse for
Infoalwaysalways (when attached)Decisions, lifecycle milestones
WarnalwaysalwaysDegraded-but-continuing situations
Error / Error(msg, ex)alwaysalwaysFailures; the exception overload formats the message chain and stack
Debugonly when DebugEnabledalwaysHigh-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 .1 backup, so it can't grow without bound.
  • Every line is stamped with a UTC HH:mm:ss.fff timestamp.
  • The file is opened with FileShare.ReadWrite, so the user can open it while the game is still writing.
  • AttachFile never throws; it returns true when 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 Log per 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 ArgumentException otherwise — the only place this class throws).
  • Call Log.DetachFile() in your teardown path so the file handle doesn't outlive the session.