Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions samples/Sentry.Samples.AspNetCore.Basic/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
// Configure the minimum Log Level of Breadcrumbs and Events
options.MinimumBreadcrumbLevel = LogLevel.Information;
options.MinimumEventLevel = LogLevel.Error;

// Also send ILogger entries to Sentry as structured logs. This is off by default.
// Logs sent with SentrySdk.Logger don't need this option.
// Configure the minimum level of structured logs in "appsettings.json" and "appsettings.{HostEnvironment}.json"
options.EnableLogs = true;
});

var app = builder.Build();
Expand Down
4 changes: 3 additions & 1 deletion samples/Sentry.Samples.AspNetCore.Grpc/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"DiagnosticLevel": "Error",
"DefaultTags": {
"default-key-in-config": "default-value"
}
},
// Record log messages as Structured Logs
"EnableLogs": true
},
"Logging": {
"IncludeScopes": false,
Expand Down
4 changes: 3 additions & 1 deletion samples/Sentry.Samples.AspNetCore.Mvc/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"DiagnosticLevel": "Error",
"DefaultTags": {
"default-key-in-config": "default-value"
}
},
// Record log messages as Structured Logs
"EnableLogs": true
},
"Logging": {
"LogLevel": {
Expand Down
1 change: 1 addition & 0 deletions samples/Sentry.Samples.ME.AI.AspNetCore/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
options.DiagnosticLevel = SentryLevel.Debug;
options.SampleRate = 1;
options.TracesSampleRate = 1.0;
options.EnableLogs = true;
});

// This sample uses Microsoft.Extensions.AI.OpenAI
Expand Down
3 changes: 2 additions & 1 deletion samples/Sentry.Samples.Maui/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public static MauiApp CreateMauiApp()
options.AttachScreenshot = true;

options.Debug = true;
options.EnableLogs = true;
options.SampleRate = 1.0F;

// The Sentry MVVM Community Toolkit integration automatically creates traces for async relay commands,
Expand Down Expand Up @@ -78,7 +79,7 @@ public static MauiApp CreateMauiApp()
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});

// Configure Logging, including Structured Logs sent to Sentry
// 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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,17 @@ public SentryBlazorOptions()
{
SetSdk(Sentry.AspNetCore.Blazor.WebAssembly.Constants.SdkName, typeof(SentryBlazorOptions).Assembly.GetNameAndVersion());
}

/// <summary>
/// Whether the <see cref="ILogger"/> integration that <c>UseSentry</c> adds sends log entries to Sentry as structured logs.
/// </summary>
/// <remarks>
/// Defaults to <see langword="false"/>, including when the app also calls <c>AddSentry()</c> on its
/// <see cref="ILoggingBuilder"/>.
/// </remarks>
public bool EnableLogs
{
get => LogsEnabled;
set => LogsEnabled = value;
}
}
13 changes: 13 additions & 0 deletions src/Sentry.AspNetCore/SentryAspNetCoreOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ namespace Sentry.AspNetCore;
/// <inheritdoc />
public class SentryAspNetCoreOptions : SentryHostOptions
{
/// <summary>
/// Whether the <see cref="Microsoft.Extensions.Logging.ILogger"/> integration that <c>UseSentry</c> adds sends log entries to Sentry as structured logs.
/// </summary>
/// <remarks>
/// Defaults to <see langword="false"/>, including when the app also calls <c>AddSentry()</c> on its
/// <see cref="Microsoft.Extensions.Logging.ILoggingBuilder"/>.
/// </remarks>
public bool EnableLogs
{
get => LogsEnabled;
set => LogsEnabled = value;
}

/// <summary>
/// Gets or sets a value indicating whether [include System.Diagnostic.Activity data] to events.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/Sentry.Extensions.Logging/BindableSentryHostOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ internal class BindableSentryHostOptions : BindableSentryOptions
{
public LogLevel? MinimumBreadcrumbLevel { get; set; }
public LogLevel? MinimumEventLevel { get; set; }
public bool? EnableLogs { get; set; }

public void ApplyTo(SentryHostOptions options)
{
base.ApplyTo(options);
options.MinimumBreadcrumbLevel = MinimumBreadcrumbLevel ?? options.MinimumBreadcrumbLevel;
options.MinimumEventLevel = MinimumEventLevel ?? options.MinimumEventLevel;
options.LogsEnabled = EnableLogs ?? options.LogsEnabled;
}
}
2 changes: 2 additions & 0 deletions src/Sentry.Extensions.Logging/SentryHostOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public LogLevel MinimumEventLevel
set => Logging.MinimumEventLevel = value;
}

internal bool LogsEnabled { get; set; }

