|
4 | 4 | using Sentry.Profiling; |
5 | 5 | using System; |
6 | 6 | using System.Diagnostics; |
| 7 | +using System.Linq; |
7 | 8 | using System.Reflection; |
8 | 9 |
|
9 | 10 | namespace Chromatics.Core |
@@ -188,6 +189,18 @@ public static void Initialize() |
188 | 189 | // drops everything else when consent is off. |
189 | 190 | o.SetBeforeSend((evt, _) => |
190 | 191 | { |
| 192 | + // Drop unobserved-task SocketException noise (Hue/OpenRGB |
| 193 | + // shutdown, transient network resets) before consent gating. |
| 194 | + // These are auto-captured by Sentry's UnobservedTaskException |
| 195 | + // integration and would otherwise spam the Issues tab; our |
| 196 | + // own UnobservedTaskExceptionHandler already filters them |
| 197 | + // from the crash flow on the same criteria. |
| 198 | + if (evt.Exception != null && IsBenignBackgroundException(evt.Exception)) |
| 199 | + { |
| 200 | + Logger.WriteVerbose($"[Sentry] BeforeSend dropped event {evt.EventId} — benign background exception ({evt.Exception.GetType().Name})"); |
| 201 | + return null; |
| 202 | + } |
| 203 | + |
191 | 204 | var s = _settings; |
192 | 205 | bool consent = s == null || s.enableCrashReports; |
193 | 206 | bool isCrash = evt.Exception?.Data.Contains("Chromatics.HandledByCrashDialog") == true |
@@ -571,6 +584,39 @@ public static void Shutdown() |
571 | 584 | _sdkHandle?.Dispose(); |
572 | 585 | _initialized = false; |
573 | 586 | } |
| 587 | + |
| 588 | + // Mirror of Program.IsBenignBackgroundException — kept private to |
| 589 | + // SentryService so the BeforeSend filter doesn't take a hard dep on |
| 590 | + // Program. Both must agree on what's "benign" or events get dropped |
| 591 | + // here while the crash flow still kills the app, or vice versa. |
| 592 | + private static bool IsBenignBackgroundException(Exception ex) |
| 593 | + { |
| 594 | + if (ex is null) return false; |
| 595 | + if (ex is AggregateException agg) |
| 596 | + { |
| 597 | + var flat = agg.Flatten(); |
| 598 | + return flat.InnerExceptions.Count > 0 && flat.InnerExceptions.All(IsBenignBackgroundException); |
| 599 | + } |
| 600 | + return ex switch |
| 601 | + { |
| 602 | + System.Net.Sockets.SocketException se => IsBenignSocketError(se.SocketErrorCode), |
| 603 | + System.IO.IOException io => io.InnerException is System.Net.Sockets.SocketException ise && IsBenignSocketError(ise.SocketErrorCode), |
| 604 | + ObjectDisposedException => true, |
| 605 | + OperationCanceledException => true, |
| 606 | + _ => false, |
| 607 | + }; |
| 608 | + } |
| 609 | + |
| 610 | + private static bool IsBenignSocketError(System.Net.Sockets.SocketError code) => code switch |
| 611 | + { |
| 612 | + System.Net.Sockets.SocketError.OperationAborted => true, |
| 613 | + System.Net.Sockets.SocketError.ConnectionReset => true, |
| 614 | + System.Net.Sockets.SocketError.ConnectionAborted => true, |
| 615 | + System.Net.Sockets.SocketError.Interrupted => true, |
| 616 | + System.Net.Sockets.SocketError.Shutdown => true, |
| 617 | + System.Net.Sockets.SocketError.NetworkReset => true, |
| 618 | + _ => false, |
| 619 | + }; |
574 | 620 | } |
575 | 621 |
|
576 | 622 | /// <summary> |
|
0 commit comments