@@ -1313,6 +1313,60 @@ public async Task CaptureExceptionWithDivideByZeroException() // based on PostHo
13131313 }
13141314 }
13151315
1316+ [ Fact ]
1317+ public async Task CaptureExceptionUsesLogicalAsyncMethodName ( )
1318+ {
1319+ var ( _, requestHandler , client ) = CreateClient ( ) ;
1320+ var exception = await CreateExceptionAfterAwaitAsync ( ) ;
1321+
1322+ client . CaptureException ( exception , "some-distinct-id" ) ;
1323+ await client . FlushAsync ( ) ;
1324+
1325+ var ( _, _, properties ) = ParseSingleEvent ( requestHandler . GetReceivedRequestBody ( indented : false ) ) ;
1326+ var frames = GetStackFrames ( GetFirstException ( properties ) ) ;
1327+
1328+ Assert . Contains ( frames , frame =>
1329+ frame . GetProperty ( "function" ) . GetString ( ) == nameof ( CreateExceptionAfterAwaitAsync ) &&
1330+ frame . GetProperty ( "module" ) . GetString ( ) == typeof ( TheCaptureExceptionMethod ) . FullName ) ;
1331+ Assert . DoesNotContain ( frames , frame => frame . GetProperty ( "function" ) . GetString ( ) == "MoveNext" ) ;
1332+ }
1333+
1334+ [ Fact ]
1335+ public async Task CaptureExceptionUsesLogicalAsyncIteratorMethodName ( )
1336+ {
1337+ var ( _, requestHandler , client ) = CreateClient ( ) ;
1338+ var exception = await CreateExceptionFromAsyncIteratorAsync ( ) ;
1339+
1340+ client . CaptureException ( exception , "some-distinct-id" ) ;
1341+ await client . FlushAsync ( ) ;
1342+
1343+ var ( _, _, properties ) = ParseSingleEvent ( requestHandler . GetReceivedRequestBody ( indented : false ) ) ;
1344+ var frames = GetStackFrames ( GetFirstException ( properties ) ) ;
1345+
1346+ Assert . Contains ( frames , frame =>
1347+ frame . GetProperty ( "function" ) . GetString ( ) == nameof ( ThrowFromAsyncIteratorAfterAwait ) &&
1348+ frame . GetProperty ( "module" ) . GetString ( ) == typeof ( TheCaptureExceptionMethod ) . FullName ) ;
1349+ Assert . DoesNotContain ( frames , frame => frame . GetProperty ( "function" ) . GetString ( ) == "MoveNext" ) ;
1350+ }
1351+
1352+ #if NET8_0_OR_GREATER
1353+ [ Fact ]
1354+ public async Task CaptureExceptionOmitsStackTraceHiddenFrames ( )
1355+ {
1356+ var ( _, requestHandler , client ) = CreateClient ( ) ;
1357+ var exception = CreateExceptionThroughHiddenMethod ( ) ;
1358+
1359+ client . CaptureException ( exception , "some-distinct-id" ) ;
1360+ await client . FlushAsync ( ) ;
1361+
1362+ var ( _, _, properties ) = ParseSingleEvent ( requestHandler . GetReceivedRequestBody ( indented : false ) ) ;
1363+ var frames = GetStackFrames ( GetFirstException ( properties ) ) ;
1364+
1365+ Assert . DoesNotContain ( frames , frame =>
1366+ frame . GetProperty ( "function" ) . GetString ( ) == nameof ( ThrowFromHiddenMethod ) ) ;
1367+ }
1368+ #endif
1369+
13161370 [ Fact ]
13171371 public async Task CaptureExceptionWithAggregateException ( )
13181372 {
@@ -1571,6 +1625,65 @@ public static void Boom()
15711625 }
15721626 }
15731627
1628+ private static async Task < InvalidOperationException > CreateExceptionAfterAwaitAsync ( )
1629+ {
1630+ try
1631+ {
1632+ await Task . Yield ( ) ;
1633+ throw new InvalidOperationException ( "Async exception" ) ;
1634+ }
1635+ catch ( InvalidOperationException exception )
1636+ {
1637+ return exception ;
1638+ }
1639+ }
1640+
1641+ private static async Task < InvalidOperationException > CreateExceptionFromAsyncIteratorAsync ( )
1642+ {
1643+ try
1644+ {
1645+ await foreach ( var _ in ThrowFromAsyncIteratorAfterAwait ( ) )
1646+ {
1647+ }
1648+
1649+ throw new InvalidOperationException ( "Unreachable" ) ;
1650+ }
1651+ catch ( InvalidOperationException exception )
1652+ {
1653+ return exception ;
1654+ }
1655+ }
1656+
1657+ private static async IAsyncEnumerable < int > ThrowFromAsyncIteratorAfterAwait ( )
1658+ {
1659+ await Task . Yield ( ) ;
1660+ if ( DateTime . UtcNow . Year == 1 )
1661+ {
1662+ yield return 0 ;
1663+ }
1664+
1665+ throw new InvalidOperationException ( "Async iterator exception" ) ;
1666+ }
1667+
1668+ #if NET8_0_OR_GREATER
1669+ private static InvalidOperationException CreateExceptionThroughHiddenMethod ( )
1670+ {
1671+ try
1672+ {
1673+ ThrowFromHiddenMethod ( ) ;
1674+ throw new InvalidOperationException ( "Unreachable" ) ;
1675+ }
1676+ catch ( InvalidOperationException exception )
1677+ {
1678+ return exception ;
1679+ }
1680+ }
1681+
1682+ [ System . Diagnostics . StackTraceHidden ]
1683+ private static void ThrowFromHiddenMethod ( )
1684+ => throw new InvalidOperationException ( "Hidden exception" ) ;
1685+ #endif
1686+
15741687 // This test is pretty expensive because it dynamically compiles and loads an assembly.
15751688 // Consider alternatives.
15761689 [ Fact ]
@@ -2322,4 +2435,4 @@ await Assert.ThrowsAsync<OperationCanceledException>(() =>
23222435 Assert . DoesNotContain ( errorLogs , log =>
23232436 log . Message ? . Contains ( "Failed to load feature flags" , StringComparison . Ordinal ) == true ) ;
23242437 }
2325- }
2438+ }
0 commit comments