ConsoleLogProvider.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. using System;
  2. using System.Reflection;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using Object = UnityEngine.Object;
  6. namespace LLM.Editor.Analysis
  7. {
  8. /// <summary>
  9. /// Provides access to the Unity Editor's console log entries using reflection.
  10. /// </summary>
  11. public class ConsoleLogProvider : IContextProvider
  12. {
  13. private class ConsoleLogEntry
  14. {
  15. public string type;
  16. public string message;
  17. }
  18. // Reflection-based access to internal Unity log types
  19. private static Type _logEntriesType;
  20. private static MethodInfo _getCountMethod;
  21. private static MethodInfo _getEntryMethod;
  22. private static MethodInfo _startGettingEntriesMethod;
  23. private static MethodInfo _endGettingEntriesMethod;
  24. private static object _logEntryInstance;
  25. static ConsoleLogProvider()
  26. {
  27. // Initialize reflection types once
  28. _logEntriesType = Type.GetType("UnityEditor.LogEntries, UnityEditor.dll");
  29. if (_logEntriesType == null) return;
  30. _getCountMethod = _logEntriesType.GetMethod("GetCount", BindingFlags.Static | BindingFlags.Public);
  31. _getEntryMethod = _logEntriesType.GetMethod("GetEntryInternal", BindingFlags.Static | BindingFlags.Public);
  32. _startGettingEntriesMethod = _logEntriesType.GetMethod("StartGettingEntries", BindingFlags.Static | BindingFlags.Public);
  33. _endGettingEntriesMethod = _logEntriesType.GetMethod("EndGettingEntries", BindingFlags.Static | BindingFlags.Public);
  34. // The LogEntry class is nested within LogEntries
  35. var logEntryType = Type.GetType("UnityEditor.LogEntry, UnityEditor.dll");
  36. if (logEntryType != null)
  37. {
  38. _logEntryInstance = Activator.CreateInstance(logEntryType);
  39. }
  40. }
  41. public object GetContext(Object target, string qualifier)
  42. {
  43. if (_logEntriesType == null || _getCountMethod == null || _getEntryMethod == null || _logEntryInstance == null)
  44. {
  45. return "Error: Could not access Unity's internal console log API via reflection.";
  46. }
  47. // Parse the qualifier for filters (e.g., "errors:10")
  48. var parts = qualifier?.Split(':');
  49. var filterType = parts is { Length: > 0 } ? parts[0].ToLower() : "all";
  50. var count = (parts is { Length: > 1 } && int.TryParse(parts[1], out var num)) ? num : 10;
  51. var logEntries = new List<ConsoleLogEntry>();
  52. _startGettingEntriesMethod.Invoke(null, null);
  53. var totalCount = (int)_getCountMethod.Invoke(null, null);
  54. count = Mathf.Min(count, totalCount);
  55. for (var i = 0; i < totalCount && logEntries.Count < count; i++)
  56. {
  57. var index = totalCount - 1 - i; // Read from the most recent
  58. _getEntryMethod.Invoke(null, new object[] { index, _logEntryInstance });
  59. var message = (string)_logEntryInstance.GetType().GetField("message", BindingFlags.Instance | BindingFlags.Public)?.GetValue(_logEntryInstance);
  60. var mode = (int)_logEntryInstance.GetType().GetField("mode", BindingFlags.Instance | BindingFlags.Public)?.GetValue(_logEntryInstance)!;
  61. var logType = GetLogTypeFromMode(mode);
  62. if (filterType != "all" && (filterType != "errors" || logType != "Error") &&
  63. (filterType != "warnings" || logType != "Warning")) continue;
  64. if (message != null)
  65. logEntries.Add(new ConsoleLogEntry { type = logType, message = message.Trim() });
  66. }
  67. _endGettingEntriesMethod.Invoke(null, null);
  68. return logEntries;
  69. }
  70. private static string GetLogTypeFromMode(int mode)
  71. {
  72. // These mode values are constants defined internally in UnityEditor.LogEntry
  73. if ((mode & 1) != 0) return "Error"; // 0x0001
  74. return (mode & 2) != 0 ? "Warning" : // 0x0002
  75. "Log";
  76. }
  77. }
  78. }