using System;
using System.Collections.Generic;
using System.Reflection;
using Unity.Pipeline.Commands;
namespace Unity.Pipeline.Editor.Commands.Observability
{
///
/// Read-only observability commands over the captured Editor console (CLI-198). Logs are captured
/// continuously by ; these commands let an agent read them back as
/// structured data and clear the buffer (and the Unity console) between runs.
///
public static class ConsoleCommands
{
[CliCommand("get_console_logs", "Read recently captured Editor console logs (structured).")]
public static object GetConsoleLogs(
[CliArg("severity", "Filter: all | log | warning | error. 'all' = every entry; 'log' = Log only; 'warning' = Warning only; 'error' = Error/Exception/Assert only.")] string severity = "all",
[CliArg("limit", "Max entries to return (most-recent first), capped at 1000.")] int limit = 100)
{
// Snapshot is oldest-first; filter by tier, then take the most-recent `limit` entries
// and present them newest-first.
var snapshot = ConsoleLogBuffer.Snapshot();
var filtered = new List(snapshot.Count);
foreach (var entry in snapshot)
{
if (MatchesSeverity(entry.Type, severity))
filtered.Add(entry);
}
var clampedLimit = Math.Min(Math.Max(limit, 1), ConsoleLogBuffer.MaxEntries);
var logs = new List(Math.Min(clampedLimit, filtered.Count));
for (var i = filtered.Count - 1; i >= 0 && logs.Count < clampedLimit; i--)
logs.Add(filtered[i]);
return new
{
total = filtered.Count,
returned = logs.Count,
logs
};
}
[CliCommand("clear_console", "Clear the captured log buffer and the Unity Editor console.")]
public static object ClearConsole()
{
ConsoleLogBuffer.Clear();
// Best-effort: also clear Unity's own console window. UnityEditor.LogEntries is internal,
// so reach it via reflection and swallow any failure (API is not part of the public contract).
// LogEntries.Clear is a static, non-public method, so include NonPublic in the binding flags —
// GetMethod("Clear") with no flags only finds public methods and would silently return null.
try
{
Type.GetType("UnityEditor.LogEntries,UnityEditor")
?.GetMethod("Clear", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
?.Invoke(null, null);
}
catch
{
// Ignore — clearing the Editor console is auxiliary; the buffer is already cleared.
}
return new { cleared = true };
}
///
/// Map a Unity name onto the requested severity tier.
/// The tiers are distinct: "all" matches every entry; "log" matches Log only;
/// "warning" matches Warning only; "error" matches Error/Exception/Assert only.
/// Any unknown value falls back to "all" (matches everything).
///
private static bool MatchesSeverity(string type, string severity)
{
switch (severity?.ToLowerInvariant())
{
case "log":
return type == "Log";
case "warning":
return type == "Warning";
case "error":
return type == "Error" || type == "Exception" || type == "Assert";
case "all":
default:
return true;
}
}
}
}