diff --git a/samples/Sentry.Samples.Console.Customized/Program.cs b/samples/Sentry.Samples.Console.Customized/Program.cs
index 7a106f0263..63539e2fd9 100644
--- a/samples/Sentry.Samples.Console.Customized/Program.cs
+++ b/samples/Sentry.Samples.Console.Customized/Program.cs
@@ -1,6 +1,7 @@
using System;
using System.Net.Http;
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Sentry;
using Sentry.Extensibility;
@@ -47,6 +48,9 @@ await SentrySdk.ConfigureScopeAsync(async scope =>
// Before excluding all prefixed 'LibraryX.', any stack trace from a type namespaced 'LibraryX.Core' will be considered InApp.
o.AddInAppInclude("LibraryX.Core");
+ // Send events whe unoptimized assemblies are detected
+ o.NotifyUnoptimizedAssembly = true;
+
// Send personal identifiable information like the username logged on to the computer and machine name
o.SendDefaultPii = true;
@@ -108,6 +112,10 @@ await SentrySdk.ConfigureScopeAsync(async scope =>
SentrySdk.AddBreadcrumb(
"A 'bad breadcrumb' that will be rejected because of 'BeforeBreadcrumb callback above.'");
+ // Because 'NotifyUnoptimizedAssembly' is enabled, calling this method will raise an event to alert
+ // that an Assembly that is compiled for Debug was loaded.
+ LoadUnoptimizedAssembly();
+
// Data added to the root scope (no PushScope called up to this point)
// The modifications done here will affect all events sent and will propagate to child scopes.
await SentrySdk.ConfigureScopeAsync(async scope =>
@@ -147,7 +155,6 @@ await SentrySdk.ConfigureScopeAsync(async scope =>
SentrySdk.CaptureException(error);
}
-
var count = 10;
for (var i = 0; i < count; i++)
{
@@ -196,6 +203,13 @@ await SentrySdk.ConfigureScopeAsync(async scope =>
} // On Dispose: SDK closed, events queued are flushed/sent to Sentry
}
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void LoadUnoptimizedAssembly()
+ {
+ // https://twitter.com/jeremydmiller/status/777571510919630848
+ Console.WriteLine(typeof(StructureMap.Container).Assembly.GetName().Version);
+ }
+
private class AdminPartMiddleware
{
private readonly ISentryClient _adminClient;
diff --git a/samples/Sentry.Samples.Console.Customized/Sentry.Samples.Console.Customized.csproj b/samples/Sentry.Samples.Console.Customized/Sentry.Samples.Console.Customized.csproj
index 70771ec60a..9de0801c9a 100644
--- a/samples/Sentry.Samples.Console.Customized/Sentry.Samples.Console.Customized.csproj
+++ b/samples/Sentry.Samples.Console.Customized/Sentry.Samples.Console.Customized.csproj
@@ -5,6 +5,8 @@
netcoreapp2.1;net472
false
+
+ false
@@ -14,5 +16,8 @@
+
+
+
diff --git a/src/Sentry/Integrations/UnoptimizedAssemblyIntegration.cs b/src/Sentry/Integrations/UnoptimizedAssemblyIntegration.cs
new file mode 100644
index 0000000000..831d34a712
--- /dev/null
+++ b/src/Sentry/Integrations/UnoptimizedAssemblyIntegration.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Linq;
+using Sentry.Extensibility;
+using Sentry.Protocol;
+using Sentry.Reflection;
+
+namespace Sentry.Integrations
+{
+ ///
+ /// An integration that emits events when detects assemblies compiled for debug.
+ ///
+ public class UnoptimizedAssemblyIntegration : ISdkIntegration
+ {
+ ///
+ /// Registers the integration with the hub and options.
+ ///
+ /// The hub to use to send events.
+ /// The options to configure the integration.
+ public void Register(IHub hub, SentryOptions options)
+ {
+ if (options.NotifyUnoptimizedAssembly)
+ {
+ options.DiagnosticLogger?.LogDebug("Subscribing to AssemblyLoad to detect unoptimized assemblies.");
+ // TODO: .NET Core equivalent
+ AppDomain.CurrentDomain.AssemblyLoad += (sender, args) =>
+ {
+ if (!args.LoadedAssembly.IsOptimized())
+ {
+ CaptureEvent(hub, options, args.LoadedAssembly.FullName);
+ hub.FlushAsync(TimeSpan.FromSeconds(10)).GetAwaiter().GetResult();
+ }
+ };
+
+ var unoptimizedAssemblies = AppDomain.CurrentDomain.GetAssemblies()
+ .Where(a => !a.IsOptimized())
+ .Select(a => a.FullName)
+ .ToArray();
+
+ if (unoptimizedAssemblies.Any())
+ {
+ CaptureEvent(hub, options, unoptimizedAssemblies);
+ }
+ }
+ }
+
+ private static void CaptureEvent(IHub hub, SentryOptions options, params string[] assemblies)
+ {
+ if (assemblies.Length > 0)
+ {
+ options.DiagnosticLogger?.LogInfo("Unoptimized Assembly found. Raising event for {count} assemblies", assemblies.Length);
+ using (hub.PushScope())
+ {
+ hub.ConfigureScope(s =>
+ {
+ s.SetFingerprint(new[] {"UnoptimizedAssemblyIntegration"});
+ foreach (var asm in assemblies)
+ {
+ options.DiagnosticLogger?.LogInfo("Unoptimized Assembly: {asm}", asm);
+ s.SetExtra("unoptimized-assembly", asm);
+ }
+ s.Level = SentryLevel.Warning;
+ });
+ hub.CaptureMessage("Unoptimized assembly detected.");
+ }
+ }
+ }
+ }
+}
diff --git a/src/Sentry/Reflection/AssemblyExtensions.cs b/src/Sentry/Reflection/AssemblyExtensions.cs
index 4a9836d0cb..76648ed708 100644
--- a/src/Sentry/Reflection/AssemblyExtensions.cs
+++ b/src/Sentry/Reflection/AssemblyExtensions.cs
@@ -1,4 +1,5 @@
using System.ComponentModel;
+using System.Diagnostics;
using System.Reflection;
using Sentry.Protocol;
@@ -29,5 +30,20 @@ public static SdkVersion GetNameAndVersion(this Assembly asm)
return new SdkVersion { Name = name, Version = version };
}
+
+ ///
+ /// Whether the assembly was compiled with the optimize+ flag
+ ///
+ /// The assembly to verify the optimization flag
+ ///
+ /// true if no exists or
+ /// is false,
+ /// otherwise, false.
+ ///
+ public static bool IsOptimized(this Assembly asm)
+ {
+ var att = asm.GetCustomAttribute();
+ return att == null || att.IsJITOptimizerDisabled == false;
+ }
}
}
diff --git a/src/Sentry/SentryOptions.cs b/src/Sentry/SentryOptions.cs
index 25c28d1d84..1a721f8e14 100644
--- a/src/Sentry/SentryOptions.cs
+++ b/src/Sentry/SentryOptions.cs
@@ -349,6 +349,11 @@ public IDiagnosticLogger DiagnosticLogger
///
public bool ReportAssemblies { get; set; } = true;
+ ///
+ /// Whether the SDK should raise events if unoptimized assemblies are loaded.
+ ///
+ public bool NotifyUnoptimizedAssembly { get; set; }
+
///
/// What modes to use for event automatic deduplication
///
@@ -411,7 +416,8 @@ public SentryOptions()
Integrations
= ImmutableList.Create(
new AppDomainUnhandledExceptionIntegration(),
- new AppDomainProcessExitIntegration());
+ new AppDomainProcessExitIntegration(),
+ new UnoptimizedAssemblyIntegration());
InAppExclude
= ImmutableList.Create(