Skip to content

Commit

Permalink
Automatically capture heap dumps (#3667)
Browse files Browse the repository at this point in the history
  • Loading branch information
jamescrosswell authored Nov 19, 2024
1 parent ed36c19 commit 3fde00a
Show file tree
Hide file tree
Showing 36 changed files with 1,256 additions and 10 deletions.
7 changes: 7 additions & 0 deletions .generated.NoMobile.sln
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "root", "root", "{233D34AB-9
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.AspNetCore.Blazor.WebAssembly", "src\Sentry.AspNetCore.Blazor.WebAssembly\Sentry.AspNetCore.Blazor.WebAssembly.csproj", "{8298202C-9983-4D0A-851D-805539EE481A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Samples.Console.HeapDump", "samples\Sentry.Samples.Console.HeapDump\Sentry.Samples.Console.HeapDump.csproj", "{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -493,6 +495,10 @@ Global
{A5B26C14-7313-4EDC-91E3-287F9374AB75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5B26C14-7313-4EDC-91E3-287F9374AB75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5B26C14-7313-4EDC-91E3-287F9374AB75}.Release|Any CPU.Build.0 = Release|Any CPU
{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -575,5 +581,6 @@ Global
{46E40BE8-1AB0-4846-B0A2-A40AD0272C64} = {6987A1CC-608E-4868-A02C-09D30C8B7B2D}
{8298202C-9983-4D0A-851D-805539EE481A} = {230B9384-90FD-4551-A5DE-1A5C197F25B6}
{A5B26C14-7313-4EDC-91E3-287F9374AB75} = {21B42F60-5802-404E-90F0-AEBCC56760C0}
{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821} = {21B42F60-5802-404E-90F0-AEBCC56760C0}
EndGlobalSection
EndGlobal
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- `SentryOptions.EnableTracing` has been removed. Instead, tracing should be enabled or disabled by setting the `SentryOptions.TracesSampleRate` or by using `SentryOptions.TracesSampler` to configure a sampling function ([#3569](https://github.com/getsentry/sentry-dotnet/pull/3569))
- The `FailedRequestTargets`, `TagFilters` and `TracePropagationTargets` options have all been changed from `SubstringOrRegexPattern` to `IList<StringOrRegex>` ([#3566](https://github.com/getsentry/sentry-dotnet/pull/3566))
- `Scope.Transaction` is now always stored as an `AsyncLocal` also in [Global Mode](https://docs.sentry.io/platforms/dotnet/configuration/options/#is-global-mode-enabled), to prevent auto-instrumented spans from the UI ending up parented to transactions from a background task (or vice versa). ([#3596](https://github.com/getsentry/sentry-dotnet/pull/3596))
- Heap dumps can be captured automatically when memory usage exceeds a configurable threshold ([#3667](https://github.com/getsentry/sentry-dotnet/pull/3667))
- Sentry's Experimental Metrics feature has been deprecated and removed from the SDK. ([#3718](https://github.com/getsentry/sentry-dotnet/pull/3718))

### Features
Expand Down
9 changes: 9 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@
<SentryCLIDirectory>$(MSBuildThisFileDirectory)tools\sentry-cli\$(SentryCLIVersion)\</SentryCLIDirectory>
</PropertyGroup>

<!-- dotnet-gcdump needs net6+ and won't work on mobile. -->
<PropertyGroup>
<PlatformIsLegacy Condition="$(TargetFramework.StartsWith('net4')) or $(TargetFramework.StartsWith('netstandard'))">true</PlatformIsLegacy>
<PlatformIsMobile Condition="$(TargetFramework.EndsWith('android')) or $(TargetFramework.EndsWith('ios')) or $(TargetFramework.EndsWith('maccatalyst'))">true</PlatformIsMobile>
<MemoryDumpSupported Condition="!($(PlatformIsLegacy) == 'true' or $(PlatformIsMobile) == 'true')">true</MemoryDumpSupported>

<DefineConstants Condition="'$(MemoryDumpSupported)' == 'true'">$(DefineConstants);MEMORY_DUMP_SUPPORTED</DefineConstants>
</PropertyGroup>

<!-- Public key of .assets/Sentry.snk - not a secret. Used by other InternalsVisibleTo entries throughout the solution. -->
<PropertyGroup>
<SentryPublicKey>002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8</SentryPublicKey>
Expand Down
1 change: 1 addition & 0 deletions Sentry-CI-Build-Linux.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"samples\\Sentry.Samples.Azure.Functions.Worker\\Sentry.Samples.Azure.Functions.Worker.csproj",
"samples\\Sentry.Samples.Console.Basic\\Sentry.Samples.Console.Basic.csproj",
"samples\\Sentry.Samples.Console.Customized\\Sentry.Samples.Console.Customized.csproj",
"samples\\Sentry.Samples.Console.HeapDump\\Sentry.Samples.Console.HeapDump.csproj",
"samples\\Sentry.Samples.Console.Native\\Sentry.Samples.Console.Native.csproj",
"samples\\Sentry.Samples.Console.Profiling\\Sentry.Samples.Console.Profiling.csproj",
"samples\\Sentry.Samples.EntityFramework\\Sentry.Samples.EntityFramework.csproj",
Expand Down
1 change: 1 addition & 0 deletions Sentry-CI-Build-Windows.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"samples\\Sentry.Samples.Azure.Functions.Worker\\Sentry.Samples.Azure.Functions.Worker.csproj",
"samples\\Sentry.Samples.Console.Basic\\Sentry.Samples.Console.Basic.csproj",
"samples\\Sentry.Samples.Console.Customized\\Sentry.Samples.Console.Customized.csproj",
"samples\\Sentry.Samples.Console.HeapDump\\Sentry.Samples.Console.HeapDump.csproj",
"samples\\Sentry.Samples.Console.Native\\Sentry.Samples.Console.Native.csproj",
"samples\\Sentry.Samples.Console.Profiling\\Sentry.Samples.Console.Profiling.csproj",
"samples\\Sentry.Samples.EntityFramework\\Sentry.Samples.EntityFramework.csproj",
Expand Down
1 change: 1 addition & 0 deletions Sentry-CI-Build-macOS.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"samples\\Sentry.Samples.Azure.Functions.Worker\\Sentry.Samples.Azure.Functions.Worker.csproj",
"samples\\Sentry.Samples.Console.Basic\\Sentry.Samples.Console.Basic.csproj",
"samples\\Sentry.Samples.Console.Customized\\Sentry.Samples.Console.Customized.csproj",
"samples\\Sentry.Samples.Console.HeapDump\\Sentry.Samples.Console.HeapDump.csproj",
"samples\\Sentry.Samples.Console.Native\\Sentry.Samples.Console.Native.csproj",
"samples\\Sentry.Samples.Console.Profiling\\Sentry.Samples.Console.Profiling.csproj",
"samples\\Sentry.Samples.EntityFramework\\Sentry.Samples.EntityFramework.csproj",
Expand Down
7 changes: 7 additions & 0 deletions Sentry.sln
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "root", "root", "{233D34AB-9
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.AspNetCore.Blazor.WebAssembly", "src\Sentry.AspNetCore.Blazor.WebAssembly\Sentry.AspNetCore.Blazor.WebAssembly.csproj", "{8298202C-9983-4D0A-851D-805539EE481A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Samples.Console.HeapDump", "samples\Sentry.Samples.Console.HeapDump\Sentry.Samples.Console.HeapDump.csproj", "{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -502,6 +504,10 @@ Global
{A5B26C14-7313-4EDC-91E3-287F9374AB75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5B26C14-7313-4EDC-91E3-287F9374AB75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5B26C14-7313-4EDC-91E3-287F9374AB75}.Release|Any CPU.Build.0 = Release|Any CPU
{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -584,5 +590,6 @@ Global
{46E40BE8-1AB0-4846-B0A2-A40AD0272C64} = {6987A1CC-608E-4868-A02C-09D30C8B7B2D}
{8298202C-9983-4D0A-851D-805539EE481A} = {230B9384-90FD-4551-A5DE-1A5C197F25B6}
{A5B26C14-7313-4EDC-91E3-287F9374AB75} = {21B42F60-5802-404E-90F0-AEBCC56760C0}
{D7DF0B26-AD43-4F8B-9BFE-C4471CCC9821} = {21B42F60-5802-404E-90F0-AEBCC56760C0}
EndGlobalSection
EndGlobal
1 change: 1 addition & 0 deletions Sentry.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OS/@EntryIndexedValue">OS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QL/@EntryIndexedValue">QL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=debouncer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Enricher/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=enrichers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=instrumenter/@EntryIndexedValue">True</s:Boolean>
Expand Down
1 change: 1 addition & 0 deletions SentryNoMobile.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"samples\\Sentry.Samples.Azure.Functions.Worker\\Sentry.Samples.Azure.Functions.Worker.csproj",
"samples\\Sentry.Samples.Console.Basic\\Sentry.Samples.Console.Basic.csproj",
"samples\\Sentry.Samples.Console.Customized\\Sentry.Samples.Console.Customized.csproj",
"samples\\Sentry.Samples.Console.HeapDump\\Sentry.Samples.Console.HeapDump.csproj",
"samples\\Sentry.Samples.Console.Native\\Sentry.Samples.Console.Native.csproj",
"samples\\Sentry.Samples.Console.Profiling\\Sentry.Samples.Console.Profiling.csproj",
"samples\\Sentry.Samples.EntityFramework\\Sentry.Samples.EntityFramework.csproj",
Expand Down
2 changes: 1 addition & 1 deletion samples/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<!-- Workaround for hang on compile issue. See https://github.com/xamarin/xamarin-macios/issues/17825#issuecomment-1478568270. -->
<PropertyGroup Condition="'$(Configuration)' == 'Release' And '$(TargetFramework)' == 'net7.0-ios' And '$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'Arm64'">
<PropertyGroup Condition="'$(Configuration)' == 'Release' And $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
<MtouchUseLlvm>false</MtouchUseLlvm>
</PropertyGroup>
</Project>
6 changes: 3 additions & 3 deletions samples/Sentry.Samples.Console.Basic/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
* For more advanced features of the SDK, see Sentry.Samples.Console.Customized.
*/

// Initialize the Sentry SDK. (It is not necessary to dispose it.)

using System.Net.Http;
using static System.Console;

// Initialize the Sentry SDK. (It is not necessary to dispose it.)
SentrySdk.Init(options =>
{
// You can set here in code, or you can set it in the SENTRY_DSN environment variable.
Expand Down Expand Up @@ -55,7 +55,7 @@ async Task FirstFunction()
var messageHandler = new SentryHttpMessageHandler();
var httpClient = new HttpClient(messageHandler, true);
var html = await httpClient.GetStringAsync("https://example.com/");
Console.WriteLine(html);
WriteLine(html);
}

async Task SecondFunction()
Expand Down
72 changes: 72 additions & 0 deletions samples/Sentry.Samples.Console.HeapDump/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* This sample demonstrates how you can configure Sentry to automatically capture heap dumps based on certain memory
* triggers (e.g. if memory consumption exceeds a certain percentage threshold).
*
* Note that this functionality is only available when targeting net6.0 or above and is not available on iOS, Android
* or Mac Catalyst.
*/

using System.Reflection;
using static System.Console;

var cts = new CancellationTokenSource();

// Initialize the Sentry SDK. (It is not necessary to dispose it.)
SentrySdk.Init(options =>
{
// You can set here in code, or you can set it in the SENTRY_DSN environment variable.
// See https://docs.sentry.io/product/sentry-basics/dsn-explainer/
options.Dsn = "https://eb18e953812b41c3aeb042e666fd3b5c@o447951.ingest.sentry.io/5428537";

// When debug is enabled, the Sentry client will emit detailed debugging information to the console.
// This might be helpful, or might interfere with the normal operation of your application.
// We enable it here for demonstration purposes.
// You should not do this in your applications unless you are troubleshooting issues with Sentry.
options.Debug = true;

// Set TracesSampleRate = 0 to disable tracing for this demo
options.TracesSampleRate = 0;

// This option tells Sentry to capture a heap dump and send these as a file attachment in a Sentry event
options.EnableHeapDumps(
// Triggers a heap dump if the process uses more than 5% of the total memory. We could use any threshold or even
// provide a custom trigger function here instead.
5,
// Limit the frequency of heap dumps to a maximum of 3 events per day and at least 1 hour between each event.
Debouncer.PerDay(3, TimeSpan.FromHours(1)),
// Set the level for heap dump events to Info
SentryLevel.Info
);

// This is an example of intercepting events before they get sent to Sentry. Typically, you might use this to
// filter events that you didn't want to send but in this case we're using it to detect when a heap dump has
// been captured, so we know when to stop allocating memory in the heap dump demo.
options.SetBeforeSend((evt, hint) =>
{
if (hint.Attachments.Any(a => a.FileName.EndsWith("gcdump")))
{
cts.Cancel();
}
return evt; // If we returned null here, that would stop the event from being sent
});
});

// In Debug mode there will be a bit of stuff logged out during initialization... wait for that to play out
await Task.Delay(1000);

var memoryHog = new List<object>();
WriteLine();

WriteLine("Hogging memory...");

// Sentry checks memory usage every time a full garbage collection occurs. It might take a while to trigger this,
// although we've configured some ridiculously aggressive settings in the runtimeconfig.template.json file to make
// this happen more quickly, for the purposes of this demo... definitely don't do this in production!
while (cts.Token.IsCancellationRequested == false)
{
var array = new byte[2_000_000_000];
array.Initialize();
memoryHog.Add(array);
}

GC.KeepAlive(memoryHog);
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<PropertyGroup>
<!--
Note, these options do nothing if you are not authenticated.
See https://docs.sentry.io/platforms/dotnet/configuration/msbuild/#authentication
-->
<!--
<SentryUrl>...your Sentry URL if self-hosted, or omit this line if using sentry.io...</SentryUrl>
-->
<SentryOrg>sentry-sdks</SentryOrg>
<SentryProject>sentry-dotnet</SentryProject>

<!--
After the above properties are configured, you can use the following features.
Uploading symbols to Sentry will enable server-side symbolication (i.e. when the PDB is not present at runtime, or for AOT published programs).
Uploading sources to Sentry during the build will enable Source Context in the Sentry issue details page.
-->
<SentryUploadSymbols>true</SentryUploadSymbols>
<SentryUploadSources>true</SentryUploadSources>

<!--
You can automatically create releases via sentry-cli and control their creation via these properties
See https://docs.sentry.io/cli/releases/#creating-releases
-->
<SentryCreateRelease>true</SentryCreateRelease>

<!--
To associate commits with releases
See https://docs.sentry.io/cli/releases/#commit-integration
-->
<SentrySetCommits>true</SentrySetCommits>
<SentrySetCommitOptions>--local</SentrySetCommitOptions>

<!--
To associate commits with releases
See https://docs.sentry.io/cli/releases/#commit-integration
-->
<!-- <SentrySetCommits>true</SentrySetCommits>-->
<!-- <SentrySetCommitOptions>&#45;&#45;local</SentrySetCommitOptions>-->
</PropertyGroup>

<!-- In your own project, this would be a PackageReference to the latest version of Sentry. -->
<ItemGroup>
<ProjectReference Include="..\..\src\Sentry\Sentry.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"configProperties": {
"System.GC.ConserveMemory": 9,
"System.GC.HighMemoryPercent": 20
}
}
Loading

0 comments on commit 3fde00a

Please sign in to comment.