Skip to content
Closed
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
16 changes: 15 additions & 1 deletion samples/Sentry.Samples.Console.Customized/Program.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 =>
Expand Down Expand Up @@ -147,7 +155,6 @@ await SentrySdk.ConfigureScopeAsync(async scope =>
SentrySdk.CaptureException(error);
}


var count = 10;
for (var i = 0; i < count; i++)
{
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
<TargetFrameworks>netcoreapp2.1;net472</TargetFrameworks>
<!--Set explicitly to demonstrate one way of defining the Sentry Release-->
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<!-- To be able to load structuremap 4.4.0 which is unsigned-->
<SignAssembly>false</SignAssembly>
</PropertyGroup>

<ItemGroup>
Expand All @@ -14,5 +16,8 @@
<Reference Include="System.Net.Http" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="structuremap" Version="4.4.0" />
</ItemGroup>

</Project>
68 changes: 68 additions & 0 deletions src/Sentry/Integrations/UnoptimizedAssemblyIntegration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Linq;
using Sentry.Extensibility;
using Sentry.Protocol;
using Sentry.Reflection;

namespace Sentry.Integrations
{
/// <summary>
/// An integration that emits events when detects assemblies compiled for debug.
/// </summary>
public class UnoptimizedAssemblyIntegration : ISdkIntegration
{
/// <summary>
/// Registers the integration with the hub and options.
/// </summary>
/// <param name="hub">The hub to use to send events.</param>
/// <param name="options">The options to configure the integration.</param>
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.");
}
}
}
}
}
16 changes: 16 additions & 0 deletions src/Sentry/Reflection/AssemblyExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using Sentry.Protocol;

Expand Down Expand Up @@ -29,5 +30,20 @@ public static SdkVersion GetNameAndVersion(this Assembly asm)

return new SdkVersion { Name = name, Version = version };
}

/// <summary>
/// Whether the assembly was compiled with the optimize+ flag
/// </summary>
/// <param name="asm">The assembly to verify the optimization flag</param>
/// <returns>
/// true if no <see cref="DebuggableAttribute"/> exists or
/// <see cref="DebuggableAttribute.IsJITOptimizerDisabled"/> is false,
/// otherwise, false.
/// </returns>
public static bool IsOptimized(this Assembly asm)
{
var att = asm.GetCustomAttribute<DebuggableAttribute>();
return att == null || att.IsJITOptimizerDisabled == false;
}
}
}
8 changes: 7 additions & 1 deletion src/Sentry/SentryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,11 @@ public IDiagnosticLogger DiagnosticLogger
/// </summary>
public bool ReportAssemblies { get; set; } = true;

/// <summary>
/// Whether the SDK should raise events if unoptimized assemblies are loaded.
/// </summary>
public bool NotifyUnoptimizedAssembly { get; set; }

/// <summary>
/// What modes to use for event automatic deduplication
/// </summary>
Expand Down Expand Up @@ -411,7 +416,8 @@ public SentryOptions()
Integrations
= ImmutableList.Create<ISdkIntegration>(
new AppDomainUnhandledExceptionIntegration(),
new AppDomainProcessExitIntegration());
new AppDomainProcessExitIntegration(),
new UnoptimizedAssemblyIntegration());

InAppExclude
= ImmutableList.Create(
Expand Down