Skip to content

Commit 642210c

Browse files
authored
Merge pull request CoplayDev#202 from dsarno/fix-read-console
Fix: ReadConsole tool: stable log severity classification and reliable console reads across Unity versions
2 parents 0743e64 + ae87e3f commit 642210c

File tree

1 file changed

+96
-41
lines changed

1 file changed

+96
-41
lines changed

UnityMcpBridge/Editor/Tools/ReadConsole.cs

Lines changed: 96 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ namespace UnityMcpBridge.Editor.Tools
1616
/// </summary>
1717
public static class ReadConsole
1818
{
19+
// (Calibration removed)
20+
1921
// Reflection members for accessing internal LogEntry data
2022
// private static MethodInfo _getEntriesMethod; // Removed as it's unused and fails reflection
2123
private static MethodInfo _startGettingEntriesMethod;
@@ -41,6 +43,8 @@ static ReadConsole()
4143
);
4244
if (logEntriesType == null)
4345
throw new Exception("Could not find internal type UnityEditor.LogEntries");
46+
47+
4448

4549
// Include NonPublic binding flags as internal APIs might change accessibility
4650
BindingFlags staticFlags =
@@ -100,6 +104,9 @@ static ReadConsole()
100104
_instanceIdField = logEntryType.GetField("instanceID", instanceFlags);
101105
if (_instanceIdField == null)
102106
throw new Exception("Failed to reflect LogEntry.instanceID");
107+
108+
// (Calibration removed)
109+
103110
}
104111
catch (Exception e)
105112
{
@@ -251,16 +258,38 @@ bool includeStacktrace
251258
// int instanceId = (int)_instanceIdField.GetValue(logEntryInstance);
252259

253260
if (string.IsNullOrEmpty(message))
261+
{
254262
continue; // Skip empty messages
263+
}
264+
265+
// (Calibration removed)
255266

256267
// --- Filtering ---
257-
// Filter by type
258-
LogType currentType = GetLogTypeFromMode(mode);
259-
if (!types.Contains(currentType.ToString().ToLowerInvariant()))
268+
// Prefer classifying severity from message/stacktrace; fallback to mode bits if needed
269+
LogType unityType = InferTypeFromMessage(message);
270+
bool isExplicitDebug = IsExplicitDebugLog(message);
271+
if (!isExplicitDebug && unityType == LogType.Log)
260272
{
261-
continue;
273+
unityType = GetLogTypeFromMode(mode);
262274
}
263275

276+
bool want;
277+
// Treat Exception/Assert as errors for filtering convenience
278+
if (unityType == LogType.Exception)
279+
{
280+
want = types.Contains("error") || types.Contains("exception");
281+
}
282+
else if (unityType == LogType.Assert)
283+
{
284+
want = types.Contains("error") || types.Contains("assert");
285+
}
286+
else
287+
{
288+
want = types.Contains(unityType.ToString().ToLowerInvariant());
289+
}
290+
291+
if (!want) continue;
292+
264293
// Filter by text (case-insensitive)
265294
if (
266295
!string.IsNullOrEmpty(filterText)
@@ -294,7 +323,7 @@ bool includeStacktrace
294323
default:
295324
formattedEntry = new
296325
{
297-
type = currentType.ToString(),
326+
type = unityType.ToString(),
298327
message = messageOnly,
299328
file = file,
300329
line = line,
@@ -350,15 +379,12 @@ bool includeStacktrace
350379

351380
// --- Internal Helpers ---
352381

353-
// Mapping from LogEntry.mode bits to LogType enum
354-
// Based on decompiled UnityEditor code or common patterns. Precise bits might change between Unity versions.
355-
// See comments below for LogEntry mode bits exploration.
356-
// Note: This mapping is simplified and might not cover all edge cases or future Unity versions perfectly.
382+
// Mapping bits from LogEntry.mode. These may vary by Unity version.
357383
private const int ModeBitError = 1 << 0;
358384
private const int ModeBitAssert = 1 << 1;
359385
private const int ModeBitWarning = 1 << 2;
360386
private const int ModeBitLog = 1 << 3;
361-
private const int ModeBitException = 1 << 4; // Often combined with Error bits
387+
private const int ModeBitException = 1 << 4; // often combined with Error bits
362388
private const int ModeBitScriptingError = 1 << 9;
363389
private const int ModeBitScriptingWarning = 1 << 10;
364390
private const int ModeBitScriptingLog = 1 << 11;
@@ -367,46 +393,75 @@ bool includeStacktrace
367393

368394
private static LogType GetLogTypeFromMode(int mode)
369395
{
370-
// First, determine the type based on the original logic (most severe first)
371-
LogType initialType;
372-
if (
373-
(
374-
mode
375-
& (
376-
ModeBitError
377-
| ModeBitScriptingError
378-
| ModeBitException
379-
| ModeBitScriptingException
380-
)
381-
) != 0
382-
)
383-
{
384-
initialType = LogType.Error;
385-
}
386-
else if ((mode & (ModeBitAssert | ModeBitScriptingAssertion)) != 0)
387-
{
388-
initialType = LogType.Assert;
389-
}
390-
else if ((mode & (ModeBitWarning | ModeBitScriptingWarning)) != 0)
391-
{
392-
initialType = LogType.Warning;
393-
}
394-
else
395-
{
396-
initialType = LogType.Log;
397-
}
396+
// Preserve Unity's real type (no remapping); bits may vary by version
397+
if ((mode & (ModeBitException | ModeBitScriptingException)) != 0) return LogType.Exception;
398+
if ((mode & (ModeBitError | ModeBitScriptingError)) != 0) return LogType.Error;
399+
if ((mode & (ModeBitAssert | ModeBitScriptingAssertion)) != 0) return LogType.Assert;
400+
if ((mode & (ModeBitWarning | ModeBitScriptingWarning)) != 0) return LogType.Warning;
401+
return LogType.Log;
402+
}
403+
404+
// (Calibration helpers removed)
405+
406+
/// <summary>
407+
/// Classifies severity using message/stacktrace content. Works across Unity versions.
408+
/// </summary>
409+
private static LogType InferTypeFromMessage(string fullMessage)
410+
{
411+
if (string.IsNullOrEmpty(fullMessage)) return LogType.Log;
412+
413+
// Fast path: look for explicit Debug API names in the appended stack trace
414+
// e.g., "UnityEngine.Debug:LogError (object)" or "LogWarning"
415+
if (fullMessage.IndexOf("LogError", StringComparison.OrdinalIgnoreCase) >= 0)
416+
return LogType.Error;
417+
if (fullMessage.IndexOf("LogWarning", StringComparison.OrdinalIgnoreCase) >= 0)
418+
return LogType.Warning;
419+
420+
// Compiler diagnostics (C#): "warning CSxxxx" / "error CSxxxx"
421+
if (fullMessage.IndexOf(" warning CS", StringComparison.OrdinalIgnoreCase) >= 0
422+
|| fullMessage.IndexOf(": warning CS", StringComparison.OrdinalIgnoreCase) >= 0)
423+
return LogType.Warning;
424+
if (fullMessage.IndexOf(" error CS", StringComparison.OrdinalIgnoreCase) >= 0
425+
|| fullMessage.IndexOf(": error CS", StringComparison.OrdinalIgnoreCase) >= 0)
426+
return LogType.Error;
427+
428+
// Exceptions (avoid misclassifying compiler diagnostics)
429+
if (fullMessage.IndexOf("Exception", StringComparison.OrdinalIgnoreCase) >= 0)
430+
return LogType.Exception;
431+
432+
// Unity assertions
433+
if (fullMessage.IndexOf("Assertion", StringComparison.OrdinalIgnoreCase) >= 0)
434+
return LogType.Assert;
435+
436+
return LogType.Log;
437+
}
398438

399-
// Apply the observed "one level lower" correction
400-
switch (initialType)
439+
private static bool IsExplicitDebugLog(string fullMessage)
440+
{
441+
if (string.IsNullOrEmpty(fullMessage)) return false;
442+
if (fullMessage.IndexOf("Debug:Log (", StringComparison.OrdinalIgnoreCase) >= 0) return true;
443+
if (fullMessage.IndexOf("UnityEngine.Debug:Log (", StringComparison.OrdinalIgnoreCase) >= 0) return true;
444+
return false;
445+
}
446+
447+
/// <summary>
448+
/// Applies the "one level lower" remapping for filtering, like the old version.
449+
/// This ensures compatibility with the filtering logic that expects remapped types.
450+
/// </summary>
451+
private static LogType GetRemappedTypeForFiltering(LogType unityType)
452+
{
453+
switch (unityType)
401454
{
402455
case LogType.Error:
403456
return LogType.Warning; // Error becomes Warning
404457
case LogType.Warning:
405458
return LogType.Log; // Warning becomes Log
406459
case LogType.Assert:
407-
return LogType.Assert; // Assert remains Assert (no lower level defined)
460+
return LogType.Assert; // Assert remains Assert
408461
case LogType.Log:
409462
return LogType.Log; // Log remains Log
463+
case LogType.Exception:
464+
return LogType.Warning; // Exception becomes Warning
410465
default:
411466
return LogType.Log; // Default fallback
412467
}

0 commit comments

Comments
 (0)