Skip to content

Commit

Permalink
Add MemoryInfo to sentry event (#1337)
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonCropp committed Dec 16, 2021
1 parent eb191c9 commit 12c46e1
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Fixes

- Add MemoryInfo to sentry event ([#1337](https://github.com/getsentry/sentry-dotnet/pull/1337))

## 3.12.2

### Fixes
Expand Down
38 changes: 38 additions & 0 deletions src/Sentry/Internal/MainSentryEventProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal class MainSentryEventProcessor : ISentryEventProcessor
{
internal const string CultureInfoKey = "Current Culture";
internal const string CurrentUiCultureKey = "Current UI Culture";
internal const string MemoryInfoKey = "Memory Info";

private readonly Enricher _enricher;

Expand Down Expand Up @@ -54,6 +55,7 @@ public SentryEvent Process(SentryEvent @event)
@event.Contexts[CurrentUiCultureKey] = currentUiCultureMap;
}

AddMemoryInfo(@event.Contexts);
if (@event.ServerName == null)
{
// Value set on the options take precedence over device name.
Expand Down Expand Up @@ -133,6 +135,41 @@ public SentryEvent Process(SentryEvent @event)
return @event;
}

private void AddMemoryInfo(Contexts contexts)
{
#if NETCOREAPP3_0_OR_GREATER
var memory = GC.GetGCMemoryInfo();
var allocatedBytes = GC.GetTotalAllocatedBytes();
#if NET5_0_OR_GREATER
contexts[MemoryInfoKey] = new MemoryInfo(
allocatedBytes,
memory.FragmentedBytes,
memory.HeapSizeBytes,
memory.HighMemoryLoadThresholdBytes,
memory.TotalAvailableMemoryBytes,
memory.MemoryLoadBytes,
memory.TotalCommittedBytes,
memory.PromotedBytes,
memory.PinnedObjectsCount,
memory.PauseTimePercentage,
memory.Index,
memory.Generation,
memory.FinalizationPendingCount,
memory.Compacted,
memory.Concurrent,
memory.PauseDurations.ToArray());
#else
contexts[MemoryInfoKey] = new MemoryInfo(
allocatedBytes,
memory.FragmentedBytes,
memory.HeapSizeBytes,
memory.HighMemoryLoadThresholdBytes,
memory.TotalAvailableMemoryBytes,
memory.MemoryLoadBytes);
#endif
#endif
}

private static IDictionary<string, string>? CultureInfoToDictionary(CultureInfo cultureInfo)
{
var dic = new Dictionary<string, string>();
Expand All @@ -153,4 +190,5 @@ public SentryEvent Process(SentryEvent @event)
return dic.Count > 0 ? dic : null;
}
}

}
116 changes: 116 additions & 0 deletions src/Sentry/Internal/MemoryInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#if NETCOREAPP3_0_OR_GREATER

using System;
using System.Text.Json;
using Sentry.Extensibility;

namespace Sentry
{
internal sealed class MemoryInfo : IJsonSerializable
{
public long AllocatedBytes { get; }
public long FragmentedBytes { get; }
public long HeapSizeBytes { get; }
public long HighMemoryLoadThresholdBytes { get; }
public long TotalAvailableMemoryBytes { get; }
public long MemoryLoadBytes { get; }

#if NET5_0_OR_GREATER
public long TotalCommittedBytes { get; }
public long PromotedBytes { get; }
public long PinnedObjectsCount { get; }
public double PauseTimePercentage { get; }
public TimeSpan[] PauseDurations { get; }
public long Index { get; }
public int Generation { get; }
public long FinalizationPendingCount { get; }
public bool Compacted { get; }
public bool Concurrent { get; }

public MemoryInfo(
long allocatedBytes,
long fragmentedBytes,
long heapSizeBytes,
long highMemoryLoadThresholdBytes,
long totalAvailableMemoryBytes,
long memoryLoadBytes,
long totalCommittedBytes,
long promotedBytes,
long pinnedObjectsCount,
double pauseTimePercentage,
long index,
int generation,
long finalizationPendingCount,
bool compacted,
bool concurrent,
TimeSpan[] pauseDurations)
{
AllocatedBytes = allocatedBytes;
FragmentedBytes = fragmentedBytes;
HeapSizeBytes = heapSizeBytes;
HighMemoryLoadThresholdBytes = highMemoryLoadThresholdBytes;
TotalAvailableMemoryBytes = totalAvailableMemoryBytes;
MemoryLoadBytes = memoryLoadBytes;
TotalCommittedBytes = totalCommittedBytes;
PromotedBytes = promotedBytes;
PinnedObjectsCount = pinnedObjectsCount;
PauseTimePercentage = pauseTimePercentage;
PauseDurations = pauseDurations;
Index = index;
Generation = generation;
FinalizationPendingCount = finalizationPendingCount;
Compacted = compacted;
Concurrent = concurrent;
}
#else
public MemoryInfo(
long allocatedBytes,
long fragmentedBytes,
long heapSizeBytes,
long highMemoryLoadThresholdBytes,
long totalAvailableMemoryBytes,
long memoryLoadBytes)
{
AllocatedBytes = allocatedBytes;
FragmentedBytes = fragmentedBytes;
HeapSizeBytes = heapSizeBytes;
HighMemoryLoadThresholdBytes = highMemoryLoadThresholdBytes;
TotalAvailableMemoryBytes = totalAvailableMemoryBytes;
MemoryLoadBytes = memoryLoadBytes;
}
#endif
public void WriteTo(Utf8JsonWriter writer, IDiagnosticLogger? logger)
{
writer.WriteStartObject();

writer.WriteNumber("allocatedBytes", AllocatedBytes);
writer.WriteNumber("fragmentedBytes", FragmentedBytes);
writer.WriteNumber("heapSizeBytes", HeapSizeBytes);
writer.WriteNumber("highMemoryLoadThresholdBytes", HighMemoryLoadThresholdBytes);
writer.WriteNumber("totalAvailableMemoryBytes", TotalAvailableMemoryBytes);
writer.WriteNumber("memoryLoadBytes", MemoryLoadBytes);

#if NET5_0_OR_GREATER
writer.WriteNumber("totalCommittedBytes", TotalCommittedBytes);
writer.WriteNumber("promotedBytes", PromotedBytes);
writer.WriteNumber("pinnedObjectsCount", PinnedObjectsCount);
writer.WriteNumber("pauseTimePercentage", PauseTimePercentage);
writer.WriteNumber("index", Index);
writer.WriteNumber("generation", Generation);
writer.WriteNumber("finalizationPendingCount", FinalizationPendingCount);
writer.WriteBoolean("compacted", Compacted);
writer.WriteBoolean("concurrent", Concurrent);
writer.WritePropertyName("pauseDurations");
writer.WriteStartArray();
foreach (var duration in PauseDurations)
{
writer.WriteNumberValue(duration.TotalMilliseconds);
}
writer.WriteEndArray();
#endif
writer.WriteEndObject();
}
}
}

#endif
26 changes: 26 additions & 0 deletions test/Sentry.Tests/Internals/MainSentryEventProcessorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,32 @@ public void Process_SendDefaultPiiTrueIdEnvironmentDefault_UserNameSet()
Assert.Equal(Environment.UserName, evt.User.Username);
}

