using System;
using System.Reflection;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
namespace LLM.Editor.Analysis
{
///
/// Provides access to the Unity Editor's console log entries using reflection.
///
public class ConsoleLogProvider : IContextProvider
{
private class ConsoleLogEntry
{
public string type;
public string message;
}
// Reflection-based access to internal Unity log types
private static Type _logEntriesType;
private static MethodInfo _getCountMethod;
private static MethodInfo _getEntryMethod;
private static MethodInfo _startGettingEntriesMethod;
private static MethodInfo _endGettingEntriesMethod;
private static object _logEntryInstance;
static ConsoleLogProvider()
{
// Initialize reflection types once
_logEntriesType = Type.GetType("UnityEditor.LogEntries, UnityEditor.dll");
if (_logEntriesType == null) return;
_getCountMethod = _logEntriesType.GetMethod("GetCount", BindingFlags.Static | BindingFlags.Public);
_getEntryMethod = _logEntriesType.GetMethod("GetEntryInternal", BindingFlags.Static | BindingFlags.Public);
_startGettingEntriesMethod = _logEntriesType.GetMethod("StartGettingEntries", BindingFlags.Static | BindingFlags.Public);
_endGettingEntriesMethod = _logEntriesType.GetMethod("EndGettingEntries", BindingFlags.Static | BindingFlags.Public);
// The LogEntry class is nested within LogEntries
var logEntryType = Type.GetType("UnityEditor.LogEntry, UnityEditor.dll");
if (logEntryType != null)
{
_logEntryInstance = Activator.CreateInstance(logEntryType);
}
}
public object GetContext(Object target, string qualifier)
{
if (_logEntriesType == null || _getCountMethod == null || _getEntryMethod == null || _logEntryInstance == null)
{
return "Error: Could not access Unity's internal console log API via reflection.";
}
// Parse the qualifier for filters (e.g., "errors:10")
var parts = qualifier?.Split(':');
var filterType = parts is { Length: > 0 } ? parts[0].ToLower() : "all";
var count = (parts is { Length: > 1 } && int.TryParse(parts[1], out var num)) ? num : 10;
var logEntries = new List();
_startGettingEntriesMethod.Invoke(null, null);
var totalCount = (int)_getCountMethod.Invoke(null, null);
count = Mathf.Min(count, totalCount);
for (var i = 0; i < totalCount && logEntries.Count < count; i++)
{
var index = totalCount - 1 - i; // Read from the most recent
_getEntryMethod.Invoke(null, new object[] { index, _logEntryInstance });
var message = (string)_logEntryInstance.GetType().GetField("message", BindingFlags.Instance | BindingFlags.Public)?.GetValue(_logEntryInstance);
var mode = (int)_logEntryInstance.GetType().GetField("mode", BindingFlags.Instance | BindingFlags.Public)?.GetValue(_logEntryInstance)!;
var logType = GetLogTypeFromMode(mode);
if (filterType != "all" && (filterType != "errors" || logType != "Error") &&
(filterType != "warnings" || logType != "Warning")) continue;
if (message != null)
logEntries.Add(new ConsoleLogEntry { type = logType, message = message.Trim() });
}
_endGettingEntriesMethod.Invoke(null, null);
return logEntries;
}
private static string GetLogTypeFromMode(int mode)
{
// These mode values are constants defined internally in UnityEditor.LogEntry
if ((mode & 1) != 0) return "Error"; // 0x0001
return (mode & 2) != 0 ? "Warning" : // 0x0002
"Log";
}
}
}