Skip to content

Commit 1308c56

Browse files
authored
fix: Capture Debug.LogError as message, not exception (#2377)
1 parent ba62623 commit 1308c56

13 files changed

+575
-461
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
- The SDK no longer ends sessions as crashed when capturing unhandled or logged exceptions. Instead, sessions get correctly marked as `SessionEndStatus.Unhandled` ([#2376](https://github.com/getsentry/sentry-unity/pull/2376))
1616
- Added support for Structured Logging. The `SentrySdk.Logger` API is now exposed for Unity users, enabling structured log capture. The SDK can also automatically capture and send Debug logs based on the options configured. ([#2368](https://github.com/getsentry/sentry-unity/pull/2368))
1717

18+
### Fixes
19+
20+
- When configured, the SDK now no longer treats `Debug.LogError` events as exceptions but resports them as message events instead ([#2377](https://github.com/getsentry/sentry-unity/pull/2377))
21+
1822
### Dependencies
1923

2024
- Bump CLI from v2.56.0 to v2.56.1 ([#2356](https://github.com/getsentry/sentry-unity/pull/2356))

src/Sentry.Unity/Il2CppEventProcessor.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,6 @@ public void Process(Exception incomingException, SentryEvent sentryEvent)
3232
{
3333
Options.DiagnosticLogger?.LogDebug("Running Unity IL2CPP event exception processor on: Event {0}", sentryEvent.EventId);
3434

35-
// UnityLogException is a synthetic exception created by the LoggingIntegration by parsing the stacktrace provided
36-
// to the SDK as a string. It therefore lacks the necessary data to fetch the native stacktrace and go from there
37-
if (incomingException is UnityErrorLogException)
38-
{
39-
return;
40-
}
41-
4235
var sentryExceptions = sentryEvent.SentryExceptions;
4336
if (sentryExceptions == null)
4437
{
@@ -54,6 +47,12 @@ public void Process(Exception incomingException, SentryEvent sentryEvent)
5447
// In case they don't we update the offsets to match the GameAssembly library.
5548
foreach (var (sentryException, exception) in sentryExceptions.Zip(exceptions, (se, ex) => (se, ex)))
5649
{
50+
if (sentryException.Mechanism?.Synthetic is true)
51+
{
52+
// Skip synthetic exceptions since they have no native counterpart
53+
continue;
54+
}
55+
5756
var sentryStacktrace = sentryException.Stacktrace;
5857
if (sentryStacktrace == null)
5958
{

src/Sentry.Unity/Integrations/UnityApplicationLoggingIntegration.cs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@ private bool IsGettingDebounced(LogType logType)
8686
private void ProcessException(string message, string stacktrace, LogType logType)
8787
{
8888
// LogType.Exception is getting handled by the `UnityLogHandlerIntegration`
89-
// UNLESS we're configured to handle them - i.e. on WebGL
89+
// UNLESS we're configured to process them - i.e. on WebGL
9090
if (logType is LogType.Exception && _captureExceptions)
9191
{
9292
_options.LogDebug("Exception capture has been enabled. Capturing exception through '{0}'.", nameof(UnityApplicationLoggingIntegration));
9393

94-
var ule = new UnityErrorLogException(message, stacktrace, _options);
95-
_hub?.CaptureException(ule);
94+
var evt = UnityLogEventFactory.CreateExceptionEvent(message, stacktrace, false, _options);
95+
_hub?.CaptureEvent(evt);
9696
}
9797
}
9898

@@ -107,12 +107,8 @@ private void ProcessError(string message, string stacktrace, LogType logType)
107107

108108
if (_options.AttachStacktrace && !string.IsNullOrEmpty(stacktrace))
109109
{
110-
_options.LogDebug("Attaching stacktrace to event.");
111-
112-
var ule = new UnityErrorLogException(message, stacktrace, _options);
113-
var sentryEvent = new SentryEvent(ule) { Level = SentryLevel.Error };
114-
115-
_hub?.CaptureEvent(sentryEvent);
110+
var evt = UnityLogEventFactory.CreateMessageEvent(message, stacktrace, SentryLevel.Error, _options);
111+
_hub?.CaptureEvent(evt);
116112
}
117113
else
118114
{

src/Sentry.Unity/Integrations/UnityErrorLogException.cs

Lines changed: 0 additions & 173 deletions
This file was deleted.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using Sentry.Protocol;
5+
6+
namespace Sentry.Unity.Integrations;
7+
8+
/// <summary>
9+
/// Factory for creating SentryEvent objects from Unity log messages and stacktraces
10+
/// </summary>
11+
internal static class UnityLogEventFactory
12+
{
13+
/// <summary>
14+
/// Creates a message event with stacktrace attached via threads (for Debug.LogError)
15+
/// </summary>
16+
/// <param name="message">The log message</param>
17+
/// <param name="stackTrace">The Unity stacktrace string</param>
18+
/// <param name="level">The Sentry event level</param>
19+
/// <param name="options">Sentry Unity options</param>
20+
/// <returns>A SentryEvent with the message and stacktrace as threads</returns>
21+
public static SentryEvent CreateMessageEvent(
22+
string message,
23+
string stackTrace,
24+
SentryLevel level,
25+
SentryUnityOptions options)
26+
{
27+
var frames = UnityStackTraceParser.Parse(stackTrace, options);
28+
frames.Reverse();
29+
30+
var thread = CreateThreadFromStackTrace(frames);
31+
32+
return new SentryEvent
33+
{
34+
Message = message,
35+
Level = level,
36+
SentryThreads = [thread]
37+
};
38+
}
39+
40+
/// <summary>
41+
/// Creates an exception event from Unity log data (for exceptions on WebGL)
42+
/// </summary>
43+
/// <param name="message">The log message</param>
44+
/// <param name="stackTrace">The Unity stacktrace string</param>
45+
/// <param name="handled">Whether the exception was handled or not</param>
46+
/// /// <param name="options">Sentry Unity options</param>
47+
/// <returns>A SentryEvent with a synthetic exception</returns>
48+
public static SentryEvent CreateExceptionEvent(
49+
string message,
50+
string stackTrace,
51+
bool handled,
52+
SentryUnityOptions options)
53+
{
54+
var frames = UnityStackTraceParser.Parse(stackTrace, options);
55+
frames.Reverse();
56+
57+
return new SentryEvent
58+
{
59+
SentryExceptions = [new SentryException
60+
{
61+
Stacktrace = new SentryStackTrace { Frames = frames },
62+
Value = message,
63+
Type = "LogException",
64+
Mechanism = new Mechanism
65+
{
66+
Handled = handled,
67+
Type = "unity.log",
68+
Terminal = false,
69+
Synthetic = true
70+
}
71+
}],
72+
Level = SentryLevel.Error
73+
};
74+
}
75+
76+
private static SentryThread CreateThreadFromStackTrace(List<SentryStackFrame> frames)
77+
{
78+
var currentThread = Thread.CurrentThread;
79+
return new SentryThread
80+
{
81+
Crashed = false,
82+
Current = true,
83+
Name = currentThread.Name,
84+
Id = currentThread.ManagedThreadId,
85+
Stacktrace = new SentryStackTrace { Frames = frames }
86+
};
87+
}
88+
}

0 commit comments

Comments
 (0)