#if NETCOREAPP3_1_OR_GREATER
[Fact]
public void EnsureMemoryInfoExists()
{
var evt = new SentryEvent();

_fixture.SentryOptions.SendDefaultPii = true;
var sut = _fixture.GetSut();

_ = sut.Process(evt);
var memory = (MemoryInfo)evt.Contexts[MainSentryEventProcessor.MemoryInfoKey];
Assert.NotEqual(0, memory.TotalAvailableMemoryBytes);
Assert.NotEqual(0, memory.FragmentedBytes);
Assert.NotEqual(0, memory.HeapSizeBytes);
Assert.NotEqual(0, memory.HighMemoryLoadThresholdBytes);
Assert.NotEqual(0, memory.TotalAvailableMemoryBytes);
Assert.NotEqual(0, memory.MemoryLoadBytes);
#if NET5_0_OR_GREATER
Assert.NotEqual(0, memory.TotalCommittedBytes);
Assert.NotEqual(0, memory.PromotedBytes);
Assert.NotEqual(0, memory.PauseTimePercentage);
Assert.NotEmpty(memory.PauseDurations);
#endif
}
#endif

[Fact]
public void Process_SendDefaultPiiTrueIdEnvironmentTrue_UserNameSet()
{
Expand Down
27 changes: 27 additions & 0 deletions test/Sentry.Tests/Internals/MemoryInfoTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#if NETCOREAPP3_1_OR_GREATER
using System.Text.Json;

public class MemoryInfoTests
{
[Fact]
public void WriteTo()
{
#if NET5_0_OR_GREATER
var info = new MemoryInfo(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, true, false, new[] { TimeSpan.FromSeconds(1) });
#else
var info = new MemoryInfo(1, 2, 3, 4, 5, 6);
#endif

var stream = new MemoryStream();
var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true });
info.WriteTo(writer, null);
writer.Flush();
var json = Encoding.UTF8.GetString(stream.ToArray());
Assert.NotNull(json);
Assert.NotEmpty(json);
//Validate json
var serializer = new Newtonsoft.Json.JsonSerializer();
serializer.Deserialize(new Newtonsoft.Json.JsonTextReader(new StringReader(json)));
}
}
#endif

0 comments on commit 12c46e1

Please sign in to comment.