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);
}
}
}