From e8a6f873c7fdecacd75c3de633d5cda04f3816e8 Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Fri, 19 Sep 2025 17:56:16 +1200 Subject: [PATCH 1/8] Ensure template is not sent for Structured logs with no parameters Resolves #4480: - https://github.com/getsentry/sentry-dotnet/issues/4480 --- .../Internal/DefaultSentryStructuredLogger.cs | 4 ++- .../SentryStructuredLoggerTests.Format.cs | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Sentry/Internal/DefaultSentryStructuredLogger.cs b/src/Sentry/Internal/DefaultSentryStructuredLogger.cs index 42d61705f1..0dfe97b19e 100644 --- a/src/Sentry/Internal/DefaultSentryStructuredLogger.cs +++ b/src/Sentry/Internal/DefaultSentryStructuredLogger.cs @@ -53,7 +53,9 @@ private protected override void CaptureLog(SentryLogLevel level, string template SentryLog log = new(timestamp, traceHeader.TraceId, level, message) { - Template = template, + // the SDK MUST NOT attach a sentry.message.template attribute if there are no parameters + // https://develop.sentry.dev/sdk/telemetry/logs/#default-attributes + Template = parameters is { Length: > 0 } ? template : null, Parameters = @params, ParentSpanId = traceHeader.SpanId, }; diff --git a/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs b/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs index 87894fed75..2ed53208ed 100644 --- a/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs +++ b/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs @@ -26,6 +26,40 @@ public void Log_Enabled_CapturesEnvelope(SentryLogLevel level) _fixture.AssertEnvelopeWithoutAttributes(envelope, level); } + [Theory] + [InlineData(SentryLogLevel.Trace)] + [InlineData(SentryLogLevel.Debug)] + [InlineData(SentryLogLevel.Info)] + [InlineData(SentryLogLevel.Warning)] + [InlineData(SentryLogLevel.Error)] + [InlineData(SentryLogLevel.Fatal)] + public void Log_NoParameters_TemplateNotSet(SentryLogLevel level) + { + // Arrange + _fixture.Options.Experimental.EnableLogs = true; + var logger = _fixture.GetSut(); + + Envelope envelope = null!; + _fixture.Hub.CaptureEnvelope(Arg.Do(arg => envelope = arg)); + + // Act + logger.Log(level, "Template string without arguments"); + logger.Flush(); + + // Assert + _fixture.Hub.Received(1).CaptureEnvelope(Arg.Any()); + var envelopeItem = envelope.Items.Should().ContainSingle().Which; + var log = envelopeItem.Payload.Should().BeOfType().Which.Source.Should().BeOfType().Which; + log.Should().NotBeNull(); + var items = log.Items; + items.Length.Should().Be(1); + var item = items[0]; + + // If there are no sentry.message.parameter.X attributes included in the log, then + // the SDK MUST NOT attach a sentry.message.template attribute. + item.Template.Should().BeNull(); + } + [Theory] [InlineData(SentryLogLevel.Trace)] [InlineData(SentryLogLevel.Debug)] From 8c82c8e72d901660813530faf442f34d0a522c2b Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Fri, 19 Sep 2025 17:59:25 +1200 Subject: [PATCH 2/8] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a0e5c1bd3..57c989f407 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Fail when building Blazor WASM with Profiling. We don't support profiling in Blazor WebAssembly projects. ([#4512](https://github.com/getsentry/sentry-dotnet/pull/4512)) - Do not overwrite user IP if it is set manually in ASP.NET sdk ([#4513](https://github.com/getsentry/sentry-dotnet/pull/4513)) - Fix `SentryOptions.Native.SuppressSignalAborts` and `SuppressExcBadAccess` on iOS ([#4521](https://github.com/getsentry/sentry-dotnet/pull/4521)) +- Templates are no longer sent with Structured that have no parameters ([#4544](https://github.com/getsentry/sentry-dotnet/pull/4544)) ### Dependencies From 92fccb4295dededefb2fe86633d044189e97c8da Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Mon, 22 Sep 2025 10:36:19 +1200 Subject: [PATCH 3/8] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26ca23a15e..596ae6e594 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Templates are no longer sent with Structured that have no parameters ([#4544](https://github.com/getsentry/sentry-dotnet/pull/4544)) + ## 5.15.1 ### Fixes @@ -7,7 +13,6 @@ - Fail when building Blazor WASM with Profiling. We don't support profiling in Blazor WebAssembly projects. ([#4512](https://github.com/getsentry/sentry-dotnet/pull/4512)) - Do not overwrite user IP if it is set manually in ASP.NET sdk ([#4513](https://github.com/getsentry/sentry-dotnet/pull/4513)) - Fix `SentryOptions.Native.SuppressSignalAborts` and `SuppressExcBadAccess` on iOS ([#4521](https://github.com/getsentry/sentry-dotnet/pull/4521)) -- Templates are no longer sent with Structured that have no parameters ([#4544](https://github.com/getsentry/sentry-dotnet/pull/4544)) ### Dependencies From 9cf6abbbb9db7348eee71d859106f57721e83bd6 Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Thu, 25 Sep 2025 11:52:44 +1200 Subject: [PATCH 4/8] Moved logic to clear template to serialiser method --- .../Internal/DefaultSentryStructuredLogger.cs | 4 +-- src/Sentry/SentryLog.cs | 4 ++- test/Sentry.Tests/SentryLogTests.cs | 25 ++++++++++++++ .../SentryStructuredLoggerTests.Format.cs | 34 ------------------- 4 files changed, 29 insertions(+), 38 deletions(-) diff --git a/src/Sentry/Internal/DefaultSentryStructuredLogger.cs b/src/Sentry/Internal/DefaultSentryStructuredLogger.cs index 0dfe97b19e..42d61705f1 100644 --- a/src/Sentry/Internal/DefaultSentryStructuredLogger.cs +++ b/src/Sentry/Internal/DefaultSentryStructuredLogger.cs @@ -53,9 +53,7 @@ private protected override void CaptureLog(SentryLogLevel level, string template SentryLog log = new(timestamp, traceHeader.TraceId, level, message) { - // the SDK MUST NOT attach a sentry.message.template attribute if there are no parameters - // https://develop.sentry.dev/sdk/telemetry/logs/#default-attributes - Template = parameters is { Length: > 0 } ? template : null, + Template = template, Parameters = @params, ParentSpanId = traceHeader.SpanId, }; diff --git a/src/Sentry/SentryLog.cs b/src/Sentry/SentryLog.cs index b506b9da6c..0ffb6c35c4 100644 --- a/src/Sentry/SentryLog.cs +++ b/src/Sentry/SentryLog.cs @@ -224,7 +224,9 @@ internal void WriteTo(Utf8JsonWriter writer, IDiagnosticLogger? logger) writer.WritePropertyName("attributes"); writer.WriteStartObject(); - if (Template is not null) + // the SDK MUST NOT attach a sentry.message.template attribute if there are no parameters + // https://develop.sentry.dev/sdk/telemetry/logs/#default-attributes + if (Template is not null && Parameters is { Length: > 0 }) { SentryAttributeSerializer.WriteStringAttribute(writer, "sentry.message.template", Template); } diff --git a/test/Sentry.Tests/SentryLogTests.cs b/test/Sentry.Tests/SentryLogTests.cs index 3393137b85..f84a62420c 100644 --- a/test/Sentry.Tests/SentryLogTests.cs +++ b/test/Sentry.Tests/SentryLogTests.cs @@ -67,6 +67,31 @@ public void Protocol_Default_VerifyAttributes() notFound.Should().BeNull(); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void WriteTo_NoParameters_NoTemplate(bool hasParameters) + { + // Arrange + ImmutableArray> parameters = hasParameters + ? [new KeyValuePair("param", "params")] + : []; + var log = new SentryLog(Timestamp, TraceId, SentryLogLevel.Debug, "message") + { + Template = "template", + Parameters = parameters, + ParentSpanId = ParentSpanId, + }; + + // Act + // var document = log.ToJsonString(); + var document = log.ToJsonDocument(static (obj, writer, logger) => obj.WriteTo(writer, logger), _output); + var attributes = document.RootElement.GetProperty("attributes"); + + // Assert + attributes.TryGetProperty("sentry.message.template", out _).Should().Be(hasParameters); + } + [Fact] public void WriteTo_Envelope_MinimalSerializedSentryLog() { diff --git a/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs b/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs index 2ed53208ed..87894fed75 100644 --- a/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs +++ b/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs @@ -26,40 +26,6 @@ public void Log_Enabled_CapturesEnvelope(SentryLogLevel level) _fixture.AssertEnvelopeWithoutAttributes(envelope, level); } - [Theory] - [InlineData(SentryLogLevel.Trace)] - [InlineData(SentryLogLevel.Debug)] - [InlineData(SentryLogLevel.Info)] - [InlineData(SentryLogLevel.Warning)] - [InlineData(SentryLogLevel.Error)] - [InlineData(SentryLogLevel.Fatal)] - public void Log_NoParameters_TemplateNotSet(SentryLogLevel level) - { - // Arrange - _fixture.Options.Experimental.EnableLogs = true; - var logger = _fixture.GetSut(); - - Envelope envelope = null!; - _fixture.Hub.CaptureEnvelope(Arg.Do(arg => envelope = arg)); - - // Act - logger.Log(level, "Template string without arguments"); - logger.Flush(); - - // Assert - _fixture.Hub.Received(1).CaptureEnvelope(Arg.Any()); - var envelopeItem = envelope.Items.Should().ContainSingle().Which; - var log = envelopeItem.Payload.Should().BeOfType().Which.Source.Should().BeOfType().Which; - log.Should().NotBeNull(); - var items = log.Items; - items.Length.Should().Be(1); - var item = items[0]; - - // If there are no sentry.message.parameter.X attributes included in the log, then - // the SDK MUST NOT attach a sentry.message.template attribute. - item.Template.Should().BeNull(); - } - [Theory] [InlineData(SentryLogLevel.Trace)] [InlineData(SentryLogLevel.Debug)] From eb5c58f20bdf186f3da5d5f454eaf16dd10eb6ce Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Thu, 25 Sep 2025 00:07:34 +0000 Subject: [PATCH 5/8] Format code --- test/Sentry.Tests/SentryLogTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Sentry.Tests/SentryLogTests.cs b/test/Sentry.Tests/SentryLogTests.cs index f84a62420c..a79ce19486 100644 --- a/test/Sentry.Tests/SentryLogTests.cs +++ b/test/Sentry.Tests/SentryLogTests.cs @@ -73,7 +73,7 @@ public void Protocol_Default_VerifyAttributes() public void WriteTo_NoParameters_NoTemplate(bool hasParameters) { // Arrange - ImmutableArray> parameters = hasParameters + ImmutableArray> parameters = hasParameters ? [new KeyValuePair("param", "params")] : []; var log = new SentryLog(Timestamp, TraceId, SentryLogLevel.Debug, "message") From 0625308c2f29262772fcb0585e59873c04a43c53 Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Sun, 28 Sep 2025 16:35:34 +1300 Subject: [PATCH 6/8] Update test/Sentry.Tests/SentryLogTests.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stefan Pölz <38893694+Flash0ver@users.noreply.github.com> --- test/Sentry.Tests/SentryLogTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Sentry.Tests/SentryLogTests.cs b/test/Sentry.Tests/SentryLogTests.cs index a79ce19486..105e196d56 100644 --- a/test/Sentry.Tests/SentryLogTests.cs +++ b/test/Sentry.Tests/SentryLogTests.cs @@ -84,7 +84,6 @@ public void WriteTo_NoParameters_NoTemplate(bool hasParameters) }; // Act - // var document = log.ToJsonString(); var document = log.ToJsonDocument(static (obj, writer, logger) => obj.WriteTo(writer, logger), _output); var attributes = document.RootElement.GetProperty("attributes"); From faad68af1a8cf9d27b305be334b43e7237a29667 Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Sun, 28 Sep 2025 16:35:54 +1300 Subject: [PATCH 7/8] Update CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stefan Pölz <38893694+Flash0ver@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e416924c3d..0c54cbcc8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Fixes -- Templates are no longer sent with Structured that have no parameters ([#4544](https://github.com/getsentry/sentry-dotnet/pull/4544)) +- Templates are no longer sent with Structured Logs that have no parameters ([#4544](https://github.com/getsentry/sentry-dotnet/pull/4544)) - Upload linked PDBs to fix non-IL-stripped symbolication for iOS ([#4527](https://github.com/getsentry/sentry-dotnet/pull/4527)) - In MAUI Android apps, generate and inject UUID to APK and upload ProGuard mapping to Sentry with the UUID ([#4532](https://github.com/getsentry/sentry-dotnet/pull/4532)) - Fixed WASM0001 warning when building Blazor WebAssembly projects ([#4519](https://github.com/getsentry/sentry-dotnet/pull/4519)) From 320d6d8825690237bed6c4f06272caef8729905d Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Wed, 1 Oct 2025 11:41:49 +1300 Subject: [PATCH 8/8] . --- src/Sentry/SentryLog.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sentry/SentryLog.cs b/src/Sentry/SentryLog.cs index 0ffb6c35c4..7aef142d36 100644 --- a/src/Sentry/SentryLog.cs +++ b/src/Sentry/SentryLog.cs @@ -226,7 +226,7 @@ internal void WriteTo(Utf8JsonWriter writer, IDiagnosticLogger? logger) // the SDK MUST NOT attach a sentry.message.template attribute if there are no parameters // https://develop.sentry.dev/sdk/telemetry/logs/#default-attributes - if (Template is not null && Parameters is { Length: > 0 }) + if (Template is not null && !Parameters.IsDefaultOrEmpty) { SentryAttributeSerializer.WriteStringAttribute(writer, "sentry.message.template", Template); }