using System; using UnityEngine; namespace Unity.Pipeline.Console { /// /// Captures Unity console output into a process-wide so the /// console command can serve it to CLI clients. This type lives in the runtime /// assembly, so it ships in player builds as well as the Editor. /// /// Lifecycle: /// - In a Player, the [RuntimeInitializeOnLoadMethod] hook starts capture as the app boots. /// - In the Editor, the editor-only EditorConsoleCaptureBootstrap starts capture on every /// domain reload and layers on persistence so entries survive reloads (e.g. after a recompile). /// Both paths funnel through , which is idempotent — entering Play /// mode in the Editor fires the runtime hook too, and the guard makes that a no-op. /// - is used (not the non-threaded variant) /// so logs emitted from background threads are captured too. The buffer is thread-safe. /// /// Capture starts when this type first initializes. Console entries produced before that — or /// before the package's first import — are not retroactively captured; this reads from the public /// log callback, not Unity's internal console store. /// public static class ConsoleLogCapture { static readonly ConsoleLogBuffer s_Buffer = new ConsoleLogBuffer(); static readonly object s_SubscriptionLock = new object(); static bool s_Subscribed; /// The shared buffer holding captured console entries. public static ConsoleLogBuffer Buffer => s_Buffer; /// /// Player entry point. Runs as the application boots so console output is captured from the /// start. In the Editor this also fires when entering Play mode, but /// is idempotent so it does not double-subscribe. /// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void RuntimeBootstrap() { EnsureCapturing(); } /// /// Subscribe to Unity's log callback if not already subscribed. Safe to call repeatedly and /// from either the runtime bootstrap or the Editor bootstrap. /// public static void EnsureCapturing() { lock (s_SubscriptionLock) { if (s_Subscribed) return; // Defensive: remove before adding in case a prior subscription leaked across a reload. Application.logMessageReceivedThreaded -= OnLogMessage; Application.logMessageReceivedThreaded += OnLogMessage; s_Subscribed = true; } } static void OnLogMessage(string condition, string stackTrace, LogType type) { s_Buffer.Add(type, condition, stackTrace, DateTime.UtcNow); } } }