diff --git a/CHANGELOG.md b/CHANGELOG.md index b03716d4ff..c1479920cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Implement pause & resume session ([#1069](https://github.com/getsentry/sentry-dotnet/pull/1069)) - Add auto session tracking ([#1068](https://github.com/getsentry/sentry-dotnet/pull/1068)) +- Add SDK information to envelope ([#1084](https://github.com/getsentry/sentry-dotnet/pull/1084)) - Add ReportAssembliesMode in favor of ReportAssemblies ([#1079](https://github.com/getsentry/sentry-dotnet/pull/1079)) ### Fixes diff --git a/src/Sentry/Envelopes/Envelope.cs b/src/Sentry/Envelopes/Envelope.cs index 5fd3bb55a0..f8eca6c7a7 100644 --- a/src/Sentry/Envelopes/Envelope.cs +++ b/src/Sentry/Envelopes/Envelope.cs @@ -36,11 +36,6 @@ public Envelope(IReadOnlyDictionary header, IReadOnlyList items) - : this(Empty.Dictionary(), items) - { - } - /// /// Attempts to extract the value of "sentry_id" header if it's present. /// @@ -76,6 +71,26 @@ public async Task SerializeAsync(Stream stream, CancellationToken cancellationTo /// public void Dispose() => Items.DisposeAll(); + private static Dictionary CreateHeader(SentryId? eventId = null) + { + var header = new Dictionary(2, StringComparer.Ordinal) + { + // Include limited SDK information (no packages) + ["sdk"] = new Dictionary(2, StringComparer.Ordinal) + { + ["name"] = SdkVersion.Instance.Name, + ["version"] = SdkVersion.Instance.Version + } + }; + + if (eventId is not null) + { + header[EventIdKey] = eventId.Value.ToString(); + } + + return header; + } + /// /// Creates an envelope that contains a single event. /// @@ -84,10 +99,7 @@ public async Task SerializeAsync(Stream stream, CancellationToken cancellationTo IReadOnlyCollection? attachments = null, SessionUpdate? sessionUpdate = null) { - var header = new Dictionary(1, StringComparer.Ordinal) - { - [EventIdKey] = @event.EventId.ToString() - }; + var header = CreateHeader(@event.EventId); var items = new List { @@ -112,10 +124,7 @@ public async Task SerializeAsync(Stream stream, CancellationToken cancellationTo /// public static Envelope FromUserFeedback(UserFeedback sentryUserFeedback) { - var header = new Dictionary(1, StringComparer.Ordinal) - { - [EventIdKey] = sentryUserFeedback.EventId.ToString() - }; + var header = CreateHeader(sentryUserFeedback.EventId); var items = new[] { @@ -130,10 +139,7 @@ public static Envelope FromUserFeedback(UserFeedback sentryUserFeedback) /// public static Envelope FromTransaction(Transaction transaction) { - var header = new Dictionary(1, StringComparer.Ordinal) - { - [EventIdKey] = transaction.EventId.ToString() - }; + var header = CreateHeader(transaction.EventId); var items = new[] { @@ -148,12 +154,14 @@ public static Envelope FromTransaction(Transaction transaction) /// public static Envelope FromSession(SessionUpdate sessionUpdate) { + var header = CreateHeader(); + var items = new[] { EnvelopeItem.FromSession(sessionUpdate) }; - return new Envelope(items); + return new Envelope(header, items); } private static async Task> DeserializeHeaderAsync( diff --git a/src/Sentry/Internal/Empty.cs b/src/Sentry/Internal/Empty.cs deleted file mode 100644 index e50b85dabc..0000000000 --- a/src/Sentry/Internal/Empty.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; - -namespace Sentry.Internal -{ - internal static class Empty - { - private static class DictionaryContainer where TKey : notnull - { - public static IReadOnlyDictionary Instance { get; } = - new ReadOnlyDictionary(new Dictionary()); - } - - public static IReadOnlyDictionary Dictionary() where TKey : notnull => - DictionaryContainer.Instance; - } -} diff --git a/src/Sentry/Internal/Enricher.cs b/src/Sentry/Internal/Enricher.cs index 01b333fa50..1e5c58cda5 100644 --- a/src/Sentry/Internal/Enricher.cs +++ b/src/Sentry/Internal/Enricher.cs @@ -1,7 +1,6 @@ using System; using System.Runtime.InteropServices; using Sentry.PlatformAbstractions; -using Sentry.Reflection; using OperatingSystem = Sentry.Protocol.OperatingSystem; using Runtime = Sentry.Protocol.Runtime; @@ -22,9 +21,6 @@ internal class Enricher }; }); - private readonly Lazy _sdkVersionLazy = - new(() => typeof(ISentryClient).Assembly.GetNameAndVersion()); - public Enricher(SentryOptions options) { _options = options; @@ -54,12 +50,12 @@ public void Apply(IEventLike eventLike) if (eventLike.Sdk.Version is null && eventLike.Sdk.Name is null) { eventLike.Sdk.Name = Constants.SdkName; - eventLike.Sdk.Version = _sdkVersionLazy.Value.Version; + eventLike.Sdk.Version = SdkVersion.Instance.Version; } - if (_sdkVersionLazy.Value.Version is not null) + if (SdkVersion.Instance.Version is not null) { - eventLike.Sdk.AddPackage("nuget:" + _sdkVersionLazy.Value.Name, _sdkVersionLazy.Value.Version); + eventLike.Sdk.AddPackage("nuget:" + SdkVersion.Instance.Name, SdkVersion.Instance.Version); } // Platform diff --git a/src/Sentry/SdkVersion.cs b/src/Sentry/SdkVersion.cs index 07d3af3e44..563bf569bd 100644 --- a/src/Sentry/SdkVersion.cs +++ b/src/Sentry/SdkVersion.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text.Json; using Sentry.Internal.Extensions; +using Sentry.Reflection; namespace Sentry { @@ -14,6 +15,12 @@ namespace Sentry /// Requires Sentry version 8.4 or higher. public sealed class SdkVersion : IJsonSerializable { + private static readonly Lazy InstanceLazy = new( + () => typeof(ISentryClient).Assembly.GetNameAndVersion() + ); + + internal static SdkVersion Instance => InstanceLazy.Value; + internal ConcurrentBag InternalPackages { get; set; } = new(); /// diff --git a/test/Sentry.Tests/PlatformAbstractions/RuntimeInfoTests.cs b/test/Sentry.Tests/PlatformAbstractions/RuntimeInfoTests.cs index 6274e2430e..819aae70a1 100644 --- a/test/Sentry.Tests/PlatformAbstractions/RuntimeInfoTests.cs +++ b/test/Sentry.Tests/PlatformAbstractions/RuntimeInfoTests.cs @@ -69,8 +69,7 @@ public void SetNetCoreVersion_NetCoreAsName() } #endif - // TODO: Should be NET5_0_OR_GREATER which isn't available (to be added when NET6 lands) -#if NET5_0 +#if NET5_0_OR_GREATER [Fact] public void SetNetCoreVersion_Net5Runtime_NullNetCoreVersion() { diff --git a/test/Sentry.Tests/Protocol/Envelopes/EnvelopeTests.cs b/test/Sentry.Tests/Protocol/Envelopes/EnvelopeTests.cs index 41d1f8b659..55cf9fe2c5 100644 --- a/test/Sentry.Tests/Protocol/Envelopes/EnvelopeTests.cs +++ b/test/Sentry.Tests/Protocol/Envelopes/EnvelopeTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; using FluentAssertions; using Sentry.Protocol; @@ -608,5 +609,24 @@ public async Task Deserialization_MalformedData_Throws() async () => await Envelope.DeserializeAsync(input) ); } + + [Fact] + public void FromEvent_Header_IncludesSdkInformation() + { + // Act + var envelope = Envelope.FromEvent(new SentryEvent()); + + // Assert + envelope.Header.Any(kvp => + { + var (key, value) = kvp; + + return + key == "sdk" && + value is IReadOnlyDictionary nested && + nested["name"] == SdkVersion.Instance.Name && + nested["version"] == SdkVersion.Instance.Version; + }).Should().BeTrue(); + } } }