Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
- 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))
- 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))

### Fixes

- 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))

### Dependencies

- Bump CLI from v2.56.0 to v2.56.1 ([#2356](https://github.com/getsentry/sentry-unity/pull/2356))
Expand Down
13 changes: 6 additions & 7 deletions src/Sentry.Unity/Il2CppEventProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,6 @@ public void Process(Exception incomingException, SentryEvent sentryEvent)
{
Options.DiagnosticLogger?.LogDebug("Running Unity IL2CPP event exception processor on: Event {0}", sentryEvent.EventId);

// UnityLogException is a synthetic exception created by the LoggingIntegration by parsing the stacktrace provided
// to the SDK as a string. It therefore lacks the necessary data to fetch the native stacktrace and go from there
if (incomingException is UnityErrorLogException)
{
return;
}

var sentryExceptions = sentryEvent.SentryExceptions;
if (sentryExceptions == null)
{
Expand All @@ -54,6 +47,12 @@ public void Process(Exception incomingException, SentryEvent sentryEvent)
// In case they don't we update the offsets to match the GameAssembly library.
foreach (var (sentryException, exception) in sentryExceptions.Zip(exceptions, (se, ex) => (se, ex)))
{
if (sentryException.Mechanism?.Synthetic is true)
{
// Skip synthetic exceptions since they have no native counterpart
continue;
}

var sentryStacktrace = sentryException.Stacktrace;
if (sentryStacktrace == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,13 @@ private bool IsGettingDebounced(LogType logType)
private void ProcessException(string message, string stacktrace, LogType logType)
{
// LogType.Exception is getting handled by the `UnityLogHandlerIntegration`
// UNLESS we're configured to handle them - i.e. on WebGL
// UNLESS we're configured to process them - i.e. on WebGL
if (logType is LogType.Exception && _captureExceptions)
{
_options.LogDebug("Exception capture has been enabled. Capturing exception through '{0}'.", nameof(UnityApplicationLoggingIntegration));

var ule = new UnityErrorLogException(message, stacktrace, _options);
_hub?.CaptureException(ule);
var evt = UnityLogEventFactory.CreateExceptionEvent(message, stacktrace, false, _options);
_hub?.CaptureEvent(evt);
}
}

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

if (_options.AttachStacktrace && !string.IsNullOrEmpty(stacktrace))
{
_options.LogDebug("Attaching stacktrace to event.");

var ule = new UnityErrorLogException(message, stacktrace, _options);
var sentryEvent = new SentryEvent(ule) { Level = SentryLevel.Error };

_hub?.CaptureEvent(sentryEvent);
var evt = UnityLogEventFactory.CreateMessageEvent(message, stacktrace, SentryLevel.Error, _options);
_hub?.CaptureEvent(evt);
}
else
{
Expand Down
173 changes: 0 additions & 173 deletions src/Sentry.Unity/Integrations/UnityErrorLogException.cs

This file was deleted.

88 changes: 88 additions & 0 deletions src/Sentry.Unity/Integrations/UnityLogEventFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Sentry.Protocol;

namespace Sentry.Unity.Integrations;

/// <summary>
/// Factory for creating SentryEvent objects from Unity log messages and stacktraces
/// </summary>
internal static class UnityLogEventFactory
{
/// <summary>
/// Creates a message event with stacktrace attached via threads (for Debug.LogError)
/// </summary>
/// <param name="message">The log message</param>
/// <param name="stackTrace">The Unity stacktrace string</param>
/// <param name="level">The Sentry event level</param>
/// <param name="options">Sentry Unity options</param>
/// <returns>A SentryEvent with the message and stacktrace as threads</returns>
public static SentryEvent CreateMessageEvent(
string message,
string stackTrace,
SentryLevel level,
SentryUnityOptions options)
{
var frames = UnityStackTraceParser.Parse(stackTrace, options);
frames.Reverse();

var thread = CreateThreadFromStackTrace(frames);

return new SentryEvent
{
Message = message,
Level = level,
SentryThreads = [thread]
};
}

/// <summary>
/// Creates an exception event from Unity log data (for exceptions on WebGL)
/// </summary>
/// <param name="message">The log message</param>
/// <param name="stackTrace">The Unity stacktrace string</param>
/// <param name="handled">Whether the exception was handled or not</param>
/// /// <param name="options">Sentry Unity options</param>
/// <returns>A SentryEvent with a synthetic exception</returns>
public static SentryEvent CreateExceptionEvent(
string message,
string stackTrace,
bool handled,
SentryUnityOptions options)
{
var frames = UnityStackTraceParser.Parse(stackTrace, options);
frames.Reverse();

return new SentryEvent
{
SentryExceptions = [new SentryException
{
Stacktrace = new SentryStackTrace { Frames = frames },
Value = message,
Type = "LogException",
Mechanism = new Mechanism
{
Handled = handled,
Type = "unity.log",
Terminal = false,
Synthetic = true
}
}],
Level = SentryLevel.Error
};
}

private static SentryThread CreateThreadFromStackTrace(List<SentryStackFrame> frames)
{
var currentThread = Thread.CurrentThread;
return new SentryThread
{
Crashed = false,
Current = true,
Name = currentThread.Name,
Id = currentThread.ManagedThreadId,
Stacktrace = new SentryStackTrace { Frames = frames }
};
}
}
Loading
Loading