diff --git a/CHANGELOG.md b/CHANGELOG.md index fb7ff6ca80..e5925af8ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Exception.HResult is now included in the mechanism data for all exceptions ([#4029](https://github.com/getsentry/sentry-dotnet/pull/4029)) + ### Dependencies - Bump CLI from v2.42.2 to v2.42.3 ([#4036](https://github.com/getsentry/sentry-dotnet/pull/4036)) diff --git a/src/Sentry/Internal/MainExceptionProcessor.cs b/src/Sentry/Internal/MainExceptionProcessor.cs index 57fca6597a..b80ab1ea94 100644 --- a/src/Sentry/Internal/MainExceptionProcessor.cs +++ b/src/Sentry/Internal/MainExceptionProcessor.cs @@ -199,6 +199,9 @@ private static Mechanism GetMechanism(Exception exception, int id, int? parentId exception.Data.Remove(Mechanism.DescriptionKey); } + // Add HResult to mechanism data before adding exception data, so that it can be overridden. + mechanism.Data["HResult"] = $"0x{exception.HResult:X8}"; + // Copy remaining exception data to mechanism data. foreach (var key in exception.Data.Keys.OfType()) { diff --git a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet8_0.verified.txt b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet8_0.verified.txt index 58b52da963..05803effbe 100644 --- a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet8_0.verified.txt +++ b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet8_0.verified.txt @@ -10,7 +10,15 @@ SentryExceptions: [ { Type: System.Exception, - Value: my exception + Value: my exception, + Mechanism: { + Type: generic, + Synthetic: false, + IsExceptionGroup: false, + Data: { + HResult: 0x80131500 + } + } } ], Level: error, diff --git a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet9_0.verified.txt b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet9_0.verified.txt index 58b52da963..05803effbe 100644 --- a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet9_0.verified.txt +++ b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet9_0.verified.txt @@ -10,7 +10,15 @@ SentryExceptions: [ { Type: System.Exception, - Value: my exception + Value: my exception, + Mechanism: { + Type: generic, + Synthetic: false, + IsExceptionGroup: false, + Data: { + HResult: 0x80131500 + } + } } ], Level: error, diff --git a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.Net4_8.verified.txt b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.Net4_8.verified.txt index 57227d296e..75d6b3e321 100644 --- a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.Net4_8.verified.txt +++ b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.Net4_8.verified.txt @@ -10,7 +10,15 @@ SentryExceptions: [ { Type: System.Exception, - Value: my exception + Value: my exception, + Mechanism: { + Type: generic, + Synthetic: false, + IsExceptionGroup: false, + Data: { + HResult: 0x80131500 + } + } } ], Level: error, diff --git a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsSqlAsync.verified.txt b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsSqlAsync.verified.txt index 0172e27d4e..e317514b27 100644 --- a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsSqlAsync.verified.txt +++ b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsSqlAsync.verified.txt @@ -10,7 +10,15 @@ SentryExceptions: [ { Type: System.Exception, - Value: my exception + Value: my exception, + Mechanism: { + Type: generic, + Synthetic: false, + IsExceptionGroup: false, + Data: { + HResult: 0x80131500 + } + } } ], Level: error, diff --git a/test/Sentry.EntityFramework.Tests/IntegrationTests.Simple.verified.txt b/test/Sentry.EntityFramework.Tests/IntegrationTests.Simple.verified.txt index e24261c17c..826fb58e95 100644 --- a/test/Sentry.EntityFramework.Tests/IntegrationTests.Simple.verified.txt +++ b/test/Sentry.EntityFramework.Tests/IntegrationTests.Simple.verified.txt @@ -10,7 +10,15 @@ SentryExceptions: [ { Type: System.Exception, - Value: my exception + Value: my exception, + Mechanism: { + Type: generic, + Synthetic: false, + IsExceptionGroup: false, + Data: { + HResult: 0x80131500 + } + } } ], Level: error, diff --git a/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt b/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt index 0546a4fe28..c1b263a0fb 100644 --- a/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt +++ b/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt @@ -59,7 +59,10 @@ Type: generic, Handled: true, Synthetic: false, - IsExceptionGroup: false + IsExceptionGroup: false, + Data: { + HResult: 0x80131500 + } } } ], diff --git a/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet9_0.verified.txt b/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet9_0.verified.txt index 0546a4fe28..c1b263a0fb 100644 --- a/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet9_0.verified.txt +++ b/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet9_0.verified.txt @@ -59,7 +59,10 @@ Type: generic, Handled: true, Synthetic: false, - IsExceptionGroup: false + IsExceptionGroup: false, + Data: { + HResult: 0x80131500 + } } } ], diff --git a/test/Sentry.NLog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt b/test/Sentry.NLog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt index 983ec3e5c1..099ffe6958 100644 --- a/test/Sentry.NLog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt +++ b/test/Sentry.NLog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt @@ -59,7 +59,10 @@ Type: generic, Handled: true, Synthetic: false, - IsExceptionGroup: false + IsExceptionGroup: false, + Data: { + HResult: 0x80131500 + } } } ], diff --git a/test/Sentry.NLog.Tests/IntegrationTests.Simple.Net4_8.verified.txt b/test/Sentry.NLog.Tests/IntegrationTests.Simple.Net4_8.verified.txt index 0546a4fe28..c1b263a0fb 100644 --- a/test/Sentry.NLog.Tests/IntegrationTests.Simple.Net4_8.verified.txt +++ b/test/Sentry.NLog.Tests/IntegrationTests.Simple.Net4_8.verified.txt @@ -59,7 +59,10 @@ Type: generic, Handled: true, Synthetic: false, - IsExceptionGroup: false + IsExceptionGroup: false, + Data: { + HResult: 0x80131500 + } } } ], diff --git a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt index 1f894bd0ef..e426868eab 100644 --- a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt +++ b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt @@ -224,7 +224,8 @@ Synthetic: false, IsExceptionGroup: false, Data: { - details: Do work always throws. + details: Do work always throws., + HResult: 0x80131500 } } } diff --git a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet9_0.verified.txt b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet9_0.verified.txt index 1f894bd0ef..e426868eab 100644 --- a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet9_0.verified.txt +++ b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet9_0.verified.txt @@ -224,7 +224,8 @@ Synthetic: false, IsExceptionGroup: false, Data: { - details: Do work always throws. + details: Do work always throws., + HResult: 0x80131500 } } } diff --git a/test/Sentry.Tests/Internals/MainExceptionProcessorTests.CreateSentryException_Aggregate.verified.txt b/test/Sentry.Tests/Internals/MainExceptionProcessorTests.CreateSentryException_Aggregate.verified.txt index d48b44f301..520f33f3fa 100644 --- a/test/Sentry.Tests/Internals/MainExceptionProcessorTests.CreateSentryException_Aggregate.verified.txt +++ b/test/Sentry.Tests/Internals/MainExceptionProcessorTests.CreateSentryException_Aggregate.verified.txt @@ -8,7 +8,10 @@ Synthetic: false, IsExceptionGroup: false, ExceptionId: 2, - ParentId: 0 + ParentId: 0, + Data: { + HResult: 0x80131500 + } } }, { @@ -20,7 +23,10 @@ Synthetic: false, IsExceptionGroup: false, ExceptionId: 1, - ParentId: 0 + ParentId: 0, + Data: { + HResult: 0x80131500 + } } }, { @@ -33,7 +39,8 @@ IsExceptionGroup: true, ExceptionId: 0, Data: { - foo: bar + foo: bar, + HResult: 0x80131500 } } } diff --git a/test/Sentry.Tests/Internals/MainExceptionProcessorTests.cs b/test/Sentry.Tests/Internals/MainExceptionProcessorTests.cs index 8d9c5ab1ca..f5dedc0b4e 100644 --- a/test/Sentry.Tests/Internals/MainExceptionProcessorTests.cs +++ b/test/Sentry.Tests/Internals/MainExceptionProcessorTests.cs @@ -12,7 +12,7 @@ private class Fixture private readonly Fixture _fixture = new(); [Fact] - public void Process_ExceptionsWithoutData_MechanismDataIsEmpty() + public void Process_ExceptionsWithoutData_MechanismDataIsMinimal() { var sut = _fixture.GetSut(); var evt = new SentryEvent(); @@ -21,7 +21,12 @@ public void Process_ExceptionsWithoutData_MechanismDataIsEmpty() sut.Process(ex, evt); var sentryException = evt.SentryExceptions!.Single(); - Assert.Empty(sentryException.Mechanism!.Data); + + // All managed exceptions has an HResult, at a bare minimum (which we store in the Mechanism.Data) + sentryException.Mechanism!.Data.Should().BeEquivalentTo(new Dictionary() + { + ["HResult"] = "0x80131500" // The default value of HRESULT for managed exceptions (COR_E_EXCEPTION) + }); } [Fact] @@ -109,7 +114,13 @@ public void CreateSentryException_DataHasObjectAsKey_ItemIgnored() var actual = sut.CreateSentryExceptions(ex).Single(); - Assert.Null(actual.Mechanism); + // The custom data won't be added, but the mechanism data will still contain an HResult. + // We add the HResult for all exceptions + actual.Mechanism!.Data.Should().BeEquivalentTo(new Dictionary() + { + ["HResult"] = "0x80131500" // The default value of HRESULT for managed exceptions (COR_E_EXCEPTION) + }); + } [Fact]