Skip to content

Unity Logging Extensions & Tag Formatter

Bring structured, color-coded logs to any Unity project without sprinkling Debug.Log everywhere. WallstopStudiosLogger adds extension methods (this.Log, this.LogWarn, this.LogError, this.LogDebug) that automatically capture component metadata, thread info, timestamps, and user-defined tags rendered by UnityLogTagFormatter.

  • Thread-safe: Logs are marshaled back to the Unity main thread when required (via UnityMainThreadDispatcher / UnityMainThreadGuard).
  • Readable output: Pretty mode prefixes time|GameObject[Component] when logging on the main thread and inserts |thread| only when background workers emit messages, keeping logs deterministic without extra noise.
  • Tag formatter: Apply rich text decorations inline ($"{name:b,color=cyan}") without string concatenation. Tags deduplicate automatically and can be stacked in any order.

These helpers live in Runtime/Core/Extension/WallstopStudiosLogger.cs and Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs. Tests at Tests/Runtime/Extensions/LoggingExtensionTests.cs demonstrate every supported scenario.


Sample Scene

  • Import the Logging – Tag Formatter package sample and open Samples~/Logging - Tag Formatter/Scenes/LoggingDemo.unity.
  • Press Play to use the on-screen toggles (global logging, component logging, pretty output) and emit Info/Warn/Error logs that showcase the decorators.
  • Review LoggingDemoBootstrap (decorator registration) and LoggingDemoController (runtime toggles + this.Log* usage) to copy the patterns into your project.

Quick Start

C#
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Extension;

public sealed class EnemyHUD : MonoBehaviour
{
    private void Start()
    {
        string mode = Application.isEditor ? "Test" : "Live";
        int hp = 42;

        this.Log(
            $"Player {"Rogue-17":b,color=orange} :: HP {hp:color=#FF4444} ({mode:italic})"
        );
    }
}
  • Pass interpolated strings directly; the formatter applies tags before Unity renders the message.
  • Use pretty: false if you only want the decorated text without the timestamp (or optional thread) prefix.
  • Call this.LogWarn, this.LogError, or this.LogDebug for severity-specific output; all overloads accept Exception e to append stack traces.

Enabling logging in builds

ENABLE_UBERLOGGING is defined automatically for DEBUG, DEVELOPMENT_BUILD, and UNITY_EDITOR. Define it manually (or DEBUG_LOGGING / WARN_LOGGING / ERROR_LOGGING) in Player Settings if you need the extensions in release builds.


Default Tag Reference

Tag syntax Effect Notes
:b, :bold, :! Wraps value in <b> Editor-only (uses Unity rich text)
:i, :italic, :_ Wraps value in <i> Editor-only
:json Serializes value via ToJson() Works in player builds
:#color, :color=name, :color=#hex Wraps with <color=...> Named colors resolve to UnityEngine.Color constants
:42, :size=42 Wraps with <size=42> Integers 1–100 (or any positive int)
  • Combine tags using commas: $"{stats:json,b,color=yellow}" emits bold, colored JSON.
  • Tags are applied in priority order and deduplicate automatically, so repeating :b has no effect.

Custom Decorations

Register project-specific tags at startup (for example, in an InitializeOnLoad editor script or a runtime bootstrapper):

C#
using WallstopStudios.UnityHelpers.Core.Extension;
using WallstopStudios.UnityHelpers.Core.Helper.Logging;

[InitializeOnLoad]
internal static class LoggingBootstrap
{
    static LoggingBootstrap()
    {
        UnityLogTagFormatter formatter = WallstopStudiosLogger.LogInstance;

        formatter.AddDecoration(
            predicate: tag => tag.StartsWith("stat:", StringComparison.OrdinalIgnoreCase),
            format: (tag, value) =>
            {
                string label = tag.Substring("stat:".Length);
                return $"<color=#7AD7FF>[{label}]</color> {value}";
            },
            tag: "StatLabel",
            priority: -10 // run before built-ins
        );
    }
}

Key APIs:

  • AddDecoration(string match, Func<object,string> format, string tag, int priority = 0, bool editorOnly = false, bool force = false)
  • AddDecoration(Func<string,bool> predicate, Func<string,object,string> format, string tag, int priority = 0, bool editorOnly = false, bool force = false)
  • RemoveDecoration(string tag, out Decoration removed) to swap or disable decorators at runtime.
  • UnityLogTagFormatter.Separator (',') controls how stacked tags are parsed.

Use negative priorities for “outer” wrappers (run earlier) and higher numbers for final passes. Setting force: true replaces existing tags with the same name.


Extension Method Cheat Sheet

API Description
component.Log(FormattableString, Exception e = null, bool pretty = true) Sends an info log through the formatter. Guarded by ENABLE_UBERLOGGING/DEBUG_LOGGING.
component.LogWarn(...), component.LogError(...), component.LogDebug(...) Severity-specific variants with the same signature.
component.GenericToString() Serializes all public fields/properties into JSON (used by the formatter when you pass :json).
component.EnableLogging() / component.DisableLogging() Per-object toggle. Disabled components are skipped without allocations.
component.GlobalEnableLogging() / component.GlobalDisableLogging() / SetGlobalLoggingEnabled(bool) Global kill switch suitable for in-game consoles or dev toggles.
WallstopStudiosLogger.IsGlobalLoggingEnabled() Query current state (useful for tooling UIs).

Additional behavior:

  • Thread routing: If a log originates off the main thread, the extension tries UnityMainThreadDispatcher.TryDispatchToMainThread first. If unavailable, it falls back to UnityMainThreadGuard.TryPostToMainThread and, if that fails, emits an “offline” log with a [WallstopMainThreadLogger:*] prefix.
  • Pretty output: Keeps logs uniform (timestamp|GameObject[Component]|message on the main thread, inserting |thread| only for worker threads). Pass pretty: false when emitting data the Unity console already decorates (for example, performance CSV dumps).
  • Context awareness: Unity context objects are forwarded to Debug.Log*, preserving click-to-focus navigation even when logs originate from pooled helper classes.

Best Practices

  1. Register tags once — Use static constructors or [RuntimeInitializeOnLoadMethod] to register project-wide tags. Avoid allocating per-frame delegates.
  2. Prefer interpolation$"{health:json}" keeps minimal formatting allocations compared to string.Format.
  3. Use pretty: false for exporters — When writing to files or parsing logs, disable prefixes to simplify downstream tooling.
  4. Gate release builds — If you plan to leave logging enabled in production, explicitly define ENABLE_UBERLOGGING (or DEBUG_LOGGING / WARN_LOGGING / ERROR_LOGGING) and make sure log volume is acceptable (or wrap noisy calls in your own #defines).
  5. Leverage testsTests/Runtime/Extensions/LoggingExtensionTests.cs covers every default tag and stacking scenario. Copy those patterns when adding new decorations to ensure behavior stays deterministic.