/// <summary>
/// Add a callback to configure the scope upon SDK initialization
/// </summary>
Expand Down
3 changes: 2 additions & 1 deletion src/Sentry.Extensions.Logging/SentryStructuredLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ internal SentryStructuredLogger(string categoryName, IHub hub, ISystemClock cloc
public bool IsEnabled(LogLevel logLevel)
{
return _hub.IsEnabled
&& logLevel != LogLevel.None;
&& logLevel != LogLevel.None
&& _hub.GetSentryOptions() is not SentryHostOptions { LogsEnabled: false };
}

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
Expand Down
13 changes: 13 additions & 0 deletions src/Sentry.Maui/SentryMauiOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ public SentryMauiOptions()
IntegrationEventBinders.Add(new MauiElementEventBinderRegistration<TEventBinder>());
}

/// <summary>
/// Whether the <see cref="ILogger"/> integration that <c>UseSentry</c> adds sends log entries to Sentry as structured logs.
/// </summary>
/// <remarks>
/// Defaults to <see langword="false"/>, including when the app also calls <c>AddSentry()</c> on its
/// <see cref="ILoggingBuilder"/>.
/// </remarks>
public bool EnableLogs
{
get => LogsEnabled;
set => LogsEnabled = value;
}

/// <summary>
/// Gets or sets whether elements that implement <see cref="IText"/>
/// (such as <see cref="Button"/>, <see cref="Label"/>, <see cref="Entry"/>, and others)
Expand Down
6 changes: 5 additions & 1 deletion src/Sentry.NLog/SentryTarget.cs
Comment thread
jamescrosswell marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,18 @@ public string MinimumBreadcrumbLevel
set => Options.MinimumBreadcrumbLevel = LogLevel.FromString(value);
}

internal const string ObsoleteEnableLogs =
"The Sentry target always sends logs. This option is ignored and will be removed in a future major version. " +
"To drop logs, use SetBeforeSendLog on the options passed to SentrySdk.Init and return null.";

/// <summary>
/// Logs are always generated and sent.
/// </summary>
/// <remarks>
/// This option no longer has any effect. The getter always returns <see langword="true"/> and the setter is ignored.
/// To filter or drop logs, use <see cref="SentryOptions.SetBeforeSendLog(Func{SentryLog, SentryLog})"/> and return <see langword="null"/>.
/// </remarks>
[Obsolete(SentryOptions.ObsoleteEnableLogs)]
[Obsolete(ObsoleteEnableLogs)]
public bool EnableLogs
{
get => true;
Expand Down
2 changes: 0 additions & 2 deletions src/Sentry/BindableSentryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ 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 bool? EnableMetrics { get; set; }
public int? MaxQueueItems { get; set; }
public int? MaxCacheItems { get; set; }
Expand Down Expand Up @@ -76,7 +75,6 @@ public void ApplyTo(SentryOptions options)
options.Environment = Environment ?? options.Environment;
options.Dsn = Dsn ?? options.Dsn;
#pragma warning disable CS0618 // Bound so existing configuration keys still resolve; the values are ignored.
options.EnableLogs = EnableLogs ?? options.EnableLogs;
options.EnableMetrics = EnableMetrics ?? options.EnableMetrics;
#pragma warning restore CS0618
options.MaxQueueItems = MaxQueueItems ?? options.MaxQueueItems;
Expand Down
22 changes: 0 additions & 22 deletions src/Sentry/SentryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -607,28 +607,6 @@ public void SetBeforeBreadcrumb(Func<Breadcrumb, Breadcrumb?> beforeBreadcrumb)
_beforeBreadcrumb = (breadcrumb, _) => beforeBreadcrumb(breadcrumb);
}

internal const string ObsoleteEnableLogs =
"Logs are always enabled. This option is ignored and will be removed in a future major version. " +
"To drop logs, use SetBeforeSendLog and return null.";

/// <summary>
/// Logs are always sent to Sentry.
/// </summary>
/// <remarks>
/// This option no longer has any effect. The getter always returns <see langword="true"/> and the setter is ignored.
/// To filter or drop logs, use <see cref="SetBeforeSendLog(Func{SentryLog, SentryLog})"/> and return <see langword="null"/>.
/// </remarks>
/// <seealso href="https://develop.sentry.dev/sdk/telemetry/logs/"/>
[Obsolete(ObsoleteEnableLogs)]
public bool EnableLogs
{
get => true;
set
{
// Logs are always enabled. This option is deliberately ignored.
}
}

private Func<SentryLog, SentryLog?>? _beforeSendLog;

internal Func<SentryLog, SentryLog?>? BeforeSendLogInternal => _beforeSendLog;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,48 @@ public void UseSentry_MinimumEventLevel_AppliesToLogger()

_events.Should().ContainSingle().Which.Message!.Message.Should().Be("at the configured level");
}

[Fact]
public void UseSentry_Default_DoesNotSendLogs()
{
var logs = LogInformation(_ => { });

logs.Should().BeEmpty();
}

