From 2fb7d376ce18629cb00d88fcd6d4766d1af044df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:56:31 +0100 Subject: [PATCH 01/18] ref(logs): make API stable (remove Experimental from Options) --- .../SentryStructuredLoggerBenchmarks.cs | 7 +- .../StructuredLogBatchProcessorBenchmarks.cs | 5 +- .../Program.cs | 2 +- .../Sentry.Samples.Console.Basic/Program.cs | 4 +- samples/Sentry.Samples.ME.Logging/Program.cs | 4 +- samples/Sentry.Samples.Serilog/Program.cs | 2 +- .../SentryStructuredLogger.cs | 2 +- src/Sentry.Serilog/SentrySink.cs | 4 +- src/Sentry.Serilog/SentrySinkExtensions.cs | 14 ++-- src/Sentry/BindableSentryOptions.cs | 11 +-- src/Sentry/IHub.cs | 4 +- .../Internal/DefaultSentryStructuredLogger.cs | 4 +- src/Sentry/SentryOptions.cs | 71 +++++++------------ src/Sentry/SentryStructuredLogger.cs | 2 +- ...AspNetCoreStructuredLoggerProviderTests.cs | 2 +- .../SentryLoggingOptionsSetupTests.cs | 6 +- .../SentryStructuredLoggerProviderTests.cs | 2 +- .../SentryStructuredLoggerTests.cs | 2 +- ...iApprovalTests.Run.DotNet10_0.verified.txt | 2 +- ...piApprovalTests.Run.DotNet8_0.verified.txt | 2 +- ...piApprovalTests.Run.DotNet9_0.verified.txt | 2 +- .../ApiApprovalTests.Run.Net4_8.verified.txt | 2 +- .../AspNetCoreIntegrationTests.cs | 4 +- .../IntegrationTests.verify.cs | 2 +- .../SentrySerilogSinkExtensionsTests.cs | 6 +- .../SentrySinkTests.Structured.cs | 12 ++-- .../SerilogAspNetSentrySdkTestFixture.cs | 8 +-- test/Sentry.Testing/BindableTests.cs | 13 ---- ...iApprovalTests.Run.DotNet10_0.verified.txt | 8 +-- ...piApprovalTests.Run.DotNet8_0.verified.txt | 8 +-- ...piApprovalTests.Run.DotNet9_0.verified.txt | 8 +-- .../ApiApprovalTests.Run.Net4_8.verified.txt | 8 +-- test/Sentry.Tests/HubTests.cs | 16 ++--- .../SentryStructuredLoggerTests.Format.cs | 8 +-- .../SentryStructuredLoggerTests.cs | 26 +++---- 35 files changed, 110 insertions(+), 173 deletions(-) diff --git a/benchmarks/Sentry.Benchmarks/Extensions.Logging/SentryStructuredLoggerBenchmarks.cs b/benchmarks/Sentry.Benchmarks/Extensions.Logging/SentryStructuredLoggerBenchmarks.cs index 3e18747a65..08beda17f3 100644 --- a/benchmarks/Sentry.Benchmarks/Extensions.Logging/SentryStructuredLoggerBenchmarks.cs +++ b/benchmarks/Sentry.Benchmarks/Extensions.Logging/SentryStructuredLoggerBenchmarks.cs @@ -22,16 +22,13 @@ public void Setup() SentryLoggingOptions options = new() { Dsn = DsnSamples.ValidDsn, - Experimental = - { - EnableLogs = true, - }, + EnableLogs = true, ExperimentalLogging = { MinimumLogLevel = LogLevel.Information, } }; - options.Experimental.SetBeforeSendLog((SentryLog log) => + options.SetBeforeSendLog((SentryLog log) => { _lastLog = log; return null; diff --git a/benchmarks/Sentry.Benchmarks/StructuredLogBatchProcessorBenchmarks.cs b/benchmarks/Sentry.Benchmarks/StructuredLogBatchProcessorBenchmarks.cs index 9085068cce..4a2d1fc981 100644 --- a/benchmarks/Sentry.Benchmarks/StructuredLogBatchProcessorBenchmarks.cs +++ b/benchmarks/Sentry.Benchmarks/StructuredLogBatchProcessorBenchmarks.cs @@ -22,10 +22,7 @@ public void Setup() SentryOptions options = new() { Dsn = DsnSamples.ValidDsn, - Experimental = - { - EnableLogs = true, - }, + EnableLogs = true, }; var batchInterval = Timeout.InfiniteTimeSpan; diff --git a/samples/Sentry.Samples.AspNetCore.Basic/Program.cs b/samples/Sentry.Samples.AspNetCore.Basic/Program.cs index 221a10293b..18cee62d80 100644 --- a/samples/Sentry.Samples.AspNetCore.Basic/Program.cs +++ b/samples/Sentry.Samples.AspNetCore.Basic/Program.cs @@ -17,7 +17,7 @@ #endif // This option enables Logs sent to Sentry. - options.Experimental.EnableLogs = true; + options.EnableLogs = true; }); var app = builder.Build(); diff --git a/samples/Sentry.Samples.Console.Basic/Program.cs b/samples/Sentry.Samples.Console.Basic/Program.cs index 1a2605c0ee..a75b3d379e 100644 --- a/samples/Sentry.Samples.Console.Basic/Program.cs +++ b/samples/Sentry.Samples.Console.Basic/Program.cs @@ -38,8 +38,8 @@ options.TracesSampleRate = 1.0; // This option enables Sentry Logs created via SentrySdk.Logger. - options.Experimental.EnableLogs = true; - options.Experimental.SetBeforeSendLog(static log => + options.EnableLogs = true; + options.SetBeforeSendLog(static log => { // A demonstration of how you can drop logs based on some attribute they have if (log.TryGetAttribute("suppress", out var attribute) && attribute is true) diff --git a/samples/Sentry.Samples.ME.Logging/Program.cs b/samples/Sentry.Samples.ME.Logging/Program.cs index 0178235c03..996a2aa59f 100644 --- a/samples/Sentry.Samples.ME.Logging/Program.cs +++ b/samples/Sentry.Samples.ME.Logging/Program.cs @@ -26,8 +26,8 @@ options.ExperimentalLogging.MinimumLogLevel = LogLevel.Trace; // This level or above will result in log sent to Sentry // This option enables Logs sent to Sentry. - options.Experimental.EnableLogs = true; - options.Experimental.SetBeforeSendLog(static log => + options.EnableLogs = true; + options.SetBeforeSendLog(static log => { log.SetAttribute("attribute-key", "attribute-value"); return log; diff --git a/samples/Sentry.Samples.Serilog/Program.cs b/samples/Sentry.Samples.Serilog/Program.cs index c1822a3714..127a47ccdb 100644 --- a/samples/Sentry.Samples.Serilog/Program.cs +++ b/samples/Sentry.Samples.Serilog/Program.cs @@ -26,7 +26,7 @@ private static void Main() options.MinimumEventLevel = LogEventLevel.Error; options.AttachStacktrace = true; // send structured logs to Sentry - options.Experimental.EnableLogs = true; + options.EnableLogs = true; // send PII like the username of the user logged in to the device options.SendDefaultPii = true; // Optional Serilog text formatter used to format LogEvent to string. If TextFormatter is set, FormatProvider is ignored. diff --git a/src/Sentry.Extensions.Logging/SentryStructuredLogger.cs b/src/Sentry.Extensions.Logging/SentryStructuredLogger.cs index 43cb0f17a7..d38fcf6f70 100644 --- a/src/Sentry.Extensions.Logging/SentryStructuredLogger.cs +++ b/src/Sentry.Extensions.Logging/SentryStructuredLogger.cs @@ -29,7 +29,7 @@ internal SentryStructuredLogger(string categoryName, SentryLoggingOptions option public bool IsEnabled(LogLevel logLevel) { return _hub.IsEnabled - && _options.Experimental.EnableLogs + && _options.EnableLogs && logLevel != LogLevel.None && logLevel >= _options.ExperimentalLogging.MinimumLogLevel; } diff --git a/src/Sentry.Serilog/SentrySink.cs b/src/Sentry.Serilog/SentrySink.cs index 4a4ad3e7f7..f00556794b 100644 --- a/src/Sentry.Serilog/SentrySink.cs +++ b/src/Sentry.Serilog/SentrySink.cs @@ -84,7 +84,7 @@ private bool IsEnabled(LogEvent logEvent) return logEvent.Level >= _options.MinimumEventLevel || logEvent.Level >= _options.MinimumBreadcrumbLevel - || options?.Experimental.EnableLogs is true; + || options?.EnableLogs is true; } private void InnerEmit(LogEvent logEvent) @@ -169,7 +169,7 @@ private void InnerEmit(LogEvent logEvent) // In cases where Sentry's Serilog-Sink is added without a DSN (i.e., without initializing the SDK) and the SDK is initialized differently (e.g., through ASP.NET Core), // then the 'EnableLogs' option of this Sink's Serilog-Options is default, but the Hub's Sentry-Options have the actual user-defined value configured. var options = hub.GetSentryOptions(); - if (options?.Experimental.EnableLogs is true) + if (options?.EnableLogs is true) { CaptureStructuredLog(hub, options, logEvent, formatted, template); } diff --git a/src/Sentry.Serilog/SentrySinkExtensions.cs b/src/Sentry.Serilog/SentrySinkExtensions.cs index e300ae1697..7a823c3d89 100644 --- a/src/Sentry.Serilog/SentrySinkExtensions.cs +++ b/src/Sentry.Serilog/SentrySinkExtensions.cs @@ -35,7 +35,7 @@ public static class SentrySinkExtensions /// What mode to use for reporting referenced assemblies in each event sent to sentry. Defaults to /// What modes to use for event automatic de-duplication. /// Default tags to add to all events. - /// Whether to send structured logs. + /// Whether to send structured logs. /// /// This sample shows how each item may be set from within a configuration file: /// @@ -73,7 +73,7 @@ public static class SentrySinkExtensions /// "key-1", "value-1", /// "key-2", "value-2" /// }, - /// "experimentalEnableLogs": true + /// "enableLogs": true /// } /// } /// ] @@ -106,7 +106,7 @@ public static LoggerConfiguration Sentry( ReportAssembliesMode? reportAssembliesMode = null, DeduplicateMode? deduplicateMode = null, Dictionary? defaultTags = null, - bool? experimentalEnableLogs = null) + bool? enableLogs = null) { return loggerConfiguration.Sentry(o => ConfigureSentrySerilogOptions(o, dsn, @@ -132,7 +132,7 @@ public static LoggerConfiguration Sentry( reportAssembliesMode, deduplicateMode, defaultTags, - experimentalEnableLogs)); + enableLogs)); } /// @@ -210,7 +210,7 @@ internal static void ConfigureSentrySerilogOptions( ReportAssembliesMode? reportAssembliesMode = null, DeduplicateMode? deduplicateMode = null, Dictionary? defaultTags = null, - bool? experimentalEnableLogs = null) + bool? enableLogs = null) { if (dsn is not null) { @@ -322,9 +322,9 @@ internal static void ConfigureSentrySerilogOptions( sentrySerilogOptions.DeduplicateMode = deduplicateMode.Value; } - if (experimentalEnableLogs.HasValue) + if (enableLogs.HasValue) { - sentrySerilogOptions.Experimental.EnableLogs = experimentalEnableLogs.Value; + sentrySerilogOptions.EnableLogs = enableLogs.Value; } // Serilog-specific items diff --git a/src/Sentry/BindableSentryOptions.cs b/src/Sentry/BindableSentryOptions.cs index c3314257f8..bbadddaf33 100644 --- a/src/Sentry/BindableSentryOptions.cs +++ b/src/Sentry/BindableSentryOptions.cs @@ -21,6 +21,7 @@ internal partial class BindableSentryOptions public string? Distribution { get; set; } public string? Environment { get; set; } public string? Dsn { get; set; } + public bool? EnableLogs { get; set; } public int? MaxQueueItems { get; set; } public int? MaxCacheItems { get; set; } public TimeSpan? ShutdownTimeout { get; set; } @@ -55,13 +56,6 @@ internal partial class BindableSentryOptions public bool? EnableSpotlight { get; set; } public string? SpotlightUrl { get; set; } - public BindableSentryExperimentalOptions Experimental { get; set; } = new(); - - internal sealed class BindableSentryExperimentalOptions - { - public bool? EnableLogs { get; set; } - } - public void ApplyTo(SentryOptions options) { options.IsGlobalModeEnabled = IsGlobalModeEnabled ?? options.IsGlobalModeEnabled; @@ -78,6 +72,7 @@ public void ApplyTo(SentryOptions options) options.Distribution = Distribution ?? options.Distribution; options.Environment = Environment ?? options.Environment; options.Dsn = Dsn ?? options.Dsn; + options.EnableLogs = EnableLogs ?? options.EnableLogs; options.MaxQueueItems = MaxQueueItems ?? options.MaxQueueItems; options.MaxCacheItems = MaxCacheItems ?? options.MaxCacheItems; options.ShutdownTimeout = ShutdownTimeout ?? options.ShutdownTimeout; @@ -111,8 +106,6 @@ public void ApplyTo(SentryOptions options) options.EnableSpotlight = EnableSpotlight ?? options.EnableSpotlight; options.SpotlightUrl = SpotlightUrl ?? options.SpotlightUrl; - options.Experimental.EnableLogs = Experimental.EnableLogs ?? options.Experimental.EnableLogs; - #if ANDROID Android.ApplyTo(options.Android); Native.ApplyTo(options.Native); diff --git a/src/Sentry/IHub.cs b/src/Sentry/IHub.cs index b4d62138bf..076f454f3f 100644 --- a/src/Sentry/IHub.cs +++ b/src/Sentry/IHub.cs @@ -23,8 +23,8 @@ public interface IHub : ISentryClient, ISentryScopeManager /// /// Available options: /// - /// - /// + /// + /// /// /// public SentryStructuredLogger Logger { get; } diff --git a/src/Sentry/Internal/DefaultSentryStructuredLogger.cs b/src/Sentry/Internal/DefaultSentryStructuredLogger.cs index 1f13191ed2..90f6df853a 100644 --- a/src/Sentry/Internal/DefaultSentryStructuredLogger.cs +++ b/src/Sentry/Internal/DefaultSentryStructuredLogger.cs @@ -14,7 +14,7 @@ internal sealed class DefaultSentryStructuredLogger : SentryStructuredLogger, ID internal DefaultSentryStructuredLogger(IHub hub, SentryOptions options, ISystemClock clock, int batchCount, TimeSpan batchInterval) { Debug.Assert(hub.IsEnabled); - Debug.Assert(options is { Experimental.EnableLogs: true }); + Debug.Assert(options is { EnableLogs: true }); _hub = hub; _options = options; @@ -79,7 +79,7 @@ protected internal override void CaptureLog(SentryLog log) { var configuredLog = log; - if (_options.Experimental.BeforeSendLogInternal is { } beforeSendLog) + if (_options.BeforeSendLogInternal is { } beforeSendLog) { try { diff --git a/src/Sentry/SentryOptions.cs b/src/Sentry/SentryOptions.cs index 67e7248f11..f3ad6710a1 100644 --- a/src/Sentry/SentryOptions.cs +++ b/src/Sentry/SentryOptions.cs @@ -544,6 +544,31 @@ public void SetBeforeBreadcrumb(Func beforeBreadcrumb) _beforeBreadcrumb = (breadcrumb, _) => beforeBreadcrumb(breadcrumb); } + /// + /// When set to , logs are sent to Sentry. + /// Defaults to . + /// + /// + public bool EnableLogs { get; set; } = false; + + private Func? _beforeSendLog; + + internal Func? BeforeSendLogInternal => _beforeSendLog; + + /// + /// Sets a callback function to be invoked before sending the log to Sentry. + /// When the delegate throws an during invocation, the log will not be captured. + /// + /// + /// It can be used to modify the log object before being sent to Sentry. + /// To prevent the log from being sent to Sentry, return . + /// + /// + public void SetBeforeSendLog(Func beforeSendLog) + { + _beforeSendLog = beforeSendLog; + } + private int _maxQueueItems = 30; /// @@ -1878,50 +1903,4 @@ internal static List GetDefaultInAppExclude() => "ServiceStack", "Java.Interop", ]; - - /// - /// Experimental Sentry features. - /// - /// - /// This and related experimental APIs may change in the future. - /// - public SentryExperimentalOptions Experimental { get; set; } = new(); - - /// - /// Experimental Sentry SDK options. - /// - /// - /// This and related experimental APIs may change in the future. - /// - public class SentryExperimentalOptions - { - internal SentryExperimentalOptions() - { - } - - /// - /// When set to , logs are sent to Sentry. - /// Defaults to . - /// - /// - public bool EnableLogs { get; set; } = false; - - private Func? _beforeSendLog; - - internal Func? BeforeSendLogInternal => _beforeSendLog; - - /// - /// Sets a callback function to be invoked before sending the log to Sentry. - /// When the delegate throws an during invocation, the log will not be captured. - /// - /// - /// It can be used to modify the log object before being sent to Sentry. - /// To prevent the log from being sent to Sentry, return . - /// - /// - public void SetBeforeSendLog(Func beforeSendLog) - { - _beforeSendLog = beforeSendLog; - } - } } diff --git a/src/Sentry/SentryStructuredLogger.cs b/src/Sentry/SentryStructuredLogger.cs index 9d81bd2820..f7da834ade 100644 --- a/src/Sentry/SentryStructuredLogger.cs +++ b/src/Sentry/SentryStructuredLogger.cs @@ -13,7 +13,7 @@ internal static SentryStructuredLogger Create(IHub hub, SentryOptions options, I internal static SentryStructuredLogger Create(IHub hub, SentryOptions options, ISystemClock clock, int batchCount, TimeSpan batchInterval) { - return options.Experimental.EnableLogs + return options.EnableLogs ? new DefaultSentryStructuredLogger(hub, options, clock, batchCount, batchInterval) : DisabledSentryStructuredLogger.Instance; } diff --git a/test/Sentry.AspNetCore.Tests/SentryAspNetCoreStructuredLoggerProviderTests.cs b/test/Sentry.AspNetCore.Tests/SentryAspNetCoreStructuredLoggerProviderTests.cs index d19cdf5cc4..def969676a 100644 --- a/test/Sentry.AspNetCore.Tests/SentryAspNetCoreStructuredLoggerProviderTests.cs +++ b/test/Sentry.AspNetCore.Tests/SentryAspNetCoreStructuredLoggerProviderTests.cs @@ -18,7 +18,7 @@ private class Fixture public Fixture() { var loggingOptions = new SentryAspNetCoreOptions(); - loggingOptions.Experimental.EnableLogs = true; + loggingOptions.EnableLogs = true; Options = Microsoft.Extensions.Options.Options.Create(loggingOptions); Hub = Substitute.For(); diff --git a/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs index 9321b3aa64..798dad7bf2 100644 --- a/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs @@ -25,6 +25,7 @@ public void Configure_BindsConfigurationToOptions() Distribution = "FakeDistribution", Environment = "Test", Dsn = "https://d4d82fc1c2c4032a83f3a29aa3a3aff@fake-sentry.io:65535/2147483647", + EnableLogs = true, MaxQueueItems = 8, MaxCacheItems = 9, ShutdownTimeout = TimeSpan.FromSeconds(13), @@ -57,7 +58,6 @@ public void Configure_BindsConfigurationToOptions() MinimumEventLevel = LogLevel.Error, InitializeSdk = true }; - expected.Experimental.EnableLogs = true; expected.ExperimentalLogging.MinimumLogLevel = LogLevel.None; var config = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary @@ -76,6 +76,7 @@ public void Configure_BindsConfigurationToOptions() ["Distribution"] = expected.Distribution, ["Environment"] = expected.Environment, ["Dsn"] = expected.Dsn, + ["EnableLogs"] = expected.EnableLogs.ToString(), ["MaxQueueItems"] = expected.MaxQueueItems.ToString(), ["MaxCacheItems"] = expected.MaxCacheItems.ToString(), ["ShutdownTimeout"] = expected.ShutdownTimeout.ToString(), @@ -109,7 +110,6 @@ public void Configure_BindsConfigurationToOptions() ["MinimumEventLevel"] = expected.MinimumEventLevel.ToString(), ["InitializeSdk"] = expected.InitializeSdk.ToString(), - ["Experimental:EnableLogs"] = expected.Experimental.EnableLogs.ToString(), ["ExperimentalLogging:MinimumLogLevel"] = expected.ExperimentalLogging.MinimumLogLevel.ToString(), }) .Build(); @@ -139,6 +139,7 @@ public void Configure_BindsConfigurationToOptions() actual.Distribution.Should().Be(expected.Distribution); actual.Environment.Should().Be(expected.Environment); actual.Dsn.Should().Be(expected.Dsn); + actual.EnableLogs.Should().Be(expected.EnableLogs); actual.MaxQueueItems.Should().Be(expected.MaxQueueItems); actual.MaxCacheItems.Should().Be(expected.MaxCacheItems); actual.ShutdownTimeout.Should().Be(expected.ShutdownTimeout); @@ -169,7 +170,6 @@ public void Configure_BindsConfigurationToOptions() actual.MinimumEventLevel.Should().Be(expected.MinimumEventLevel); actual.InitializeSdk.Should().Be(expected.InitializeSdk); - actual.Experimental.EnableLogs.Should().Be(expected.Experimental.EnableLogs); actual.ExperimentalLogging.MinimumLogLevel.Should().Be(expected.ExperimentalLogging.MinimumLogLevel); } } diff --git a/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerProviderTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerProviderTests.cs index a8c52f13da..4d0afafcc0 100644 --- a/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerProviderTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerProviderTests.cs @@ -18,7 +18,7 @@ private class Fixture public Fixture() { var loggingOptions = new SentryLoggingOptions(); - loggingOptions.Experimental.EnableLogs = true; + loggingOptions.EnableLogs = true; Options = Microsoft.Extensions.Options.Options.Create(loggingOptions); Hub = Substitute.For(); diff --git a/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs index dbede60ff9..4c2424967a 100644 --- a/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs @@ -48,7 +48,7 @@ public Fixture() } public void EnableHub(bool isEnabled) => Hub.IsEnabled.Returns(isEnabled); - public void EnableLogs(bool isEnabled) => Options.Value.Experimental.EnableLogs = isEnabled; + public void EnableLogs(bool isEnabled) => Options.Value.EnableLogs = isEnabled; public void SetMinimumLogLevel(LogLevel logLevel) => Options.Value.ExperimentalLogging.MinimumLogLevel = logLevel; public void WithActiveSpan(SentryId traceId, SpanId parentSpanId) diff --git a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt index f204ed0701..bb2d777e40 100644 --- a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt +++ b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt @@ -47,6 +47,6 @@ namespace Serilog Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, System.Collections.Generic.Dictionary? defaultTags = null, - bool? experimentalEnableLogs = default) { } + bool? enableLogs = default) { } } } \ No newline at end of file diff --git a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index f204ed0701..bb2d777e40 100644 --- a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt +++ b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -47,6 +47,6 @@ namespace Serilog Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, System.Collections.Generic.Dictionary? defaultTags = null, - bool? experimentalEnableLogs = default) { } + bool? enableLogs = default) { } } } \ No newline at end of file diff --git a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt index f204ed0701..bb2d777e40 100644 --- a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt +++ b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt @@ -47,6 +47,6 @@ namespace Serilog Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, System.Collections.Generic.Dictionary? defaultTags = null, - bool? experimentalEnableLogs = default) { } + bool? enableLogs = default) { } } } \ No newline at end of file diff --git a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index f204ed0701..bb2d777e40 100644 --- a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -47,6 +47,6 @@ namespace Serilog Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, System.Collections.Generic.Dictionary? defaultTags = null, - bool? experimentalEnableLogs = default) { } + bool? enableLogs = default) { } } } \ No newline at end of file diff --git a/test/Sentry.Serilog.Tests/AspNetCoreIntegrationTests.cs b/test/Sentry.Serilog.Tests/AspNetCoreIntegrationTests.cs index 760b5b84ff..3c2c9798b8 100644 --- a/test/Sentry.Serilog.Tests/AspNetCoreIntegrationTests.cs +++ b/test/Sentry.Serilog.Tests/AspNetCoreIntegrationTests.cs @@ -28,7 +28,7 @@ public async Task UnhandledException_MarkedAsUnhandled() [Fact] public async Task StructuredLogging_Disabled() { - Assert.False(ExperimentalEnableLogs); + Assert.False(EnableLogs); var handler = new RequestHandler { @@ -51,7 +51,7 @@ public async Task StructuredLogging_Disabled() [Fact] public async Task StructuredLogging_Enabled() { - ExperimentalEnableLogs = true; + EnableLogs = true; var handler = new RequestHandler { diff --git a/test/Sentry.Serilog.Tests/IntegrationTests.verify.cs b/test/Sentry.Serilog.Tests/IntegrationTests.verify.cs index aab8e7dd17..ffbe50ae5d 100644 --- a/test/Sentry.Serilog.Tests/IntegrationTests.verify.cs +++ b/test/Sentry.Serilog.Tests/IntegrationTests.verify.cs @@ -113,7 +113,7 @@ public Task StructuredLogging() _ => { _.MinimumEventLevel = (LogEventLevel)int.MaxValue; - _.Experimental.EnableLogs = true; + _.EnableLogs = true; _.Transport = transport; _.DiagnosticLogger = diagnosticLogger; _.Dsn = ValidDsn; diff --git a/test/Sentry.Serilog.Tests/SentrySerilogSinkExtensionsTests.cs b/test/Sentry.Serilog.Tests/SentrySerilogSinkExtensionsTests.cs index c0cda5c45a..36c3f1f802 100644 --- a/test/Sentry.Serilog.Tests/SentrySerilogSinkExtensionsTests.cs +++ b/test/Sentry.Serilog.Tests/SentrySerilogSinkExtensionsTests.cs @@ -25,10 +25,10 @@ private class Fixture public SentryLevel DiagnosticLevel { get; } = SentryLevel.Warning; public ReportAssembliesMode ReportAssembliesMode { get; } = ReportAssembliesMode.None; public DeduplicateMode DeduplicateMode { get; } = DeduplicateMode.SameExceptionInstance; + public bool EnableLogs { get; } = false; public bool InitializeSdk { get; } = false; public LogEventLevel MinimumEventLevel { get; } = LogEventLevel.Verbose; public LogEventLevel MinimumBreadcrumbLevel { get; } = LogEventLevel.Fatal; - public bool ExperimentalEnableLogs { get; } = true; public static SentrySerilogOptions GetSut() => new(); } @@ -98,7 +98,7 @@ public void ConfigureSentrySerilogOptions_WithAllParameters_MakesAppropriateChan _fixture.SampleRate, _fixture.Release, _fixture.Environment, _fixture.MaxQueueItems, _fixture.ShutdownTimeout, _fixture.DecompressionMethods, _fixture.RequestBodyCompressionLevel, _fixture.RequestBodyCompressionBuffered, _fixture.Debug, _fixture.DiagnosticLevel, - _fixture.ReportAssembliesMode, _fixture.DeduplicateMode, null, _fixture.ExperimentalEnableLogs); + _fixture.ReportAssembliesMode, _fixture.DeduplicateMode, null, _fixture.EnableLogs); // Compare individual properties Assert.Equal(_fixture.SendDefaultPii, sut.SendDefaultPii); @@ -119,7 +119,7 @@ public void ConfigureSentrySerilogOptions_WithAllParameters_MakesAppropriateChan Assert.Equal(_fixture.DiagnosticLevel, sut.DiagnosticLevel); Assert.Equal(_fixture.ReportAssembliesMode, sut.ReportAssembliesMode); Assert.Equal(_fixture.DeduplicateMode, sut.DeduplicateMode); - Assert.Equal(_fixture.ExperimentalEnableLogs, sut.Experimental.EnableLogs); + Assert.Equal(_fixture.EnableLogs, sut.EnableLogs); Assert.True(sut.InitializeSdk); Assert.Equal(_fixture.MinimumEventLevel, sut.MinimumEventLevel); Assert.Equal(_fixture.MinimumBreadcrumbLevel, sut.MinimumBreadcrumbLevel); diff --git a/test/Sentry.Serilog.Tests/SentrySinkTests.Structured.cs b/test/Sentry.Serilog.Tests/SentrySinkTests.Structured.cs index dc061a37e5..aa0806ad25 100644 --- a/test/Sentry.Serilog.Tests/SentrySinkTests.Structured.cs +++ b/test/Sentry.Serilog.Tests/SentrySinkTests.Structured.cs @@ -11,7 +11,7 @@ public void Emit_StructuredLogging_IsEnabled(bool isEnabled) { InMemorySentryStructuredLogger capturer = new(); _fixture.Hub.Logger.Returns(capturer); - _fixture.Options.Experimental.EnableLogs = isEnabled; + _fixture.Options.EnableLogs = isEnabled; var sut = _fixture.GetSut(); var logger = new LoggerConfiguration().WriteTo.Sink(sut).MinimumLevel.Verbose().CreateLogger(); @@ -28,7 +28,7 @@ public void Emit_StructuredLogging_UseHubOptionsOverSinkOptions(bool isEnabled) { InMemorySentryStructuredLogger capturer = new(); _fixture.Hub.Logger.Returns(capturer); - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; if (!isEnabled) { @@ -54,7 +54,7 @@ public void Emit_StructuredLogging_LogLevel(LogEventLevel level, SentryLogLevel { InMemorySentryStructuredLogger capturer = new(); _fixture.Hub.Logger.Returns(capturer); - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var sut = _fixture.GetSut(); var logger = new LoggerConfiguration().WriteTo.Sink(sut).MinimumLevel.Verbose().CreateLogger(); @@ -71,7 +71,7 @@ public void Emit_StructuredLogging_LogEvent(bool withActiveSpan) { InMemorySentryStructuredLogger capturer = new(); _fixture.Hub.Logger.Returns(capturer); - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; _fixture.Options.Environment = "test-environment"; _fixture.Options.Release = "test-release"; @@ -140,7 +140,7 @@ public void Emit_StructuredLoggingWithException_NoBreadcrumb() { InMemorySentryStructuredLogger capturer = new(); _fixture.Hub.Logger.Returns(capturer); - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var sut = _fixture.GetSut(); var logger = new LoggerConfiguration().WriteTo.Sink(sut).MinimumLevel.Verbose().CreateLogger(); @@ -156,7 +156,7 @@ public void Emit_StructuredLoggingWithoutException_LeavesBreadcrumb() { InMemorySentryStructuredLogger capturer = new(); _fixture.Hub.Logger.Returns(capturer); - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var sut = _fixture.GetSut(); var logger = new LoggerConfiguration().WriteTo.Sink(sut).MinimumLevel.Verbose().CreateLogger(); diff --git a/test/Sentry.Serilog.Tests/SerilogAspNetSentrySdkTestFixture.cs b/test/Sentry.Serilog.Tests/SerilogAspNetSentrySdkTestFixture.cs index b7b1a6d764..b453a9879c 100644 --- a/test/Sentry.Serilog.Tests/SerilogAspNetSentrySdkTestFixture.cs +++ b/test/Sentry.Serilog.Tests/SerilogAspNetSentrySdkTestFixture.cs @@ -8,7 +8,7 @@ public class SerilogAspNetSentrySdkTestFixture : AspNetSentrySdkTestFixture protected List Events; protected List Logs; - protected bool ExperimentalEnableLogs { get; set; } + protected bool EnableLogs { get; set; } protected override void ConfigureBuilder(WebHostBuilder builder) { @@ -19,8 +19,8 @@ protected override void ConfigureBuilder(WebHostBuilder builder) { options.SetBeforeSend((@event, _) => { Events.Add(@event); return @event; }); - options.Experimental.EnableLogs = ExperimentalEnableLogs; - options.Experimental.SetBeforeSendLog(log => { Logs.Add(log); return log; }); + options.EnableLogs = EnableLogs; + options.SetBeforeSendLog(log => { Logs.Add(log); return log; }); }; ConfigureApp = app => @@ -35,7 +35,7 @@ protected override void ConfigureBuilder(WebHostBuilder builder) builder.ConfigureLogging(loggingBuilder => { var logger = new LoggerConfiguration() - .WriteTo.Sentry(ValidDsn, experimentalEnableLogs: ExperimentalEnableLogs) + .WriteTo.Sentry(ValidDsn, enableLogs: EnableLogs) .CreateLogger(); loggingBuilder.AddSerilog(logger); }); diff --git a/test/Sentry.Testing/BindableTests.cs b/test/Sentry.Testing/BindableTests.cs index b8baf13c8e..f513d34e5d 100644 --- a/test/Sentry.Testing/BindableTests.cs +++ b/test/Sentry.Testing/BindableTests.cs @@ -65,10 +65,6 @@ private static KeyValuePair GetDummyBindableValue(Property {$"key1", $"{propertyInfo.Name}value1"}, {$"key2", $"{propertyInfo.Name}value2"} }, - not null when propertyType == typeof(SentryOptions.SentryExperimentalOptions) => new SentryOptions.SentryExperimentalOptions - { - EnableLogs = true, - }, not null when propertyType.FullName == "Sentry.Extensions.Logging.SentryLoggingOptions+SentryLoggingExperimentalOptions" => CreateSentryLoggingExperimentalOptions(), _ => throw new NotSupportedException($"Unsupported property type on property {propertyInfo.Name}") }; @@ -95,11 +91,6 @@ private static IEnumerable> ToConfigValues(KeyValue yield return new KeyValuePair($"{prop.Name}:{kvp.Key}", kvp.Value); } } - else if (propertyType == typeof(SentryOptions.SentryExperimentalOptions)) - { - var experimental = (SentryOptions.SentryExperimentalOptions)value; - yield return new KeyValuePair($"{prop.Name}:{nameof(SentryOptions.SentryExperimentalOptions.EnableLogs)}", Convert.ToString(experimental.EnableLogs, CultureInfo.InvariantCulture)); - } else if (propertyType.FullName == "Sentry.Extensions.Logging.SentryLoggingOptions+SentryLoggingExperimentalOptions") { var property = value.GetType().GetProperty("MinimumLogLevel"); @@ -139,10 +130,6 @@ protected void AssertContainsExpectedPropertyValues(TOptions actual) { actualValue.Should().BeEquivalentTo(expectedValue); } - else if (prop.PropertyType == typeof(SentryOptions.SentryExperimentalOptions)) - { - actualValue.Should().BeEquivalentTo(expectedValue); - } else if (prop.PropertyType.FullName == "Sentry.Extensions.Logging.SentryLoggingOptions+SentryLoggingExperimentalOptions") { actualValue.Should().BeEquivalentTo(expectedValue); diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt index c9e1f7fb87..0275d82418 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt @@ -711,10 +711,10 @@ namespace Sentry public string? Distribution { get; set; } public string? Dsn { get; set; } public bool EnableBackpressureHandling { get; set; } + public bool EnableLogs { get; set; } public bool EnableScopeSync { get; set; } public bool EnableSpotlight { get; set; } public string? Environment { get; set; } - public Sentry.SentryOptions.SentryExperimentalOptions Experimental { get; set; } public System.Collections.Generic.IList FailedRequestStatusCodes { get; set; } public System.Collections.Generic.IList FailedRequestTargets { get; set; } public System.TimeSpan FlushTimeout { get; set; } @@ -798,14 +798,10 @@ namespace Sentry public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeSend(System.Func beforeSend) { } public void SetBeforeSend(System.Func beforeSend) { } + public void SetBeforeSendLog(System.Func beforeSendLog) { } public void SetBeforeSendTransaction(System.Func beforeSendTransaction) { } public void SetBeforeSendTransaction(System.Func beforeSendTransaction) { } public Sentry.SentryOptions UseStackTraceFactory(Sentry.Extensibility.ISentryStackTraceFactory sentryStackTraceFactory) { } - public class SentryExperimentalOptions - { - public bool EnableLogs { get; set; } - public void SetBeforeSendLog(System.Func beforeSendLog) { } - } } public sealed class SentryPackage : Sentry.ISentryJsonSerializable { diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index c9e1f7fb87..0275d82418 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -711,10 +711,10 @@ namespace Sentry public string? Distribution { get; set; } public string? Dsn { get; set; } public bool EnableBackpressureHandling { get; set; } + public bool EnableLogs { get; set; } public bool EnableScopeSync { get; set; } public bool EnableSpotlight { get; set; } public string? Environment { get; set; } - public Sentry.SentryOptions.SentryExperimentalOptions Experimental { get; set; } public System.Collections.Generic.IList FailedRequestStatusCodes { get; set; } public System.Collections.Generic.IList FailedRequestTargets { get; set; } public System.TimeSpan FlushTimeout { get; set; } @@ -798,14 +798,10 @@ namespace Sentry public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeSend(System.Func beforeSend) { } public void SetBeforeSend(System.Func beforeSend) { } + public void SetBeforeSendLog(System.Func beforeSendLog) { } public void SetBeforeSendTransaction(System.Func beforeSendTransaction) { } public void SetBeforeSendTransaction(System.Func beforeSendTransaction) { } public Sentry.SentryOptions UseStackTraceFactory(Sentry.Extensibility.ISentryStackTraceFactory sentryStackTraceFactory) { } - public class SentryExperimentalOptions - { - public bool EnableLogs { get; set; } - public void SetBeforeSendLog(System.Func beforeSendLog) { } - } } public sealed class SentryPackage : Sentry.ISentryJsonSerializable { diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt index c9e1f7fb87..0275d82418 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt @@ -711,10 +711,10 @@ namespace Sentry public string? Distribution { get; set; } public string? Dsn { get; set; } public bool EnableBackpressureHandling { get; set; } + public bool EnableLogs { get; set; } public bool EnableScopeSync { get; set; } public bool EnableSpotlight { get; set; } public string? Environment { get; set; } - public Sentry.SentryOptions.SentryExperimentalOptions Experimental { get; set; } public System.Collections.Generic.IList FailedRequestStatusCodes { get; set; } public System.Collections.Generic.IList FailedRequestTargets { get; set; } public System.TimeSpan FlushTimeout { get; set; } @@ -798,14 +798,10 @@ namespace Sentry public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeSend(System.Func beforeSend) { } public void SetBeforeSend(System.Func beforeSend) { } + public void SetBeforeSendLog(System.Func beforeSendLog) { } public void SetBeforeSendTransaction(System.Func beforeSendTransaction) { } public void SetBeforeSendTransaction(System.Func beforeSendTransaction) { } public Sentry.SentryOptions UseStackTraceFactory(Sentry.Extensibility.ISentryStackTraceFactory sentryStackTraceFactory) { } - public class SentryExperimentalOptions - { - public bool EnableLogs { get; set; } - public void SetBeforeSendLog(System.Func beforeSendLog) { } - } } public sealed class SentryPackage : Sentry.ISentryJsonSerializable { diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index c95975f156..71406a71ac 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -693,10 +693,10 @@ namespace Sentry public string? Distribution { get; set; } public string? Dsn { get; set; } public bool EnableBackpressureHandling { get; set; } + public bool EnableLogs { get; set; } public bool EnableScopeSync { get; set; } public bool EnableSpotlight { get; set; } public string? Environment { get; set; } - public Sentry.SentryOptions.SentryExperimentalOptions Experimental { get; set; } public System.Collections.Generic.IList FailedRequestStatusCodes { get; set; } public System.Collections.Generic.IList FailedRequestTargets { get; set; } public System.TimeSpan FlushTimeout { get; set; } @@ -774,14 +774,10 @@ namespace Sentry public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeSend(System.Func beforeSend) { } public void SetBeforeSend(System.Func beforeSend) { } + public void SetBeforeSendLog(System.Func beforeSendLog) { } public void SetBeforeSendTransaction(System.Func beforeSendTransaction) { } public void SetBeforeSendTransaction(System.Func beforeSendTransaction) { } public Sentry.SentryOptions UseStackTraceFactory(Sentry.Extensibility.ISentryStackTraceFactory sentryStackTraceFactory) { } - public class SentryExperimentalOptions - { - public bool EnableLogs { get; set; } - public void SetBeforeSendLog(System.Func beforeSendLog) { } - } } public sealed class SentryPackage : Sentry.ISentryJsonSerializable { diff --git a/test/Sentry.Tests/HubTests.cs b/test/Sentry.Tests/HubTests.cs index b5d7a43a87..17c3474705 100644 --- a/test/Sentry.Tests/HubTests.cs +++ b/test/Sentry.Tests/HubTests.cs @@ -1765,7 +1765,7 @@ public async Task CaptureTransaction_WithTransactionProfiler_SendsTransactionWit public void Logger_IsDisabled_DoesNotCaptureLog() { // Arrange - Assert.False(_fixture.Options.Experimental.EnableLogs); + Assert.False(_fixture.Options.EnableLogs); var hub = _fixture.GetSut(); // Act @@ -1785,7 +1785,7 @@ public void Logger_IsDisabled_DoesNotCaptureLog() public void Logger_IsEnabled_DoesCaptureLog() { // Arrange - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var hub = _fixture.GetSut(); // Act @@ -1805,11 +1805,11 @@ public void Logger_IsEnabled_DoesCaptureLog() public void Logger_EnableAfterCreate_HasNoEffect() { // Arrange - Assert.False(_fixture.Options.Experimental.EnableLogs); + Assert.False(_fixture.Options.EnableLogs); var hub = _fixture.GetSut(); // Act - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; // Assert hub.Logger.Should().BeOfType(); @@ -1819,11 +1819,11 @@ public void Logger_EnableAfterCreate_HasNoEffect() public void Logger_DisableAfterCreate_HasNoEffect() { // Arrange - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var hub = _fixture.GetSut(); // Act - _fixture.Options.Experimental.EnableLogs = false; + _fixture.Options.EnableLogs = false; // Assert hub.Logger.Should().BeOfType(); @@ -1833,7 +1833,7 @@ public void Logger_DisableAfterCreate_HasNoEffect() public async Task Logger_FlushAsync_DoesCaptureLog() { // Arrange - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var hub = _fixture.GetSut(); // Act @@ -1858,7 +1858,7 @@ await _fixture.Client.Received(1).FlushAsync( public void Logger_Dispose_DoesCaptureLog() { // Arrange - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var hub = _fixture.GetSut(); // Act diff --git a/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs b/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs index 87894fed75..31aec367e3 100644 --- a/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs +++ b/test/Sentry.Tests/SentryStructuredLoggerTests.Format.cs @@ -13,7 +13,7 @@ public partial class SentryStructuredLoggerTests [InlineData(SentryLogLevel.Fatal)] public void Log_Enabled_CapturesEnvelope(SentryLogLevel level) { - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var logger = _fixture.GetSut(); Envelope envelope = null!; @@ -35,7 +35,7 @@ public void Log_Enabled_CapturesEnvelope(SentryLogLevel level) [InlineData(SentryLogLevel.Fatal)] public void Log_Disabled_DoesNotCaptureEnvelope(SentryLogLevel level) { - _fixture.Options.Experimental.EnableLogs.Should().BeFalse(); + _fixture.Options.EnableLogs.Should().BeFalse(); var logger = _fixture.GetSut(); logger.Log(level, "Template string with arguments: {0}, {1}, {2}, {3}", "string", true, 1, 2.2); @@ -53,7 +53,7 @@ public void Log_Disabled_DoesNotCaptureEnvelope(SentryLogLevel level) [InlineData(SentryLogLevel.Fatal)] public void Log_ConfigureLog_Enabled_CapturesEnvelope(SentryLogLevel level) { - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var logger = _fixture.GetSut(); Envelope envelope = null!; @@ -75,7 +75,7 @@ public void Log_ConfigureLog_Enabled_CapturesEnvelope(SentryLogLevel level) [InlineData(SentryLogLevel.Fatal)] public void Log_ConfigureLog_Disabled_DoesNotCaptureEnvelope(SentryLogLevel level) { - _fixture.Options.Experimental.EnableLogs.Should().BeFalse(); + _fixture.Options.EnableLogs.Should().BeFalse(); var logger = _fixture.GetSut(); logger.Log(level, ConfigureLog, "Template string with arguments: {0}, {1}, {2}, {3}", "string", true, 1, 2.2); diff --git a/test/Sentry.Tests/SentryStructuredLoggerTests.cs b/test/Sentry.Tests/SentryStructuredLoggerTests.cs index bee10461ff..b4e9e8c775 100644 --- a/test/Sentry.Tests/SentryStructuredLoggerTests.cs +++ b/test/Sentry.Tests/SentryStructuredLoggerTests.cs @@ -76,7 +76,7 @@ public void Dispose() [Fact] public void Create_Enabled_NewDefaultInstance() { - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var instance = _fixture.GetSut(); var other = _fixture.GetSut(); @@ -88,7 +88,7 @@ public void Create_Enabled_NewDefaultInstance() [Fact] public void Create_Disabled_CachedDisabledInstance() { - _fixture.Options.Experimental.EnableLogs.Should().BeFalse(); + _fixture.Options.EnableLogs.Should().BeFalse(); var instance = _fixture.GetSut(); var other = _fixture.GetSut(); @@ -101,7 +101,7 @@ public void Create_Disabled_CachedDisabledInstance() public void Log_WithoutActiveSpan_CapturesEnvelope() { _fixture.WithoutActiveSpan(); - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var logger = _fixture.GetSut(); Envelope envelope = null!; @@ -120,8 +120,8 @@ public void Log_WithBeforeSendLog_InvokesCallback() var invocations = 0; SentryLog configuredLog = null!; - _fixture.Options.Experimental.EnableLogs = true; - _fixture.Options.Experimental.SetBeforeSendLog((SentryLog log) => + _fixture.Options.EnableLogs = true; + _fixture.Options.SetBeforeSendLog((SentryLog log) => { invocations++; configuredLog = log; @@ -142,8 +142,8 @@ public void Log_WhenBeforeSendLogReturnsNull_DoesNotCaptureEnvelope() { var invocations = 0; - _fixture.Options.Experimental.EnableLogs = true; - _fixture.Options.Experimental.SetBeforeSendLog((SentryLog log) => + _fixture.Options.EnableLogs = true; + _fixture.Options.SetBeforeSendLog((SentryLog log) => { invocations++; return null; @@ -159,7 +159,7 @@ public void Log_WhenBeforeSendLogReturnsNull_DoesNotCaptureEnvelope() [Fact] public void Log_InvalidFormat_DoesNotCaptureEnvelope() { - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var logger = _fixture.GetSut(); logger.LogTrace("Template string with arguments: {0}, {1}, {2}, {3}, {4}", "string", true, 1, 2.2); @@ -175,7 +175,7 @@ public void Log_InvalidFormat_DoesNotCaptureEnvelope() [Fact] public void Log_InvalidConfigureLog_DoesNotCaptureEnvelope() { - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var logger = _fixture.GetSut(); logger.LogTrace(static (SentryLog log) => throw new InvalidOperationException(), "Template string with arguments: {0}, {1}, {2}, {3}", "string", true, 1, 2.2); @@ -191,8 +191,8 @@ public void Log_InvalidConfigureLog_DoesNotCaptureEnvelope() [Fact] public void Log_InvalidBeforeSendLog_DoesNotCaptureEnvelope() { - _fixture.Options.Experimental.EnableLogs = true; - _fixture.Options.Experimental.SetBeforeSendLog(static (SentryLog log) => throw new InvalidOperationException()); + _fixture.Options.EnableLogs = true; + _fixture.Options.SetBeforeSendLog(static (SentryLog log) => throw new InvalidOperationException()); var logger = _fixture.GetSut(); logger.LogTrace("Template string with arguments: {0}, {1}, {2}, {3}", "string", true, 1, 2.2); @@ -208,7 +208,7 @@ public void Log_InvalidBeforeSendLog_DoesNotCaptureEnvelope() [Fact] public void Flush_AfterLog_CapturesEnvelope() { - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var logger = _fixture.GetSut(); Envelope envelope = null!; @@ -230,7 +230,7 @@ public void Flush_AfterLog_CapturesEnvelope() [Fact] public void Dispose_BeforeLog_DoesNotCaptureEnvelope() { - _fixture.Options.Experimental.EnableLogs = true; + _fixture.Options.EnableLogs = true; var logger = _fixture.GetSut(); var defaultLogger = logger.Should().BeOfType().Which; From cd79096c603ca49ff143fa2899c69e94d59e367d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Thu, 6 Nov 2025 17:17:00 +0100 Subject: [PATCH 02/18] fix: MAUI sample --- samples/Sentry.Samples.Maui/MauiProgram.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/Sentry.Samples.Maui/MauiProgram.cs b/samples/Sentry.Samples.Maui/MauiProgram.cs index 1a8a6a30a7..0c45693cf2 100644 --- a/samples/Sentry.Samples.Maui/MauiProgram.cs +++ b/samples/Sentry.Samples.Maui/MauiProgram.cs @@ -33,7 +33,7 @@ public static MauiApp CreateMauiApp() options.AttachScreenshot = true; options.Debug = true; - options.Experimental.EnableLogs = true; + options.EnableLogs = true; options.SampleRate = 1.0F; // The Sentry MVVM Community Toolkit integration automatically creates traces for async relay commands, From 33aaeacb514f60cff4e0684e228fd906898f3fae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Thu, 6 Nov 2025 19:06:04 +0100 Subject: [PATCH 03/18] ref(logs): remove experimental MinimumLogLevel --- .../SentryStructuredLoggerBenchmarks.cs | 4 --- samples/Sentry.Samples.ME.Logging/Program.cs | 1 - .../BindableSentryLoggingOptions.cs | 2 -- .../SentryLoggingOptions.cs | 35 ------------------- .../SentryStructuredLogger.cs | 3 +- ...iApprovalTests.Run.DotNet10_0.verified.txt | 7 ---- ...piApprovalTests.Run.DotNet8_0.verified.txt | 7 ---- ...piApprovalTests.Run.DotNet9_0.verified.txt | 7 ---- .../ApiApprovalTests.Run.Net4_8.verified.txt | 5 --- .../SentryLoggingOptionsSetupTests.cs | 5 --- .../SentryStructuredLoggerTests.cs | 18 ++++------ test/Sentry.Testing/BindableTests.cs | 19 ---------- 12 files changed, 8 insertions(+), 105 deletions(-) diff --git a/benchmarks/Sentry.Benchmarks/Extensions.Logging/SentryStructuredLoggerBenchmarks.cs b/benchmarks/Sentry.Benchmarks/Extensions.Logging/SentryStructuredLoggerBenchmarks.cs index 08beda17f3..08f7296882 100644 --- a/benchmarks/Sentry.Benchmarks/Extensions.Logging/SentryStructuredLoggerBenchmarks.cs +++ b/benchmarks/Sentry.Benchmarks/Extensions.Logging/SentryStructuredLoggerBenchmarks.cs @@ -23,10 +23,6 @@ public void Setup() { Dsn = DsnSamples.ValidDsn, EnableLogs = true, - ExperimentalLogging = - { - MinimumLogLevel = LogLevel.Information, - } }; options.SetBeforeSendLog((SentryLog log) => { diff --git a/samples/Sentry.Samples.ME.Logging/Program.cs b/samples/Sentry.Samples.ME.Logging/Program.cs index 996a2aa59f..b966a243ed 100644 --- a/samples/Sentry.Samples.ME.Logging/Program.cs +++ b/samples/Sentry.Samples.ME.Logging/Program.cs @@ -23,7 +23,6 @@ // Optionally configure options: The default values are: options.MinimumBreadcrumbLevel = LogLevel.Information; // It requires at least this level to store breadcrumb options.MinimumEventLevel = LogLevel.Error; // This level or above will result in event sent to Sentry - options.ExperimentalLogging.MinimumLogLevel = LogLevel.Trace; // This level or above will result in log sent to Sentry // This option enables Logs sent to Sentry. options.EnableLogs = true; diff --git a/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs b/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs index 7843ad9975..2a82a0bb1c 100644 --- a/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs +++ b/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs @@ -22,7 +22,5 @@ public void ApplyTo(SentryLoggingOptions options) options.MinimumBreadcrumbLevel = MinimumBreadcrumbLevel ?? options.MinimumBreadcrumbLevel; options.MinimumEventLevel = MinimumEventLevel ?? options.MinimumEventLevel; options.InitializeSdk = InitializeSdk ?? options.InitializeSdk; - - options.ExperimentalLogging.MinimumLogLevel = ExperimentalLogging.MinimumLogLevel ?? options.ExperimentalLogging.MinimumLogLevel; } } diff --git a/src/Sentry.Extensions.Logging/SentryLoggingOptions.cs b/src/Sentry.Extensions.Logging/SentryLoggingOptions.cs index d181b645bf..3014f7cd0e 100644 --- a/src/Sentry.Extensions.Logging/SentryLoggingOptions.cs +++ b/src/Sentry.Extensions.Logging/SentryLoggingOptions.cs @@ -50,39 +50,4 @@ public class SentryLoggingOptions : SentryOptions /// List of callbacks to be invoked when initializing the SDK /// internal Action[] ConfigureScopeCallbacks { get; set; } = Array.Empty>(); - - /// - /// Experimental Sentry Logging features. - /// - /// - /// This and related experimental APIs may change in the future. - /// - [Experimental(Infrastructure.DiagnosticId.ExperimentalFeature)] - public SentryLoggingExperimentalOptions ExperimentalLogging { get; set; } = new(); - - /// - /// Experimental Sentry Logging options. - /// - /// - /// This and related experimental APIs may change in the future. - /// - [Experimental(Infrastructure.DiagnosticId.ExperimentalFeature)] - public sealed class SentryLoggingExperimentalOptions - { - internal SentryLoggingExperimentalOptions() - { - } - - /// - /// Gets or sets the minimum log level. - /// This API is experimental and it may change in the future. - /// - /// - /// Logs with this level or higher will be stored as . - /// - /// - /// The minimum log level. - /// - public LogLevel MinimumLogLevel { get; set; } = LogLevel.Trace; - } } diff --git a/src/Sentry.Extensions.Logging/SentryStructuredLogger.cs b/src/Sentry.Extensions.Logging/SentryStructuredLogger.cs index d38fcf6f70..c5d526253d 100644 --- a/src/Sentry.Extensions.Logging/SentryStructuredLogger.cs +++ b/src/Sentry.Extensions.Logging/SentryStructuredLogger.cs @@ -30,8 +30,7 @@ public bool IsEnabled(LogLevel logLevel) { return _hub.IsEnabled && _options.EnableLogs - && logLevel != LogLevel.None - && logLevel >= _options.ExperimentalLogging.MinimumLogLevel; + && logLevel != LogLevel.None; } public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) diff --git a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt index 9112ddfffa..b438b0af45 100644 --- a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt +++ b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt @@ -38,17 +38,10 @@ namespace Sentry.Extensions.Logging public class SentryLoggingOptions : Sentry.SentryOptions { public SentryLoggingOptions() { } - [System.Diagnostics.CodeAnalysis.Experimental("SENTRY0001")] - public Sentry.Extensions.Logging.SentryLoggingOptions.SentryLoggingExperimentalOptions ExperimentalLogging { get; set; } public bool InitializeSdk { get; set; } public Microsoft.Extensions.Logging.LogLevel MinimumBreadcrumbLevel { get; set; } public Microsoft.Extensions.Logging.LogLevel MinimumEventLevel { get; set; } public void ConfigureScope(System.Action action) { } - [System.Diagnostics.CodeAnalysis.Experimental("SENTRY0001")] - public sealed class SentryLoggingExperimentalOptions - { - public Microsoft.Extensions.Logging.LogLevel MinimumLogLevel { get; set; } - } } public static class SentryLoggingOptionsExtensions { diff --git a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index 9112ddfffa..b438b0af45 100644 --- a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt +++ b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -38,17 +38,10 @@ namespace Sentry.Extensions.Logging public class SentryLoggingOptions : Sentry.SentryOptions { public SentryLoggingOptions() { } - [System.Diagnostics.CodeAnalysis.Experimental("SENTRY0001")] - public Sentry.Extensions.Logging.SentryLoggingOptions.SentryLoggingExperimentalOptions ExperimentalLogging { get; set; } public bool InitializeSdk { get; set; } public Microsoft.Extensions.Logging.LogLevel MinimumBreadcrumbLevel { get; set; } public Microsoft.Extensions.Logging.LogLevel MinimumEventLevel { get; set; } public void ConfigureScope(System.Action action) { } - [System.Diagnostics.CodeAnalysis.Experimental("SENTRY0001")] - public sealed class SentryLoggingExperimentalOptions - { - public Microsoft.Extensions.Logging.LogLevel MinimumLogLevel { get; set; } - } } public static class SentryLoggingOptionsExtensions { diff --git a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt index 9112ddfffa..b438b0af45 100644 --- a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt +++ b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt @@ -38,17 +38,10 @@ namespace Sentry.Extensions.Logging public class SentryLoggingOptions : Sentry.SentryOptions { public SentryLoggingOptions() { } - [System.Diagnostics.CodeAnalysis.Experimental("SENTRY0001")] - public Sentry.Extensions.Logging.SentryLoggingOptions.SentryLoggingExperimentalOptions ExperimentalLogging { get; set; } public bool InitializeSdk { get; set; } public Microsoft.Extensions.Logging.LogLevel MinimumBreadcrumbLevel { get; set; } public Microsoft.Extensions.Logging.LogLevel MinimumEventLevel { get; set; } public void ConfigureScope(System.Action action) { } - [System.Diagnostics.CodeAnalysis.Experimental("SENTRY0001")] - public sealed class SentryLoggingExperimentalOptions - { - public Microsoft.Extensions.Logging.LogLevel MinimumLogLevel { get; set; } - } } public static class SentryLoggingOptionsExtensions { diff --git a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index e4dd758823..b438b0af45 100644 --- a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -38,15 +38,10 @@ namespace Sentry.Extensions.Logging public class SentryLoggingOptions : Sentry.SentryOptions { public SentryLoggingOptions() { } - public Sentry.Extensions.Logging.SentryLoggingOptions.SentryLoggingExperimentalOptions ExperimentalLogging { get; set; } public bool InitializeSdk { get; set; } public Microsoft.Extensions.Logging.LogLevel MinimumBreadcrumbLevel { get; set; } public Microsoft.Extensions.Logging.LogLevel MinimumEventLevel { get; set; } public void ConfigureScope(System.Action action) { } - public sealed class SentryLoggingExperimentalOptions - { - public Microsoft.Extensions.Logging.LogLevel MinimumLogLevel { get; set; } - } } public static class SentryLoggingOptionsExtensions { diff --git a/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs index 798dad7bf2..6417344f91 100644 --- a/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs @@ -58,7 +58,6 @@ public void Configure_BindsConfigurationToOptions() MinimumEventLevel = LogLevel.Error, InitializeSdk = true }; - expected.ExperimentalLogging.MinimumLogLevel = LogLevel.None; var config = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { @@ -109,8 +108,6 @@ public void Configure_BindsConfigurationToOptions() ["MinimumBreadcrumbLevel"] = expected.MinimumBreadcrumbLevel.ToString(), ["MinimumEventLevel"] = expected.MinimumEventLevel.ToString(), ["InitializeSdk"] = expected.InitializeSdk.ToString(), - - ["ExperimentalLogging:MinimumLogLevel"] = expected.ExperimentalLogging.MinimumLogLevel.ToString(), }) .Build(); @@ -169,8 +166,6 @@ public void Configure_BindsConfigurationToOptions() actual.MinimumBreadcrumbLevel.Should().Be(expected.MinimumBreadcrumbLevel); actual.MinimumEventLevel.Should().Be(expected.MinimumEventLevel); actual.InitializeSdk.Should().Be(expected.InitializeSdk); - - actual.ExperimentalLogging.MinimumLogLevel.Should().Be(expected.ExperimentalLogging.MinimumLogLevel); } } } diff --git a/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs index 4c2424967a..b2d13fb183 100644 --- a/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs @@ -44,12 +44,10 @@ public Fixture() EnableHub(true); EnableLogs(true); - SetMinimumLogLevel(default); } public void EnableHub(bool isEnabled) => Hub.IsEnabled.Returns(isEnabled); public void EnableLogs(bool isEnabled) => Options.Value.EnableLogs = isEnabled; - public void SetMinimumLogLevel(LogLevel logLevel) => Options.Value.ExperimentalLogging.MinimumLogLevel = logLevel; public void WithActiveSpan(SentryId traceId, SpanId parentSpanId) { @@ -251,20 +249,18 @@ public void Log_WithoutEventName_CaptureLog() } [Theory] - [InlineData(true, true, LogLevel.Warning, LogLevel.Warning, true)] - [InlineData(false, true, LogLevel.Warning, LogLevel.Warning, false)] - [InlineData(true, false, LogLevel.Warning, LogLevel.Warning, false)] - [InlineData(true, true, LogLevel.Information, LogLevel.Warning, true)] - [InlineData(true, true, LogLevel.Error, LogLevel.Warning, false)] - public void IsEnabled_HubOptionsMinimumLogLevel_Returns(bool isHubEnabled, bool isLogsEnabled, LogLevel minimumLogLevel, LogLevel actualLogLevel, bool expectedIsEnabled) + [InlineData(true, true, LogLevel.Information, true)] + [InlineData(false, true, LogLevel.Information, false)] + [InlineData(true, false, LogLevel.Information, false)] + [InlineData(true, true, LogLevel.None, false)] + public void IsEnabled_HubOptionsMinimumLogLevel_Returns(bool isHubEnabled, bool isLogsEnabled, LogLevel logLevel, bool expectedIsEnabled) { _fixture.EnableHub(isHubEnabled); _fixture.EnableLogs(isLogsEnabled); - _fixture.SetMinimumLogLevel(minimumLogLevel); var logger = _fixture.GetSut(); - var isEnabled = logger.IsEnabled(actualLogLevel); - logger.Log(actualLogLevel, "message"); + var isEnabled = logger.IsEnabled(logLevel); + logger.Log(logLevel, "message"); isEnabled.Should().Be(expectedIsEnabled); if (expectedIsEnabled) diff --git a/test/Sentry.Testing/BindableTests.cs b/test/Sentry.Testing/BindableTests.cs index f513d34e5d..68dd553a36 100644 --- a/test/Sentry.Testing/BindableTests.cs +++ b/test/Sentry.Testing/BindableTests.cs @@ -65,21 +65,11 @@ private static KeyValuePair GetDummyBindableValue(Property {$"key1", $"{propertyInfo.Name}value1"}, {$"key2", $"{propertyInfo.Name}value2"} }, - not null when propertyType.FullName == "Sentry.Extensions.Logging.SentryLoggingOptions+SentryLoggingExperimentalOptions" => CreateSentryLoggingExperimentalOptions(), _ => throw new NotSupportedException($"Unsupported property type on property {propertyInfo.Name}") }; return new KeyValuePair(propertyInfo, value); } - private static object CreateSentryLoggingExperimentalOptions() - { - var options = Activator.CreateInstance("Sentry.Extensions.Logging", "Sentry.Extensions.Logging.SentryLoggingOptions+SentryLoggingExperimentalOptions", false, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null, null); - var instance = options.Unwrap(); - var property = instance.GetType().GetProperty("MinimumLogLevel", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - property.SetValue(instance, int.MaxValue); - return instance; - } - private static IEnumerable> ToConfigValues(KeyValuePair item) { var (prop, value) = item; @@ -91,11 +81,6 @@ private static IEnumerable> ToConfigValues(KeyValue yield return new KeyValuePair($"{prop.Name}:{kvp.Key}", kvp.Value); } } - else if (propertyType.FullName == "Sentry.Extensions.Logging.SentryLoggingOptions+SentryLoggingExperimentalOptions") - { - var property = value.GetType().GetProperty("MinimumLogLevel"); - yield return new KeyValuePair($"{prop.Name}:MinimumLogLevel", Convert.ToString(property.GetValue(value), CultureInfo.InvariantCulture)); - } else { yield return new KeyValuePair(prop.Name, Convert.ToString(value, CultureInfo.InvariantCulture)); @@ -130,10 +115,6 @@ protected void AssertContainsExpectedPropertyValues(TOptions actual) { actualValue.Should().BeEquivalentTo(expectedValue); } - else if (prop.PropertyType.FullName == "Sentry.Extensions.Logging.SentryLoggingOptions+SentryLoggingExperimentalOptions") - { - actualValue.Should().BeEquivalentTo(expectedValue); - } else { actualValue.Should().Be(expectedValue); From 1a119b57084695a820a452c1741d9d7e1849d007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Thu, 20 Nov 2025 18:43:35 +0100 Subject: [PATCH 04/18] merge: cleanup after merge --- .../BindableSentryLoggingOptions.cs | 7 ------- src/Sentry.Extensions.Logging/LoggingBuilderExtensions.cs | 2 +- .../SentryStructuredLoggerTests.cs | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs b/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs index 2a82a0bb1c..299e61a21c 100644 --- a/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs +++ b/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs @@ -9,13 +9,6 @@ internal class BindableSentryLoggingOptions : BindableSentryOptions public LogLevel? MinimumEventLevel { get; set; } public bool? InitializeSdk { get; set; } - public BindableSentryLoggingExperimentalOptions ExperimentalLogging { get; set; } = new(); - - internal sealed class BindableSentryLoggingExperimentalOptions - { - public LogLevel? MinimumLogLevel { get; set; } - } - public void ApplyTo(SentryLoggingOptions options) { base.ApplyTo(options); diff --git a/src/Sentry.Extensions.Logging/LoggingBuilderExtensions.cs b/src/Sentry.Extensions.Logging/LoggingBuilderExtensions.cs index f2a4957c11..6423ee33df 100644 --- a/src/Sentry.Extensions.Logging/LoggingBuilderExtensions.cs +++ b/src/Sentry.Extensions.Logging/LoggingBuilderExtensions.cs @@ -60,7 +60,7 @@ internal static ILoggingBuilder AddSentry( builder.AddFilter(_ => true); // Logs from the SentryLogger should not flow to the SentryStructuredLogger as this may cause recursive invocations. - // Filtering of logs is handled in SentryStructuredLogger, using SentryOptions.MinimumLogLevel + // Filtering of structured logs is handled by Microsoft.Extensions.Configuration and Microsoft.Extensions.Options. builder.AddFilter(static (string? categoryName, LogLevel logLevel) => { return categoryName is null diff --git a/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs index b2d13fb183..3153c0526a 100644 --- a/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerTests.cs @@ -253,7 +253,7 @@ public void Log_WithoutEventName_CaptureLog() [InlineData(false, true, LogLevel.Information, false)] [InlineData(true, false, LogLevel.Information, false)] [InlineData(true, true, LogLevel.None, false)] - public void IsEnabled_HubOptionsMinimumLogLevel_Returns(bool isHubEnabled, bool isLogsEnabled, LogLevel logLevel, bool expectedIsEnabled) + public void IsEnabled_HubAndOptions_Returns(bool isHubEnabled, bool isLogsEnabled, LogLevel logLevel, bool expectedIsEnabled) { _fixture.EnableHub(isHubEnabled); _fixture.EnableLogs(isLogsEnabled); From 9ac70b78c1342ca063d262701bca273c8d982ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Tue, 25 Nov 2025 15:22:58 +0100 Subject: [PATCH 05/18] fix(logs): minimum Log-Level for Structured Logs --- .../Program.cs | 7 +- .../appsettings.json | 14 ++++ .../SentryAspNetCoreLoggerProvider.cs | 6 ++ ...entryAspNetCoreStructuredLoggerProvider.cs | 2 +- .../SentryWebHostBuilderExtensions.cs | 11 +-- .../LoggingBuilderExtensions.cs | 6 +- .../SentryStructuredLoggerProvider.cs | 7 +- .../Internal/SentryMauiLoggerProvider.cs | 8 ++- .../SentryMauiStructuredLoggerProvider.cs | 2 +- .../SentryMauiAppBuilderExtensions.cs | 9 ++- .../SentryAspNetCoreLoggerProviderTests.cs | 70 +++++++++++++++++++ ...AspNetCoreStructuredLoggerProviderTests.cs | 10 +++ .../SentryWebHostBuilderExtensionsTests.cs | 62 ++++++++++++++++ .../LoggingBuilderExtensionsTests.cs | 65 +++++++++++++++++ .../LoggingTests.cs | 60 +++++++++++++++- .../SentryLoggerProviderTests.cs | 12 ++++ .../SentryStructuredLoggerProviderTests.cs | 10 +++ .../Internal/SentryMauiLoggerProviderTests.cs | 70 +++++++++++++++++++ ...SentryMauiStructuredLoggerProviderTests.cs | 10 +++ .../SentryMauiAppBuilderExtensionsTests.cs | 58 +++++++++++++++ 20 files changed, 476 insertions(+), 23 deletions(-) create mode 100644 samples/Sentry.Samples.AspNetCore.Basic/appsettings.json create mode 100644 test/Sentry.AspNetCore.Tests/SentryAspNetCoreLoggerProviderTests.cs create mode 100644 test/Sentry.Extensions.Logging.Tests/LoggingBuilderExtensionsTests.cs create mode 100644 test/Sentry.Maui.Tests/Internal/SentryMauiLoggerProviderTests.cs diff --git a/samples/Sentry.Samples.AspNetCore.Basic/Program.cs b/samples/Sentry.Samples.AspNetCore.Basic/Program.cs index 18cee62d80..96788a87c0 100644 --- a/samples/Sentry.Samples.AspNetCore.Basic/Program.cs +++ b/samples/Sentry.Samples.AspNetCore.Basic/Program.cs @@ -16,7 +16,12 @@ options.Debug = true; #endif - // This option enables Logs sent to Sentry. + // Configure the minimum Log Level of Breadcrumbs and Events + options.MinimumBreadcrumbLevel = LogLevel.Information; + options.MinimumEventLevel = LogLevel.Error; + + // This option enables Logs sent to Sentry + // Configure the minimum Log Level of Structured-Logs via e.g. "appsettings.json" and "appsettings.{HostEnvironment}.json" options.EnableLogs = true; }); diff --git a/samples/Sentry.Samples.AspNetCore.Basic/appsettings.json b/samples/Sentry.Samples.AspNetCore.Basic/appsettings.json new file mode 100644 index 0000000000..d61e9906ed --- /dev/null +++ b/samples/Sentry.Samples.AspNetCore.Basic/appsettings.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + }, + "Sentry": { + "LogLevel": { + "Default": "Trace" + } + } + }, + "AllowedHosts": "*" +} diff --git a/src/Sentry.AspNetCore/SentryAspNetCoreLoggerProvider.cs b/src/Sentry.AspNetCore/SentryAspNetCoreLoggerProvider.cs index a1e7516ea4..12a27bc009 100644 --- a/src/Sentry.AspNetCore/SentryAspNetCoreLoggerProvider.cs +++ b/src/Sentry.AspNetCore/SentryAspNetCoreLoggerProvider.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Sentry.Extensions.Logging; +using Sentry.Infrastructure; namespace Sentry.AspNetCore; @@ -17,4 +18,9 @@ public SentryAspNetCoreLoggerProvider(IOptions options, : base(options, hub) { } + + internal SentryAspNetCoreLoggerProvider(SentryAspNetCoreOptions options, IHub hub, ISystemClock clock) + : base(hub, clock, options) + { + } } diff --git a/src/Sentry.AspNetCore/SentryAspNetCoreStructuredLoggerProvider.cs b/src/Sentry.AspNetCore/SentryAspNetCoreStructuredLoggerProvider.cs index 90cb033375..b2096d8bef 100644 --- a/src/Sentry.AspNetCore/SentryAspNetCoreStructuredLoggerProvider.cs +++ b/src/Sentry.AspNetCore/SentryAspNetCoreStructuredLoggerProvider.cs @@ -8,7 +8,7 @@ namespace Sentry.AspNetCore; /// /// Structured Logger Provider for Sentry. /// -[ProviderAlias("SentryLogs")] +[ProviderAlias("Sentry")] internal sealed class SentryAspNetCoreStructuredLoggerProvider : SentryStructuredLoggerProvider { public SentryAspNetCoreStructuredLoggerProvider(IOptions options, IHub hub) diff --git a/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs b/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs index 2b5f74bf4d..3b021d6c65 100644 --- a/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs +++ b/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs @@ -95,14 +95,15 @@ public static IWebHostBuilder UseSentry( _ = logging.Services.AddSingleton(); _ = logging.Services.AddSingleton(); - _ = logging.AddFilter( - "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware", - LogLevel.None); - _ = logging.AddFilter(static (string? categoryName, LogLevel logLevel) => + // Add a delegate rule in order to ignore Configuration like "appsettings.json" and "appsettings.{HostEnvironment}.json" + _ = logging.AddFilter(static (string? categoryName, LogLevel logLevel) => { return categoryName is null - || (categoryName != "Sentry.ISentryClient" && categoryName != "Sentry.AspNetCore.SentryMiddleware"); + || categoryName != "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware"; }); + // Add non-delegate rules in order to respect Configuration like "appsettings.json" and "appsettings.{HostEnvironment}.json" + _ = logging.AddFilter("Sentry.ISentryClient", LogLevel.None); + _ = logging.AddFilter("Sentry.AspNetCore.SentryMiddleware", LogLevel.None); var sentryBuilder = logging.Services.AddSentry(); configureSentry?.Invoke(context, sentryBuilder); diff --git a/src/Sentry.Extensions.Logging/LoggingBuilderExtensions.cs b/src/Sentry.Extensions.Logging/LoggingBuilderExtensions.cs index 6423ee33df..7731288078 100644 --- a/src/Sentry.Extensions.Logging/LoggingBuilderExtensions.cs +++ b/src/Sentry.Extensions.Logging/LoggingBuilderExtensions.cs @@ -61,11 +61,7 @@ internal static ILoggingBuilder AddSentry( // Logs from the SentryLogger should not flow to the SentryStructuredLogger as this may cause recursive invocations. // Filtering of structured logs is handled by Microsoft.Extensions.Configuration and Microsoft.Extensions.Options. - builder.AddFilter(static (string? categoryName, LogLevel logLevel) => - { - return categoryName is null - || categoryName != "Sentry.ISentryClient"; - }); + builder.AddFilter("Sentry.ISentryClient", LogLevel.None); return builder; } diff --git a/src/Sentry.Extensions.Logging/SentryStructuredLoggerProvider.cs b/src/Sentry.Extensions.Logging/SentryStructuredLoggerProvider.cs index fdfe0a527c..198147fd72 100644 --- a/src/Sentry.Extensions.Logging/SentryStructuredLoggerProvider.cs +++ b/src/Sentry.Extensions.Logging/SentryStructuredLoggerProvider.cs @@ -7,7 +7,7 @@ namespace Sentry.Extensions.Logging; /// /// Sentry Structured Logger Provider. /// -[ProviderAlias("SentryLogs")] +[ProviderAlias("Sentry")] internal class SentryStructuredLoggerProvider : ILoggerProvider { private readonly SentryLoggingOptions _options; @@ -20,6 +20,11 @@ public SentryStructuredLoggerProvider(IOptions options, IH { } + internal SentryStructuredLoggerProvider(IHub hub, ISystemClock clock, SentryLoggingOptions options) + : this(options, hub, clock, CreateSdkVersion()) + { + } + internal SentryStructuredLoggerProvider(SentryLoggingOptions options, IHub hub, ISystemClock clock, SdkVersion sdk) { _options = options; diff --git a/src/Sentry.Maui/Internal/SentryMauiLoggerProvider.cs b/src/Sentry.Maui/Internal/SentryMauiLoggerProvider.cs index df33ef2342..ef1d1af9e3 100644 --- a/src/Sentry.Maui/Internal/SentryMauiLoggerProvider.cs +++ b/src/Sentry.Maui/Internal/SentryMauiLoggerProvider.cs @@ -1,14 +1,20 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Sentry.Extensions.Logging; +using Sentry.Infrastructure; namespace Sentry.Maui.Internal; [ProviderAlias("Sentry")] -internal class SentryMauiLoggerProvider : SentryLoggerProvider +internal sealed class SentryMauiLoggerProvider : SentryLoggerProvider { public SentryMauiLoggerProvider(IOptions options, IHub hub) : base(options, hub) { } + + internal SentryMauiLoggerProvider(SentryMauiOptions options, IHub hub, ISystemClock clock) + : base(hub, clock, options) + { + } } diff --git a/src/Sentry.Maui/Internal/SentryMauiStructuredLoggerProvider.cs b/src/Sentry.Maui/Internal/SentryMauiStructuredLoggerProvider.cs index d0525a4b49..aa9cf8ca3e 100644 --- a/src/Sentry.Maui/Internal/SentryMauiStructuredLoggerProvider.cs +++ b/src/Sentry.Maui/Internal/SentryMauiStructuredLoggerProvider.cs @@ -5,7 +5,7 @@ namespace Sentry.Maui.Internal; -[ProviderAlias("SentryLogs")] +[ProviderAlias("Sentry")] internal sealed class SentryMauiStructuredLoggerProvider : SentryStructuredLoggerProvider { public SentryMauiStructuredLoggerProvider(IOptions options, IHub hub) diff --git a/src/Sentry.Maui/SentryMauiAppBuilderExtensions.cs b/src/Sentry.Maui/SentryMauiAppBuilderExtensions.cs index 9274cf5812..579c2b63e6 100644 --- a/src/Sentry.Maui/SentryMauiAppBuilderExtensions.cs +++ b/src/Sentry.Maui/SentryMauiAppBuilderExtensions.cs @@ -56,11 +56,10 @@ public static MauiAppBuilder UseSentry(this MauiAppBuilder builder, services.AddSingleton, SentryMauiOptionsSetup>(); services.AddSingleton(); - builder.Logging.AddFilter(static (string? categoryName, LogLevel logLevel) => - { - return categoryName is null - || categoryName != "Sentry.ISentryClient"; - }); + // Add a delegate rule in order to ignore Configuration like "appsettings.json" and "appsettings.{HostEnvironment}.json" + builder.Logging.AddFilter(_ => true); + // Add non-delegate rules in order to respect Configuration like "appsettings.json" and "appsettings.{HostEnvironment}.json" + builder.Logging.AddFilter("Sentry.ISentryClient", LogLevel.None); // Add default event binders services.AddSingleton(); diff --git a/test/Sentry.AspNetCore.Tests/SentryAspNetCoreLoggerProviderTests.cs b/test/Sentry.AspNetCore.Tests/SentryAspNetCoreLoggerProviderTests.cs new file mode 100644 index 0000000000..7dad3fdf71 --- /dev/null +++ b/test/Sentry.AspNetCore.Tests/SentryAspNetCoreLoggerProviderTests.cs @@ -0,0 +1,70 @@ +#nullable enable + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Sentry.Extensions.Logging; + +namespace Sentry.AspNetCore.Tests; + +public class SentryAspNetCoreLoggerProviderTests +{ + private class Fixture + { + public IOptions Options { get; } + public IHub Hub { get; } + public MockClock Clock { get; } + + public Fixture() + { + var loggingOptions = new SentryAspNetCoreOptions(); + + Options = Microsoft.Extensions.Options.Options.Create(loggingOptions); + Hub = Substitute.For(); + Clock = new MockClock(); + } + + public SentryAspNetCoreLoggerProvider GetSut() + { + return new SentryAspNetCoreLoggerProvider(Options.Value, Hub, Clock); + } + } + + private readonly Fixture _fixture = new(); + + [Fact] + public void Type_CustomAttributes_HasProviderAliasAttribute() + { + var type = typeof(SentryAspNetCoreLoggerProvider); + + type.GetCustomAttributes().Should() + .ContainSingle().Which + .Alias.Should().Be("Sentry"); + } + + [Fact] + public void Ctor_DependencyInjection_CanCreate() + { + using var services = new ServiceCollection() + .AddLogging() + .AddSingleton() + .AddSingleton(_fixture.Options) + .AddSingleton(_fixture.Hub) + .BuildServiceProvider(); + + var logger = services.GetRequiredService>(); + + logger.Should().BeOfType>(); + } + + [Fact] + public void CreateLogger_OfType() + { + var provider = _fixture.GetSut(); + + var logger = provider.CreateLogger("CategoryName"); + + logger.Should().BeOfType() + .Which.CategoryName.Should().Be("CategoryName"); + } +} diff --git a/test/Sentry.AspNetCore.Tests/SentryAspNetCoreStructuredLoggerProviderTests.cs b/test/Sentry.AspNetCore.Tests/SentryAspNetCoreStructuredLoggerProviderTests.cs index def969676a..f7fc58be9b 100644 --- a/test/Sentry.AspNetCore.Tests/SentryAspNetCoreStructuredLoggerProviderTests.cs +++ b/test/Sentry.AspNetCore.Tests/SentryAspNetCoreStructuredLoggerProviderTests.cs @@ -40,6 +40,16 @@ public SentryAspNetCoreStructuredLoggerProvider GetSut() private readonly Fixture _fixture = new(); + [Fact] + public void Type_CustomAttributes_HasProviderAliasAttribute() + { + var type = typeof(SentryAspNetCoreStructuredLoggerProvider); + + type.GetCustomAttributes().Should() + .ContainSingle().Which + .Alias.Should().Be("Sentry"); + } + [Fact] public void Ctor_DependencyInjection_CanCreate() { diff --git a/test/Sentry.AspNetCore.Tests/SentryWebHostBuilderExtensionsTests.cs b/test/Sentry.AspNetCore.Tests/SentryWebHostBuilderExtensionsTests.cs index 09a70d85b2..236e482fc6 100644 --- a/test/Sentry.AspNetCore.Tests/SentryWebHostBuilderExtensionsTests.cs +++ b/test/Sentry.AspNetCore.Tests/SentryWebHostBuilderExtensionsTests.cs @@ -1,6 +1,9 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Sentry.Extensions.Logging; #if NETCOREAPP3_1_OR_GREATER using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IWebHostEnvironment; @@ -74,4 +77,63 @@ public static IEnumerable ExpectedServices() new Action(c => Assert.Single(c, d => d.ImplementationType == typeof(SentryStartupFilter)))}; } + + [Fact] + public void UseSentry_Logging_AddLoggerProviders() + { +#if NET8_0 + var section = Substitute.For(); + section[Arg.Any()].Returns((string)null); + Configuration.GetSection("Sentry").Returns(section); +#endif + WebHostBuilder.UseSentry((SentryAspNetCoreOptions options) => + { + options.EnableLogs = true; + options.InitializeSdk = false; + }); + using var serviceProvider = Services.BuildServiceProvider(); + + var providers = serviceProvider.GetRequiredService>().ToArray(); + + providers.Should().HaveCount(2); + providers[0].Should().BeOfType(); + providers[1].Should().BeOfType(); + } + + [Fact] + public void UseSentry_Logging_AddLoggerFilterRules() + { + WebHostBuilder.UseSentry((SentryAspNetCoreOptions options) => + { + options.EnableLogs = true; + options.InitializeSdk = false; + }); + using var serviceProvider = Services.BuildServiceProvider(); + + var loggerFilterOptions = serviceProvider.GetRequiredService>().Value; + + loggerFilterOptions.Rules.Should().HaveCount(3); + var one = loggerFilterOptions.Rules[0]; + var two = loggerFilterOptions.Rules[1]; + var three = loggerFilterOptions.Rules[2]; + + one.ProviderName.Should().Be(typeof(SentryAspNetCoreLoggerProvider).FullName); + one.CategoryName.Should().BeNull(); + one.LogLevel.Should().BeNull(); + one.Filter.Should().NotBeNull(); + one.Filter!.Invoke(null, null, LogLevel.None).Should().BeTrue(); + one.Filter.Invoke("", "", LogLevel.None).Should().BeTrue(); + one.Filter.Invoke("type", "category", LogLevel.None).Should().BeTrue(); + one.Filter.Invoke(null, typeof(Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware).FullName, LogLevel.None).Should().BeFalse(); + + two.ProviderName.Should().Be(typeof(SentryAspNetCoreStructuredLoggerProvider).FullName); + two.CategoryName.Should().Be(typeof(ISentryClient).FullName); + two.LogLevel.Should().Be(LogLevel.None); + two.Filter.Should().BeNull(); + + three.ProviderName.Should().Be(typeof(SentryAspNetCoreStructuredLoggerProvider).FullName); + three.CategoryName.Should().Be(typeof(SentryMiddleware).FullName); + three.LogLevel.Should().Be(LogLevel.None); + three.Filter.Should().BeNull(); + } } diff --git a/test/Sentry.Extensions.Logging.Tests/LoggingBuilderExtensionsTests.cs b/test/Sentry.Extensions.Logging.Tests/LoggingBuilderExtensionsTests.cs new file mode 100644 index 0000000000..ab4cc48a26 --- /dev/null +++ b/test/Sentry.Extensions.Logging.Tests/LoggingBuilderExtensionsTests.cs @@ -0,0 +1,65 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Sentry.Extensions.Logging.Tests; + +public class LoggingBuilderExtensionsTests +{ + [Fact] + public void AddSentry_LoggingBuilder_AddLoggerProviders() + { + // Arrange + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging((ILoggingBuilder builder) => builder.AddSentry(options => + { + options.EnableLogs = true; + options.InitializeSdk = false; + })); + using var serviceProvider = serviceCollection.BuildServiceProvider(); + using var loggerFactory = serviceProvider.GetRequiredService(); + + // Act + var providers = serviceProvider.GetRequiredService>().ToArray(); + + // Assert + providers.Should().HaveCount(2); + providers[0].Should().BeOfType(); + providers[1].Should().BeOfType(); + } + + [Fact] + public void AddSentry_LoggingBuilder_AddLoggerFilterRules() + { + // Arrange + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging((ILoggingBuilder builder) => builder.AddSentry(options => + { + options.EnableLogs = true; + options.InitializeSdk = false; + })); + using var serviceProvider = serviceCollection.BuildServiceProvider(); + using var loggerFactory = serviceProvider.GetRequiredService(); + + // Act + var loggerFilterOptions = serviceProvider.GetRequiredService>().Value; + + // Assert + loggerFilterOptions.Rules.Should().HaveCount(2); + var one = loggerFilterOptions.Rules[0]; + var two = loggerFilterOptions.Rules[1]; + + one.ProviderName.Should().Be(typeof(SentryLoggerProvider).FullName); + one.CategoryName.Should().BeNull(); + one.LogLevel.Should().BeNull(); + one.Filter.Should().NotBeNull(); + one.Filter!.Invoke(null, null, LogLevel.None).Should().BeTrue(); + one.Filter.Invoke("", "", LogLevel.None).Should().BeTrue(); + one.Filter.Invoke("type", "category", LogLevel.None).Should().BeTrue(); + + two.ProviderName.Should().Be(typeof(SentryStructuredLoggerProvider).FullName); + two.CategoryName.Should().Be(typeof(ISentryClient).FullName); + two.LogLevel.Should().Be(LogLevel.None); + two.Filter.Should().BeNull(); + } +} diff --git a/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs b/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs index c16e5521ab..3c5559ccaf 100644 --- a/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs @@ -5,6 +5,8 @@ namespace Sentry.Extensions.Logging.Tests; public class LoggingTests { + private static readonly string CategoryName = "test_category"; + [SkippableTheory] [InlineData(LogLevel.Critical)] [InlineData(LogLevel.Error)] @@ -26,17 +28,19 @@ public void Log_CapturesEvent(LogLevel logLevel) serviceCollection.AddLogging(builder => builder.AddSentry(o => { o.Dsn = ValidDsn; - o.MinimumEventLevel = logLevel; o.MinimumBreadcrumbLevel = LogLevel.None; + o.MinimumEventLevel = logLevel; o.BackgroundWorker = worker; o.InitNativeSdks = false; + o.EnableLogs = false; })); + serviceCollection.Configure(options => options.AddFilter(CategoryName, LogLevel.None)); using var serviceProvider = serviceCollection.BuildServiceProvider(); using var loggerFactory = serviceProvider.GetRequiredService(); // Act const string message = "test message"; - var logger = loggerFactory.CreateLogger("test"); + var logger = loggerFactory.CreateLogger(CategoryName); logger.Log(logLevel, message); // Assert @@ -75,13 +79,15 @@ public void Log_AddsBreadcrumb(LogLevel logLevel) o.MinimumEventLevel = LogLevel.None; o.BackgroundWorker = worker; o.InitNativeSdks = false; + o.EnableLogs = false; })); + serviceCollection.Configure(options => options.AddFilter(CategoryName, LogLevel.None)); using var serviceProvider = serviceCollection.BuildServiceProvider(); using var loggerFactory = serviceProvider.GetRequiredService(); // Act const string message = "test message"; - var logger = loggerFactory.CreateLogger("test"); + var logger = loggerFactory.CreateLogger(CategoryName); logger.Log(logLevel, message); var hub = serviceProvider.GetRequiredService(); @@ -100,4 +106,52 @@ public void Log_AddsBreadcrumb(LogLevel logLevel) b.Message == message) != null)); } + + [SkippableTheory] + [InlineData(LogLevel.Critical)] + [InlineData(LogLevel.Error)] + [InlineData(LogLevel.Warning)] + [InlineData(LogLevel.Information)] + [InlineData(LogLevel.Debug)] + [InlineData(LogLevel.Trace)] + public void Log_CapturesStructuredLog(LogLevel logLevel) + { +#if __IOS__ + Skip.If(true, "Flaky on iOS"); +#endif + + // Arrange + var worker = Substitute.For(); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(builder => builder.AddSentry(o => + { + o.Dsn = ValidDsn; + o.MinimumBreadcrumbLevel = LogLevel.None; + o.MinimumEventLevel = LogLevel.None; + o.BackgroundWorker = worker; + o.InitNativeSdks = false; + o.EnableLogs = true; + })); + serviceCollection.Configure(options => options.AddFilter(CategoryName, logLevel)); + using var serviceProvider = serviceCollection.BuildServiceProvider(); + using var loggerFactory = serviceProvider.GetRequiredService(); + + // Act + const string message = "test message"; + var logger = loggerFactory.CreateLogger(CategoryName); + logger.Log(logLevel, message); + + var hub = serviceProvider.GetRequiredService(); + hub.Logger.Flush(); + + // Assert + worker.Received(1).EnqueueEnvelope( + Arg.Is(e => + e.Items + .Select(i => i.Payload).OfType() + .Select(i => i.Source).OfType() + .SingleOrDefault(log => log.Length == 1) + != null)); + } } diff --git a/test/Sentry.Extensions.Logging.Tests/SentryLoggerProviderTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryLoggerProviderTests.cs index 20b608b74b..db4bb02e73 100644 --- a/test/Sentry.Extensions.Logging.Tests/SentryLoggerProviderTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/SentryLoggerProviderTests.cs @@ -1,3 +1,5 @@ +using Microsoft.Extensions.Logging; + namespace Sentry.Extensions.Logging.Tests; public class SentryLoggerProviderTests @@ -11,6 +13,16 @@ private class Fixture private readonly Fixture _fixture = new(); + [Fact] + public void Type_CustomAttributes_HasProviderAliasAttribute() + { + var type = typeof(SentryLoggerProvider); + + type.GetCustomAttributes().Should() + .ContainSingle().Which + .Alias.Should().Be("Sentry"); + } + [Fact] public void CreateLogger_LoggerType_SentryLogger() { diff --git a/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerProviderTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerProviderTests.cs index 4d0afafcc0..2342e43e06 100644 --- a/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerProviderTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/SentryStructuredLoggerProviderTests.cs @@ -40,6 +40,16 @@ public SentryStructuredLoggerProvider GetSut() private readonly Fixture _fixture = new(); + [Fact] + public void Type_CustomAttributes_HasProviderAliasAttribute() + { + var type = typeof(SentryStructuredLoggerProvider); + + type.GetCustomAttributes().Should() + .ContainSingle().Which + .Alias.Should().Be("Sentry"); + } + [Fact] public void Ctor_DependencyInjection_CanCreate() { diff --git a/test/Sentry.Maui.Tests/Internal/SentryMauiLoggerProviderTests.cs b/test/Sentry.Maui.Tests/Internal/SentryMauiLoggerProviderTests.cs new file mode 100644 index 0000000000..7548941a35 --- /dev/null +++ b/test/Sentry.Maui.Tests/Internal/SentryMauiLoggerProviderTests.cs @@ -0,0 +1,70 @@ +#nullable enable + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Sentry.Extensions.Logging; +using Sentry.Maui.Internal; + +namespace Sentry.Maui.Tests.Internal; + +public class SentryMauiLoggerProviderTests +{ + private class Fixture + { + public IOptions Options { get; } + public IHub Hub { get; } + public MockClock Clock { get; } + + public Fixture() + { + var loggingOptions = new SentryMauiOptions(); + + Options = Microsoft.Extensions.Options.Options.Create(loggingOptions); + Hub = Substitute.For(); + Clock = new MockClock(); + } + + public SentryMauiLoggerProvider GetSut() + { + return new SentryMauiLoggerProvider(Options.Value, Hub, Clock); + } + } + + private readonly Fixture _fixture = new(); + + [Fact] + public void Type_CustomAttributes_HasProviderAliasAttribute() + { + var type = typeof(SentryMauiLoggerProvider); + + type.GetCustomAttributes().Should() + .ContainSingle().Which + .Alias.Should().Be("Sentry"); + } + + [Fact] + public void Ctor_DependencyInjection_CanCreate() + { + using var services = new ServiceCollection() + .AddLogging() + .AddSingleton() + .AddSingleton(_fixture.Options) + .AddSingleton(_fixture.Hub) + .BuildServiceProvider(); + + var logger = services.GetRequiredService>(); + + logger.Should().BeOfType>(); + } + + [Fact] + public void CreateLogger_OfType() + { + var provider = _fixture.GetSut(); + + var logger = provider.CreateLogger("CategoryName"); + + logger.Should().BeOfType() + .Which.CategoryName.Should().Be("CategoryName"); + } +} diff --git a/test/Sentry.Maui.Tests/Internal/SentryMauiStructuredLoggerProviderTests.cs b/test/Sentry.Maui.Tests/Internal/SentryMauiStructuredLoggerProviderTests.cs index 5399ff6749..27eb41fd21 100644 --- a/test/Sentry.Maui.Tests/Internal/SentryMauiStructuredLoggerProviderTests.cs +++ b/test/Sentry.Maui.Tests/Internal/SentryMauiStructuredLoggerProviderTests.cs @@ -40,6 +40,16 @@ public SentryMauiStructuredLoggerProvider GetSut() private readonly Fixture _fixture = new(); + [Fact] + public void Type_CustomAttributes_HasProviderAliasAttribute() + { + var type = typeof(SentryMauiStructuredLoggerProvider); + + type.GetCustomAttributes().Should() + .ContainSingle().Which + .Alias.Should().Be("Sentry"); + } + [Fact] public void Ctor_DependencyInjection_CanCreate() { diff --git a/test/Sentry.Maui.Tests/SentryMauiAppBuilderExtensionsTests.cs b/test/Sentry.Maui.Tests/SentryMauiAppBuilderExtensionsTests.cs index c464b2ec53..ae307a62d0 100644 --- a/test/Sentry.Maui.Tests/SentryMauiAppBuilderExtensionsTests.cs +++ b/test/Sentry.Maui.Tests/SentryMauiAppBuilderExtensionsTests.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Sentry.Internal.Http; using Sentry.Maui.Internal; @@ -333,4 +334,61 @@ public void UseSentry_DebugTrue_CustomDiagnosticsLogger() // Assert options.DiagnosticLogger.Should().BeOfType(); } + + [Fact] + public void UseSentry_Logging_AddLoggerProviders() + { + // Arrange + var builder = _fixture.Builder; + + // Act + builder.UseSentry((SentryMauiOptions options) => + { + options.EnableLogs = true; + options.InitializeSdk = false; + }); + + using var serviceProvider = builder.Services.BuildServiceProvider(); + var providers = serviceProvider.GetRequiredService>().ToArray(); + + // Assert + providers.Should().HaveCount(2); + providers[0].Should().BeOfType(); + providers[1].Should().BeOfType(); + } + + [Fact] + public void UseSentry_Logging_AddLoggerFilterRules() + { + // Arrange + var builder = _fixture.Builder; + + // Act + builder.UseSentry((SentryMauiOptions options) => + { + options.EnableLogs = true; + options.InitializeSdk = false; + }); + + using var serviceProvider = builder.Services.BuildServiceProvider(); + var loggerFilterOptions = serviceProvider.GetRequiredService>().Value; + + // Assert + loggerFilterOptions.Rules.Should().HaveCount(2); + var one = loggerFilterOptions.Rules[0]; + var two = loggerFilterOptions.Rules[1]; + + one.ProviderName.Should().Be(typeof(SentryMauiLoggerProvider).FullName); + one.CategoryName.Should().BeNull(); + one.LogLevel.Should().BeNull(); + one.Filter.Should().NotBeNull(); + one.Filter!.Invoke(null, null, LogLevel.None).Should().BeTrue(); + one.Filter.Invoke("", "", LogLevel.None).Should().BeTrue(); + one.Filter.Invoke("type", "category", LogLevel.None).Should().BeTrue(); + + two.ProviderName.Should().Be(typeof(SentryMauiStructuredLoggerProvider).FullName); + two.CategoryName.Should().Be(typeof(ISentryClient).FullName); + two.LogLevel.Should().Be(LogLevel.None); + two.Filter.Should().BeNull(); + } } From 8bc1b0216580747b85ac386386b8166f86d339a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Tue, 25 Nov 2025 15:52:47 +0100 Subject: [PATCH 06/18] ref!: make all SentryLoggerProviders non-public --- .../SentryAspNetCoreLoggerProvider.cs | 4 ++-- src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs | 4 ++-- .../SentryAspNetCoreStructuredLoggerProvider.cs | 2 +- src/Sentry.Extensions.Logging/SentryLoggerProvider.cs | 4 ++-- .../SentryStructuredLoggerProvider.cs | 2 +- src/Sentry.Maui/Internal/SentryMauiLoggerProvider.cs | 3 +++ .../Internal/SentryMauiStructuredLoggerProvider.cs | 3 +++ .../ApiApprovalTests.Run.DotNet10_0.verified.txt | 10 ---------- .../ApiApprovalTests.Run.DotNet8_0.verified.txt | 10 ---------- .../ApiApprovalTests.Run.DotNet9_0.verified.txt | 10 ---------- .../ApiApprovalTests.Run.DotNet10_0.verified.txt | 7 ------- .../ApiApprovalTests.Run.DotNet8_0.verified.txt | 7 ------- .../ApiApprovalTests.Run.DotNet9_0.verified.txt | 7 ------- .../ApiApprovalTests.Run.Net4_8.verified.txt | 7 ------- 14 files changed, 14 insertions(+), 66 deletions(-) diff --git a/src/Sentry.AspNetCore/SentryAspNetCoreLoggerProvider.cs b/src/Sentry.AspNetCore/SentryAspNetCoreLoggerProvider.cs index 12a27bc009..5ad52c8e9b 100644 --- a/src/Sentry.AspNetCore/SentryAspNetCoreLoggerProvider.cs +++ b/src/Sentry.AspNetCore/SentryAspNetCoreLoggerProvider.cs @@ -6,10 +6,10 @@ namespace Sentry.AspNetCore; /// -/// Logger provider for Sentry. +/// Sentry Logger Provider for and . /// [ProviderAlias("Sentry")] -public class SentryAspNetCoreLoggerProvider : SentryLoggerProvider +internal sealed class SentryAspNetCoreLoggerProvider : SentryLoggerProvider { /// /// Creates a new instance of diff --git a/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs b/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs index d5af7f3e3a..3f428f58f3 100644 --- a/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs +++ b/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs @@ -9,7 +9,7 @@ namespace Sentry.AspNetCore; /// Sets up ASP.NET Core option for Sentry. /// #if NETSTANDARD2_0 -public class SentryAspNetCoreOptionsSetup : ConfigureFromConfigurationOptions +internal sealed class SentryAspNetCoreOptionsSetup : ConfigureFromConfigurationOptions { /// /// Creates a new instance of . @@ -32,7 +32,7 @@ public override void Configure(SentryAspNetCoreOptions options) } #else -public class SentryAspNetCoreOptionsSetup : IConfigureOptions +internal sealed class SentryAspNetCoreOptionsSetup : IConfigureOptions { private readonly IConfiguration _config; diff --git a/src/Sentry.AspNetCore/SentryAspNetCoreStructuredLoggerProvider.cs b/src/Sentry.AspNetCore/SentryAspNetCoreStructuredLoggerProvider.cs index b2096d8bef..42f7cd8cc3 100644 --- a/src/Sentry.AspNetCore/SentryAspNetCoreStructuredLoggerProvider.cs +++ b/src/Sentry.AspNetCore/SentryAspNetCoreStructuredLoggerProvider.cs @@ -6,7 +6,7 @@ namespace Sentry.AspNetCore; /// -/// Structured Logger Provider for Sentry. +/// Sentry Logger Provider for . /// [ProviderAlias("Sentry")] internal sealed class SentryAspNetCoreStructuredLoggerProvider : SentryStructuredLoggerProvider diff --git a/src/Sentry.Extensions.Logging/SentryLoggerProvider.cs b/src/Sentry.Extensions.Logging/SentryLoggerProvider.cs index 454f070dd8..034e7b4694 100644 --- a/src/Sentry.Extensions.Logging/SentryLoggerProvider.cs +++ b/src/Sentry.Extensions.Logging/SentryLoggerProvider.cs @@ -6,10 +6,10 @@ namespace Sentry.Extensions.Logging; /// -/// Sentry Logger Provider. +/// Sentry Logger Provider for and . /// [ProviderAlias("Sentry")] -public class SentryLoggerProvider : ILoggerProvider +internal class SentryLoggerProvider : ILoggerProvider { private readonly ISystemClock _clock; private readonly SentryLoggingOptions _options; diff --git a/src/Sentry.Extensions.Logging/SentryStructuredLoggerProvider.cs b/src/Sentry.Extensions.Logging/SentryStructuredLoggerProvider.cs index 198147fd72..bf74a36da0 100644 --- a/src/Sentry.Extensions.Logging/SentryStructuredLoggerProvider.cs +++ b/src/Sentry.Extensions.Logging/SentryStructuredLoggerProvider.cs @@ -5,7 +5,7 @@ namespace Sentry.Extensions.Logging; /// -/// Sentry Structured Logger Provider. +/// Sentry Logger Provider for . /// [ProviderAlias("Sentry")] internal class SentryStructuredLoggerProvider : ILoggerProvider diff --git a/src/Sentry.Maui/Internal/SentryMauiLoggerProvider.cs b/src/Sentry.Maui/Internal/SentryMauiLoggerProvider.cs index ef1d1af9e3..dddd59bae2 100644 --- a/src/Sentry.Maui/Internal/SentryMauiLoggerProvider.cs +++ b/src/Sentry.Maui/Internal/SentryMauiLoggerProvider.cs @@ -5,6 +5,9 @@ namespace Sentry.Maui.Internal; +/// +/// Sentry Logger Provider for and . +/// [ProviderAlias("Sentry")] internal sealed class SentryMauiLoggerProvider : SentryLoggerProvider { diff --git a/src/Sentry.Maui/Internal/SentryMauiStructuredLoggerProvider.cs b/src/Sentry.Maui/Internal/SentryMauiStructuredLoggerProvider.cs index aa9cf8ca3e..a72ffafc46 100644 --- a/src/Sentry.Maui/Internal/SentryMauiStructuredLoggerProvider.cs +++ b/src/Sentry.Maui/Internal/SentryMauiStructuredLoggerProvider.cs @@ -5,6 +5,9 @@ namespace Sentry.Maui.Internal; +/// +/// Sentry Logger Provider for . +/// [ProviderAlias("Sentry")] internal sealed class SentryMauiStructuredLoggerProvider : SentryStructuredLoggerProvider { diff --git a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt index 4ca83a4f8f..7712a7f158 100644 --- a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt +++ b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt @@ -39,11 +39,6 @@ namespace Sentry.AspNetCore public static string? TryGetHttpPath(this Sentry.TransactionSamplingContext samplingContext) { } public static string? TryGetHttpRoute(this Sentry.TransactionSamplingContext samplingContext) { } } - [Microsoft.Extensions.Logging.ProviderAlias("Sentry")] - public class SentryAspNetCoreLoggerProvider : Sentry.Extensions.Logging.SentryLoggerProvider - { - public SentryAspNetCoreLoggerProvider(Microsoft.Extensions.Options.IOptions options, Sentry.IHub hub) { } - } public class SentryAspNetCoreOptions : Sentry.Extensions.Logging.SentryLoggingOptions { public SentryAspNetCoreOptions() { } @@ -55,11 +50,6 @@ namespace Sentry.AspNetCore public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; } public Sentry.AspNetCore.TransactionNameProvider? TransactionNameProvider { get; set; } } - public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.IConfigureOptions - { - public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration) { } - public void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { } - } public static class SentryBuilderExtensions { public static Sentry.AspNetCore.ISentryBuilder AddSentryOptions(this Sentry.AspNetCore.ISentryBuilder builder, System.Action? configureOptions) { } diff --git a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index 4ca83a4f8f..7712a7f158 100644 --- a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt +++ b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -39,11 +39,6 @@ namespace Sentry.AspNetCore public static string? TryGetHttpPath(this Sentry.TransactionSamplingContext samplingContext) { } public static string? TryGetHttpRoute(this Sentry.TransactionSamplingContext samplingContext) { } } - [Microsoft.Extensions.Logging.ProviderAlias("Sentry")] - public class SentryAspNetCoreLoggerProvider : Sentry.Extensions.Logging.SentryLoggerProvider - { - public SentryAspNetCoreLoggerProvider(Microsoft.Extensions.Options.IOptions options, Sentry.IHub hub) { } - } public class SentryAspNetCoreOptions : Sentry.Extensions.Logging.SentryLoggingOptions { public SentryAspNetCoreOptions() { } @@ -55,11 +50,6 @@ namespace Sentry.AspNetCore public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; } public Sentry.AspNetCore.TransactionNameProvider? TransactionNameProvider { get; set; } } - public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.IConfigureOptions - { - public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration) { } - public void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { } - } public static class SentryBuilderExtensions { public static Sentry.AspNetCore.ISentryBuilder AddSentryOptions(this Sentry.AspNetCore.ISentryBuilder builder, System.Action? configureOptions) { } diff --git a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt index 4ca83a4f8f..7712a7f158 100644 --- a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt +++ b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt @@ -39,11 +39,6 @@ namespace Sentry.AspNetCore public static string? TryGetHttpPath(this Sentry.TransactionSamplingContext samplingContext) { } public static string? TryGetHttpRoute(this Sentry.TransactionSamplingContext samplingContext) { } } - [Microsoft.Extensions.Logging.ProviderAlias("Sentry")] - public class SentryAspNetCoreLoggerProvider : Sentry.Extensions.Logging.SentryLoggerProvider - { - public SentryAspNetCoreLoggerProvider(Microsoft.Extensions.Options.IOptions options, Sentry.IHub hub) { } - } public class SentryAspNetCoreOptions : Sentry.Extensions.Logging.SentryLoggingOptions { public SentryAspNetCoreOptions() { } @@ -55,11 +50,6 @@ namespace Sentry.AspNetCore public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; } public Sentry.AspNetCore.TransactionNameProvider? TransactionNameProvider { get; set; } } - public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.IConfigureOptions - { - public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration) { } - public void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { } - } public static class SentryBuilderExtensions { public static Sentry.AspNetCore.ISentryBuilder AddSentryOptions(this Sentry.AspNetCore.ISentryBuilder builder, System.Action? configureOptions) { } diff --git a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt index b438b0af45..8650a342f4 100644 --- a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt +++ b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt @@ -28,13 +28,6 @@ namespace Sentry.Extensions.Logging public bool IsEnabled(Sentry.SentryLevel level) { } public void Log(Sentry.SentryLevel logLevel, string message, System.Exception? exception = null, params object?[] args) { } } - [Microsoft.Extensions.Logging.ProviderAlias("Sentry")] - public class SentryLoggerProvider : Microsoft.Extensions.Logging.ILoggerProvider, System.IDisposable - { - public SentryLoggerProvider(Microsoft.Extensions.Options.IOptions options, Sentry.IHub hub) { } - public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) { } - public void Dispose() { } - } public class SentryLoggingOptions : Sentry.SentryOptions { public SentryLoggingOptions() { } diff --git a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index b438b0af45..8650a342f4 100644 --- a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt +++ b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -28,13 +28,6 @@ namespace Sentry.Extensions.Logging public bool IsEnabled(Sentry.SentryLevel level) { } public void Log(Sentry.SentryLevel logLevel, string message, System.Exception? exception = null, params object?[] args) { } } - [Microsoft.Extensions.Logging.ProviderAlias("Sentry")] - public class SentryLoggerProvider : Microsoft.Extensions.Logging.ILoggerProvider, System.IDisposable - { - public SentryLoggerProvider(Microsoft.Extensions.Options.IOptions options, Sentry.IHub hub) { } - public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) { } - public void Dispose() { } - } public class SentryLoggingOptions : Sentry.SentryOptions { public SentryLoggingOptions() { } diff --git a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt index b438b0af45..8650a342f4 100644 --- a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt +++ b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt @@ -28,13 +28,6 @@ namespace Sentry.Extensions.Logging public bool IsEnabled(Sentry.SentryLevel level) { } public void Log(Sentry.SentryLevel logLevel, string message, System.Exception? exception = null, params object?[] args) { } } - [Microsoft.Extensions.Logging.ProviderAlias("Sentry")] - public class SentryLoggerProvider : Microsoft.Extensions.Logging.ILoggerProvider, System.IDisposable - { - public SentryLoggerProvider(Microsoft.Extensions.Options.IOptions options, Sentry.IHub hub) { } - public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) { } - public void Dispose() { } - } public class SentryLoggingOptions : Sentry.SentryOptions { public SentryLoggingOptions() { } diff --git a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index b438b0af45..8650a342f4 100644 --- a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -28,13 +28,6 @@ namespace Sentry.Extensions.Logging public bool IsEnabled(Sentry.SentryLevel level) { } public void Log(Sentry.SentryLevel logLevel, string message, System.Exception? exception = null, params object?[] args) { } } - [Microsoft.Extensions.Logging.ProviderAlias("Sentry")] - public class SentryLoggerProvider : Microsoft.Extensions.Logging.ILoggerProvider, System.IDisposable - { - public SentryLoggerProvider(Microsoft.Extensions.Options.IOptions options, Sentry.IHub hub) { } - public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) { } - public void Dispose() { } - } public class SentryLoggingOptions : Sentry.SentryOptions { public SentryLoggingOptions() { } From bc86bb70f79e74a851e9a5c3bc191ae62534650b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:55:44 +0100 Subject: [PATCH 07/18] example: enable Logs for Generic-Host sample --- samples/Sentry.Samples.GenericHost/SampleHostedService.cs | 2 ++ samples/Sentry.Samples.GenericHost/appsettings.json | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/samples/Sentry.Samples.GenericHost/SampleHostedService.cs b/samples/Sentry.Samples.GenericHost/SampleHostedService.cs index c99f00d7dc..aeb8149460 100644 --- a/samples/Sentry.Samples.GenericHost/SampleHostedService.cs +++ b/samples/Sentry.Samples.GenericHost/SampleHostedService.cs @@ -7,6 +7,8 @@ internal class SampleHostedService(IHub hub, ILogger logger { public Task StartAsync(CancellationToken cancellationToken) { + // Configure structured logging via appsettings.json (Logging:Sentry:LogLevel:) + logger.LogTrace("LogLevel.Trace is not configured to be sent as structured log"); // Logging integration by default keeps informational logs as Breadcrumb logger.LogInformation("Starting sample hosted service. This goes as a breadcrumb"); // You can also add breadcrumb directly through Sentry.Hub: diff --git a/samples/Sentry.Samples.GenericHost/appsettings.json b/samples/Sentry.Samples.GenericHost/appsettings.json index 256a4dc806..dbd12c4887 100644 --- a/samples/Sentry.Samples.GenericHost/appsettings.json +++ b/samples/Sentry.Samples.GenericHost/appsettings.json @@ -2,12 +2,18 @@ "Logging": { "LogLevel": { "Default": "Trace" + }, + "Sentry": { + "LogLevel": { + "Default": "Information" // Configure structured logs + } } }, "Sentry": { //"Dsn": "TODO: Configure your DSN here and uncomment this line", "MinimumBreadcrumbLevel": "Debug", "MinimumEventLevel": "Warning", - "SendDefaultPii": true // Send user name and machine name + "SendDefaultPii": true, // Send user name and machine name + "EnableLogs": true // Send structured logs } } From c65dcb11aef976e39422a62997c8885d4f695b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:56:11 +0100 Subject: [PATCH 08/18] feat: enable Logs for Google-Cloud-Functions --- .../Function.cs | 1 + .../appsettings.json | 13 +++- .../SentryStartup.cs | 13 +++- .../SentryStartupTests.cs | 62 ++++++++++++++++++- 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs b/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs index 7c151d6ee8..3abcd098e4 100644 --- a/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs +++ b/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs @@ -16,6 +16,7 @@ public class Function : IHttpFunction public Task HandleAsync(HttpContext context) { + _logger.LogTrace("LogLevel.Trace is not configured to be sent as structured log"); _logger.LogInformation("Useful info that is added to the breadcrumb list."); throw new Exception("Bad function"); } diff --git a/samples/Sentry.Samples.Google.Cloud.Functions/appsettings.json b/samples/Sentry.Samples.Google.Cloud.Functions/appsettings.json index 0f384e48c8..b572cc23fa 100644 --- a/samples/Sentry.Samples.Google.Cloud.Functions/appsettings.json +++ b/samples/Sentry.Samples.Google.Cloud.Functions/appsettings.json @@ -1,8 +1,19 @@ { + "Logging": { + "LogLevel": { + "Default": "Debug" + }, + "Sentry": { + "LogLevel": { + "Default": "Information" + } + } + }, "Sentry": { //"Dsn": "TODO: Configure your DSN here and uncomment this line", "MaxRequestBodySize": "Always", "SendDefaultPii": true, - "EnableTracing": true + "EnableTracing": true, + "EnableLogs" : true } } diff --git a/src/Sentry.Google.Cloud.Functions/SentryStartup.cs b/src/Sentry.Google.Cloud.Functions/SentryStartup.cs index 73cae34ce8..ad7e485043 100644 --- a/src/Sentry.Google.Cloud.Functions/SentryStartup.cs +++ b/src/Sentry.Google.Cloud.Functions/SentryStartup.cs @@ -57,10 +57,17 @@ public override void ConfigureLogging(WebHostBuilderContext context, ILoggingBui logging.Services.AddSingleton, SentryAspNetCoreOptionsSetup>(); logging.Services.AddSingleton(); + logging.Services.AddSingleton(); - logging.AddFilter( - "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware", - LogLevel.None); + // Add a delegate rule in order to ignore Configuration like "appsettings.json" and "appsettings.{HostEnvironment}.json" + logging.AddFilter(static (string? categoryName, LogLevel logLevel) => + { + return categoryName is null + || categoryName != "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware"; + }); + // Add non-delegate rules in order to respect Configuration like "appsettings.json" and "appsettings.{HostEnvironment}.json" + logging.AddFilter("Sentry.ISentryClient", LogLevel.None); + logging.AddFilter("Sentry.AspNetCore.SentryMiddleware", LogLevel.None); logging.Services.AddSentry(); } diff --git a/test/Sentry.Google.Cloud.Functions.Tests/SentryStartupTests.cs b/test/Sentry.Google.Cloud.Functions.Tests/SentryStartupTests.cs index 8006f81b5a..2057d17ffc 100644 --- a/test/Sentry.Google.Cloud.Functions.Tests/SentryStartupTests.cs +++ b/test/Sentry.Google.Cloud.Functions.Tests/SentryStartupTests.cs @@ -96,7 +96,7 @@ public void ConfigureLogging_SentryAspNetCoreOptions_FlushOnCompletedRequestTrue } [Theory, MemberData(nameof(ExpectedServices))] - public void UseSentry_Parameterless_ServicesRegistered(Action assert) + public void ConfigureLogging_Parameterless_ServicesRegistered(Action assert) { var sut = new SentryStartup(); sut.ConfigureLogging(WebHostBuilderContext, LoggingBuilder); @@ -121,4 +121,64 @@ public static IEnumerable ExpectedServices() new Action(c => Assert.Single(c, d => d.ImplementationType == typeof(AspNetCoreEventProcessor)))}; } + + [Fact] + public void ConfigureLogging_Logging_AddLoggerProviders() + { + LoggingBuilder.Services.Configure(options => + { + options.EnableLogs = true; + options.InitializeSdk = false; + }); + + var sut = new SentryStartup(); + sut.ConfigureLogging(WebHostBuilderContext, LoggingBuilder); + + using var serviceProvider = LoggingBuilder.Services.BuildServiceProvider(); + var providers = serviceProvider.GetRequiredService>().ToArray(); + + providers.Should().HaveCount(2); + providers[0].Should().BeOfType(); + providers[1].Should().BeOfType(); + } + + [Fact] + public void ConfigureLogging_Logging_AddLoggerFilterRules() + { + LoggingBuilder.Services.Configure(options => + { + options.EnableLogs = true; + options.InitializeSdk = false; + }); + + var sut = new SentryStartup(); + sut.ConfigureLogging(WebHostBuilderContext, LoggingBuilder); + + using var serviceProvider = LoggingBuilder.Services.BuildServiceProvider(); + var loggerFilterOptions = serviceProvider.GetRequiredService>().Value; + + loggerFilterOptions.Rules.Should().HaveCount(3); + var one = loggerFilterOptions.Rules[0]; + var two = loggerFilterOptions.Rules[1]; + var three = loggerFilterOptions.Rules[2]; + + one.ProviderName.Should().Be(typeof(SentryAspNetCoreLoggerProvider).FullName); + one.CategoryName.Should().BeNull(); + one.LogLevel.Should().BeNull(); + one.Filter.Should().NotBeNull(); + one.Filter!.Invoke(null, null, LogLevel.None).Should().BeTrue(); + one.Filter.Invoke("", "", LogLevel.None).Should().BeTrue(); + one.Filter.Invoke("type", "category", LogLevel.None).Should().BeTrue(); + one.Filter.Invoke(null, typeof(Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware).FullName, LogLevel.None).Should().BeFalse(); + + two.ProviderName.Should().Be(typeof(SentryAspNetCoreStructuredLoggerProvider).FullName); + two.CategoryName.Should().Be(typeof(ISentryClient).FullName); + two.LogLevel.Should().Be(LogLevel.None); + two.Filter.Should().BeNull(); + + three.ProviderName.Should().Be(typeof(SentryAspNetCoreStructuredLoggerProvider).FullName); + three.CategoryName.Should().Be(typeof(SentryMiddleware).FullName); + three.LogLevel.Should().Be(LogLevel.None); + three.Filter.Should().BeNull(); + } } From fb91a5b963aace5da21beb31e0d7aa169ff021fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:56:35 +0100 Subject: [PATCH 09/18] ref: seal internal Configure-Options --- src/Sentry.Extensions.Logging/SentryLoggingOptionsSetup.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Sentry.Extensions.Logging/SentryLoggingOptionsSetup.cs b/src/Sentry.Extensions.Logging/SentryLoggingOptionsSetup.cs index b220d936b5..401d3a864a 100644 --- a/src/Sentry.Extensions.Logging/SentryLoggingOptionsSetup.cs +++ b/src/Sentry.Extensions.Logging/SentryLoggingOptionsSetup.cs @@ -5,7 +5,7 @@ namespace Sentry.Extensions.Logging; -internal class SentryLoggingOptionsSetup : IConfigureOptions +internal sealed class SentryLoggingOptionsSetup : IConfigureOptions { private readonly IConfiguration _config; @@ -30,7 +30,7 @@ public void Configure(SentryLoggingOptions options) namespace Sentry.Extensions.Logging; -internal class SentryLoggingOptionsSetup : ConfigureFromConfigurationOptions +internal sealed class SentryLoggingOptionsSetup : ConfigureFromConfigurationOptions { public SentryLoggingOptionsSetup( ILoggerProviderConfiguration providerConfiguration) From 26d56fa5df30d3b556f16149af83a556f77707c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Tue, 25 Nov 2025 17:20:59 +0100 Subject: [PATCH 10/18] docs: add CHANGELOG entry --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e6e15a860..95a453b25d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,19 @@ ### Features - Added a new SDK `Sentry.Extensions.AI` which allows LLM usage instrumentation via `Microsoft.Extensions.AI` ([#4657](https://github.com/getsentry/sentry-dotnet/pull/4657)) +- Add support for _Structured Logs_ in `Sentry.Google.Cloud.Functions` ([#4700](https://github.com/getsentry/sentry-dotnet/pull/4700)) ### Fixes - Captured [Http Client Errors](https://docs.sentry.io/platforms/dotnet/guides/aspnet/configuration/http-client-errors/) on .NET 5+ now include a full stack trace in order to improve Issue grouping ([#4724](https://github.com/getsentry/sentry-dotnet/pull/4724)) - Sentry Tracing middleware crashed ASP.NET Core in .NET 10 in 6.0.0-rc.1 and earlier ([#4747](https://github.com/getsentry/sentry-dotnet/pull/4747)) - Avoid appending `/NODEFAULTLIB:MSVCRT` to NativeAOT linker arguments on Windows when targetting non-Windows platforms (Android, Browser) ([#4760](https://github.com/getsentry/sentry-dotnet/pull/4760)) +- Minimum Log-Level for _Structured Logs_, _Breadcrumbs_ and _Events_ in all Logging-Integrations ([#4700](https://github.com/getsentry/sentry-dotnet/pull/4700)) + - for `Sentry.Extensions.Logging`, `Sentry.AspNetCore`, `Sentry.Maui` and `Sentry.Google.Cloud.Functions` + - the Logger-Provider for _Breadcrumbs_ and _Events_ ignores Logging-Configuration (e.g. via `appsettings.json`) + - use the intended `SentryLoggingOptions.MinimumBreadcrumbLevel`, `SentryLoggingOptions.MinimumEventLevel`, or add filter functions via `SentryLoggingOptionsExtensions.AddLogEntryFilter` + - the Logger-Provider for _Structured Logs_ respects Logging-Configuration (e.g. via `appsettings.json`) + - when enabled by `SentryOptions.EnableLogs` ### Dependencies From 0b56dac7151ff305a59c491a950960b5a0779e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Tue, 25 Nov 2025 17:31:40 +0100 Subject: [PATCH 11/18] docs: add CHANGELOG entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95a453b25d..520f9a4b53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +### BREAKING CHANGES + +- Remove `SentryLoggingOptions.ExperimentalLogging.MinimumLogLevel`. _Structured Logs_ can now be configured via the `"Sentry"` logging provider (e.g. in `appsettings.json` and `appsettings.{HostEnvironment}.json`) ([#4700](https://github.com/getsentry/sentry-dotnet/pull/4700)) +- All logging provider types are _internal_ now in order to ensure configuration as intended ([#4700](https://github.com/getsentry/sentry-dotnet/pull/4700)) + ### Features - Added a new SDK `Sentry.Extensions.AI` which allows LLM usage instrumentation via `Microsoft.Extensions.AI` ([#4657](https://github.com/getsentry/sentry-dotnet/pull/4657)) From 467898fac9bbea3f41865fd4993fdb69b1418741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Wed, 26 Nov 2025 15:01:29 +0100 Subject: [PATCH 12/18] Update CHANGELOG.md --- CHANGELOG.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1232fdd58..c0810fff5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 6.0.0-rc.2 +## Unreleased ### BREAKING CHANGES @@ -9,14 +9,10 @@ ### Features -- Added a new SDK `Sentry.Extensions.AI` which allows LLM usage instrumentation via `Microsoft.Extensions.AI` ([#4657](https://github.com/getsentry/sentry-dotnet/pull/4657)) - Add support for _Structured Logs_ in `Sentry.Google.Cloud.Functions` ([#4700](https://github.com/getsentry/sentry-dotnet/pull/4700)) ### Fixes -- Captured [Http Client Errors](https://docs.sentry.io/platforms/dotnet/guides/aspnet/configuration/http-client-errors/) on .NET 5+ now include a full stack trace in order to improve Issue grouping ([#4724](https://github.com/getsentry/sentry-dotnet/pull/4724)) -- Sentry Tracing middleware crashed ASP.NET Core in .NET 10 in 6.0.0-rc.1 and earlier ([#4747](https://github.com/getsentry/sentry-dotnet/pull/4747)) -- Avoid appending `/NODEFAULTLIB:MSVCRT` to NativeAOT linker arguments on Windows when targetting non-Windows platforms (Android, Browser) ([#4760](https://github.com/getsentry/sentry-dotnet/pull/4760)) - Minimum Log-Level for _Structured Logs_, _Breadcrumbs_ and _Events_ in all Logging-Integrations ([#4700](https://github.com/getsentry/sentry-dotnet/pull/4700)) - for `Sentry.Extensions.Logging`, `Sentry.AspNetCore`, `Sentry.Maui` and `Sentry.Google.Cloud.Functions` - the Logger-Provider for _Breadcrumbs_ and _Events_ ignores Logging-Configuration (e.g. via `appsettings.json`) @@ -24,6 +20,18 @@ - the Logger-Provider for _Structured Logs_ respects Logging-Configuration (e.g. via `appsettings.json`) - when enabled by `SentryOptions.EnableLogs` +## 6.0.0-rc.2 + +### Features + +- Added a new SDK `Sentry.Extensions.AI` which allows LLM usage instrumentation via `Microsoft.Extensions.AI` ([#4657](https://github.com/getsentry/sentry-dotnet/pull/4657)) + +### Fixes + +- Captured [Http Client Errors](https://docs.sentry.io/platforms/dotnet/guides/aspnet/configuration/http-client-errors/) on .NET 5+ now include a full stack trace in order to improve Issue grouping ([#4724](https://github.com/getsentry/sentry-dotnet/pull/4724)) +- Sentry Tracing middleware crashed ASP.NET Core in .NET 10 in 6.0.0-rc.1 and earlier ([#4747](https://github.com/getsentry/sentry-dotnet/pull/4747)) +- Avoid appending `/NODEFAULTLIB:MSVCRT` to NativeAOT linker arguments on Windows when targetting non-Windows platforms (Android, Browser) ([#4760](https://github.com/getsentry/sentry-dotnet/pull/4760)) + ### Dependencies - Bump Java SDK from v8.24.0 to v8.26.0 ([#4728](https://github.com/getsentry/sentry-dotnet/pull/4728)) From c5012cd8b59be58066ad4e3e678937309fcce703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:25:38 +0100 Subject: [PATCH 13/18] test: add Configure-Logging test --- .../LoggingTests.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs b/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs index 3c5559ccaf..5716c5fc6d 100644 --- a/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs @@ -154,4 +154,53 @@ public void Log_CapturesStructuredLog(LogLevel logLevel) .SingleOrDefault(log => log.Length == 1) != null)); } + + [SkippableFact] + public void Log_EventsAndBreadcrumbsIgnoreConfiguration_StructuredLogsRespectConfiguration() + { +#if __IOS__ + Skip.If(true, "Flaky on iOS"); +#endif + + // Arrange + var worker = Substitute.For(); + var envelopes = new List(2); + worker.EnqueueEnvelope(Arg.Do(envelope => envelopes.Add(envelope))); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(builder => builder.AddSentry(o => + { + o.Dsn = ValidDsn; + o.MinimumBreadcrumbLevel = LogLevel.Information; + o.MinimumEventLevel = LogLevel.Warning; + o.BackgroundWorker = worker; + o.InitNativeSdks = false; + o.EnableLogs = true; + })); + serviceCollection.Configure(options => options.AddFilter(CategoryName, LogLevel.Error)); + using var serviceProvider = serviceCollection.BuildServiceProvider(); + using var loggerFactory = serviceProvider.GetRequiredService(); + + // Act + var logger = loggerFactory.CreateLogger(CategoryName); + logger.Log(LogLevel.Information, "test breadcrumb"); + logger.Log(LogLevel.Warning, "test event"); + + var hub = serviceProvider.GetRequiredService(); + hub.Logger.Flush(); + + // Assert + Assert.Collection(envelopes, + element => + { + var serializable = Assert.IsType(element.Items.Single().Payload); + var @event = Assert.IsType(serializable.Source); + Assert.Equal(SentryLevel.Warning, @event.Level); + Assert.Equal("test event", @event.Message.Message); + var breadcrumb = Assert.Single(@event.Breadcrumbs); + Assert.Equal(BreadcrumbLevel.Info, breadcrumb.Level); + Assert.Equal("test breadcrumb", breadcrumb.Message); + } + ); + } } From fab6da59df9e2447a6d59d00e2b31a6006c0556e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:38:57 +0100 Subject: [PATCH 14/18] ref: suppress null --- test/Sentry.Extensions.Logging.Tests/LoggingTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs b/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs index 5716c5fc6d..e9e752a22d 100644 --- a/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/LoggingTests.cs @@ -196,7 +196,7 @@ public void Log_EventsAndBreadcrumbsIgnoreConfiguration_StructuredLogsRespectCon var serializable = Assert.IsType(element.Items.Single().Payload); var @event = Assert.IsType(serializable.Source); Assert.Equal(SentryLevel.Warning, @event.Level); - Assert.Equal("test event", @event.Message.Message); + Assert.Equal("test event", @event.Message!.Message); var breadcrumb = Assert.Single(@event.Breadcrumbs); Assert.Equal(BreadcrumbLevel.Info, breadcrumb.Level); Assert.Equal("test breadcrumb", breadcrumb.Message); From 35b4a8f09cc2ae0554688edec8400d96672449a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:35:57 +0100 Subject: [PATCH 15/18] Update samples/Sentry.Samples.Google.Cloud.Functions/Function.cs Co-authored-by: James Crosswell --- samples/Sentry.Samples.Google.Cloud.Functions/Function.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs b/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs index 3abcd098e4..749aa31d18 100644 --- a/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs +++ b/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs @@ -16,6 +16,7 @@ public class Function : IHttpFunction public Task HandleAsync(HttpContext context) { + // Configure structured logging via appsettings.json (Logging:Sentry:LogLevel:) _logger.LogTrace("LogLevel.Trace is not configured to be sent as structured log"); _logger.LogInformation("Useful info that is added to the breadcrumb list."); throw new Exception("Bad function"); From 8a05445b8f103542d57055057aa595c2b42fef3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:39:11 +0100 Subject: [PATCH 16/18] ref: more samples --- .../Sentry.Samples.AspNetCore.Grpc/appsettings.json | 10 +++++++++- samples/Sentry.Samples.AspNetCore.Mvc/appsettings.json | 10 +++++++++- .../Sentry.Samples.Google.Cloud.Functions/Function.cs | 5 +++++ samples/Sentry.Samples.ME.Logging/Program.cs | 3 ++- samples/Sentry.Samples.Maui/MauiProgram.cs | 4 ++++ 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/samples/Sentry.Samples.AspNetCore.Grpc/appsettings.json b/samples/Sentry.Samples.AspNetCore.Grpc/appsettings.json index 39d46b6bf1..ce9322713d 100644 --- a/samples/Sentry.Samples.AspNetCore.Grpc/appsettings.json +++ b/samples/Sentry.Samples.AspNetCore.Grpc/appsettings.json @@ -23,12 +23,20 @@ "DiagnosticLevel": "Error", "DefaultTags": { "default-key-in-config": "default-value" - } + }, + // Record log messages as Structured Logs (configure via "Logging" section) + "EnableLogs": true }, "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Trace" + }, + // Configure the "Sentry" provider for Structured Logs + "Sentry": { + "LogLevel": { + "Default": "Information" + } } }, "Kestrel": { diff --git a/samples/Sentry.Samples.AspNetCore.Mvc/appsettings.json b/samples/Sentry.Samples.AspNetCore.Mvc/appsettings.json index ab7be6a3ac..e422191f09 100644 --- a/samples/Sentry.Samples.AspNetCore.Mvc/appsettings.json +++ b/samples/Sentry.Samples.AspNetCore.Mvc/appsettings.json @@ -23,12 +23,20 @@ "DiagnosticLevel": "Error", "DefaultTags": { "default-key-in-config": "default-value" - } + }, + // Record log messages as Structured Logs (configure via "Logging" section) + "EnableLogs": true }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" + }, + // Configure the "Sentry" provider for Structured Logs + "Sentry": { + "LogLevel": { + "Default": "Warning" + } } }, "AllowedHosts": "*" diff --git a/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs b/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs index 749aa31d18..896623c669 100644 --- a/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs +++ b/samples/Sentry.Samples.Google.Cloud.Functions/Function.cs @@ -12,13 +12,18 @@ public class Function : IHttpFunction { private readonly ILogger _logger; + public Function(ILogger logger) => _logger = logger; public Task HandleAsync(HttpContext context) { // Configure structured logging via appsettings.json (Logging:Sentry:LogLevel:) _logger.LogTrace("LogLevel.Trace is not configured to be sent as structured log"); + + // Logging integration by default keeps informational logs as Breadcrumb _logger.LogInformation("Useful info that is added to the breadcrumb list."); + + // Results in an Event/Error in Sentry, including the Breadcrumb from above throw new Exception("Bad function"); } } diff --git a/samples/Sentry.Samples.ME.Logging/Program.cs b/samples/Sentry.Samples.ME.Logging/Program.cs index b966a243ed..6fe41222b3 100644 --- a/samples/Sentry.Samples.ME.Logging/Program.cs +++ b/samples/Sentry.Samples.ME.Logging/Program.cs @@ -32,12 +32,13 @@ return log; }); - // TODO: AddLogEntryFilter // Don't keep as a breadcrumb or send events for messages of level less than Critical with exception of type DivideByZeroException options.AddLogEntryFilter((_, level, _, exception) => level < LogLevel.Critical && exception is DivideByZeroException); options.ConfigureScope(s => s.SetTag("RootScope", "sent with all events")); }); + // Don't send logs for messages of level less than Warning for category Program + builder.AddFilter(typeof(Program).FullName, LogLevel.Warning); }); var logger = loggerFactory.CreateLogger(); diff --git a/samples/Sentry.Samples.Maui/MauiProgram.cs b/samples/Sentry.Samples.Maui/MauiProgram.cs index eea68dd249..c7d66648bc 100644 --- a/samples/Sentry.Samples.Maui/MauiProgram.cs +++ b/samples/Sentry.Samples.Maui/MauiProgram.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using Microsoft.Extensions.Logging; using Sentry.Maui; namespace Sentry.Samples.Maui; @@ -77,6 +78,9 @@ public static MauiApp CreateMauiApp() fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); + builder.Logging.AddFilter(null, LogLevel.Warning); + builder.Logging.AddFilter("Sentry.Samples.Maui", LogLevel.Information); + // For this sample, we'll also register the main page for DI so we can inject a logger there. builder.Services.AddTransient(); From fd9dc831e423c164d410e1f2ec478bd454d4596e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:41:57 +0100 Subject: [PATCH 17/18] Update CHANGELOG.md --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d78bd9e63..54f8f56e94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,6 @@ - use the intended `SentryLoggingOptions.MinimumBreadcrumbLevel`, `SentryLoggingOptions.MinimumEventLevel`, or add filter functions via `SentryLoggingOptionsExtensions.AddLogEntryFilter` - the Logger-Provider for _Structured Logs_ respects Logging-Configuration (e.g. via `appsettings.json`) - when enabled by `SentryOptions.EnableLogs` - - Avoid appending `/NODEFAULTLIB:MSVCRT` to NativeAOT linker arguments on Windows when targetting non-Windows platforms (Android, Browser) ([#4760](https://github.com/getsentry/sentry-dotnet/pull/4760)) ## 6.0.0-rc.2 From b26b3b0cb4c580d88b7c2c265b584505aa4e76fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20P=C3=B6lz?= <38893694+Flash0ver@users.noreply.github.com> Date: Mon, 1 Dec 2025 10:21:43 +0100 Subject: [PATCH 18/18] docs: add comment to MAUI sample --- samples/Sentry.Samples.Maui/MauiProgram.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/Sentry.Samples.Maui/MauiProgram.cs b/samples/Sentry.Samples.Maui/MauiProgram.cs index c7d66648bc..c1789d3850 100644 --- a/samples/Sentry.Samples.Maui/MauiProgram.cs +++ b/samples/Sentry.Samples.Maui/MauiProgram.cs @@ -78,6 +78,7 @@ public static MauiApp CreateMauiApp() fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); + // Configure Logging, including Structured Logs sent to Sentry (see 'EnableLogs = true') builder.Logging.AddFilter(null, LogLevel.Warning); builder.Logging.AddFilter("Sentry.Samples.Maui", LogLevel.Information);