[Fact]
public void UseSentry_EnableLogs_SendsLogs()
{
var logs = LogInformation(o => o.EnableLogs = true);

logs.Should().ContainSingle().Which.Message.Should().Be("message");
}

[Fact]
public void UseSentry_EnableLogsInConfiguration_SendsLogs()
{
var logs = LogInformation(_ => { }, ("Sentry:EnableLogs", "true"));

logs.Should().ContainSingle().Which.Message.Should().Be("message");
}

private List<SentryLog> LogInformation(
Action<SentryBlazorOptions> configureOptions,
params (string Key, string Value)[] settings)
{
var logs = new List<SentryLog>();
using var provider = GetSut(o =>
{
o.SetBeforeSendLog(log =>
{
logs.Add(log);
return null;
});
configureOptions(o);
}, settings);

provider.GetRequiredService<ILoggerFactory>().CreateLogger("test_category").LogInformation("message");

return logs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace Sentry.AspNetCore
public bool AdjustStandardEnvironmentNameCasing { get; set; }
public bool AutoRegisterTracing { get; set; }
public bool CaptureBlockingCalls { get; set; }
public bool EnableLogs { get; set; }
public bool FlushOnCompletedRequest { get; set; }
public bool IncludeActivityData { get; set; }
public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace Sentry.AspNetCore
public bool AdjustStandardEnvironmentNameCasing { get; set; }
public bool AutoRegisterTracing { get; set; }
public bool CaptureBlockingCalls { get; set; }
public bool EnableLogs { get; set; }
public bool FlushOnCompletedRequest { get; set; }
public bool IncludeActivityData { get; set; }
public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace Sentry.AspNetCore
public bool AdjustStandardEnvironmentNameCasing { get; set; }
public bool AutoRegisterTracing { get; set; }
public bool CaptureBlockingCalls { get; set; }
public bool EnableLogs { get; set; }
public bool FlushOnCompletedRequest { get; set; }
public bool IncludeActivityData { get; set; }
public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace Sentry.AspNetCore
public bool AdjustStandardEnvironmentNameCasing { get; set; }
public bool AutoRegisterTracing { get; set; }
public bool CaptureBlockingCalls { get; set; }
public bool EnableLogs { get; set; }
public bool FlushOnCompletedRequest { get; set; }
public bool IncludeActivityData { get; set; }
public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,78 @@ public async Task NotFoundRequest_TraceIgnoreStatusCodesCleared_TransactionCaptu
_ = Worker.Received(1).EnqueueEnvelope(Arg.Is<Envelope>(e => HasTransaction(e, "GET /missing")));
}

[Fact]
public void LogWarning_ByDefault_NoLogSent()
{
var logs = CaptureLogs();

Build();
ServiceProvider.GetRequiredService<ILogger<IntegrationMockedBackgroundWorker>>().LogWarning("test");

logs.Should().BeEmpty();
}

[Fact]
public void LogWarning_EnableLogs_LogSent()
{
var logs = CaptureLogs(o => o.EnableLogs = true);

Build();
ServiceProvider.GetRequiredService<ILogger<IntegrationMockedBackgroundWorker>>().LogWarning("test");

logs.Should().ContainSingle().Which.Message.Should().Be("test");
}

[Fact]
public void LogWarning_EnableLogsInConfiguration_LogSent()
{
var logs = CaptureLogs();
var configureWebHost = ConfigureWebHost;
ConfigureWebHost = builder =>
{
builder.ConfigureAppConfiguration((_, config) =>
config.AddInMemoryCollection(new Dictionary<string, string> { ["Sentry:EnableLogs"] = "true" }));
configureWebHost(builder);
};

Build();
ServiceProvider.GetRequiredService<ILogger<IntegrationMockedBackgroundWorker>>().LogWarning("test");

logs.Should().ContainSingle().Which.Message.Should().Be("test");
}

[Fact]
public void LogWarning_ExplicitLoggingAddSentry_NoLogSent()
{
var logs = CaptureLogs();
var configureWebHost = ConfigureWebHost;
ConfigureWebHost = builder =>
{
builder.ConfigureLogging(logging => logging.AddSentry());
configureWebHost(builder);
};

Build();
ServiceProvider.GetRequiredService<ILogger<IntegrationMockedBackgroundWorker>>().LogWarning("test");

logs.Should().BeEmpty();
}

private List<SentryLog> CaptureLogs(Action<SentryAspNetCoreOptions> configure = null)
{
var logs = new List<SentryLog>();
Configure = o =>
{
o.SetBeforeSendLog(log =>
{
logs.Add(log);
return null;
});
configure?.Invoke(o);
};
return logs;
}

private static bool HasTransaction(Envelope envelope, string name) =>
envelope.Items
.Select(i => i.Payload)
Expand Down
Loading
Loading