Skip to content
25 changes: 11 additions & 14 deletions samples/Sentry.Samples.AspNetCore.NLog/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using NLog.Config;
using NLog.Targets;
using NLog.Web;
using Sentry.NLog;

// UseSentry below only starts Sentry once the app is running. Initializing it here as well captures crashes during
// startup, until UseSentry takes over: https://docs.sentry.io/platforms/dotnet/guides/nlog/#capturing-startup-crashes
Expand All @@ -15,20 +14,18 @@
#endif
});

// Configure NLog to send logs to Sentry. This only adds the Sentry target: it does not initialize Sentry.
var sentryTarget = new SentryTarget(new SentryNLogOptions
{
// Warn and higher are added as breadcrumbs (default is Info)
MinimumBreadcrumbLevel = NLog.LogLevel.Warn,
// Error and higher are sent as events (default is Error)
MinimumEventLevel = NLog.LogLevel.Error,
});

var nlogConfig = new LoggingConfiguration();
nlogConfig.AddRule(NLog.LogLevel.Info, NLog.LogLevel.Fatal, new ColoredConsoleTarget("console"));
// Every entry that reaches the Sentry target is sent as a structured log, so this rule sets the minimum level for logs.
// Info and higher are sent as logs. Breadcrumbs and events can only use entries that pass this rule.
nlogConfig.AddRule(NLog.LogLevel.Info, NLog.LogLevel.Fatal, sentryTarget);
// Configure NLog to send logs to Sentry. This only adds the Sentry target: it does not initialize Sentry.
nlogConfig.AddSentry(options =>
{
// Warn and higher are added as breadcrumbs (default is Info)
options.MinimumBreadcrumbLevel = NLog.LogLevel.Warn;
// Error and higher are sent as events (default is Error)
options.MinimumEventLevel = NLog.LogLevel.Error;
// Info and higher are sent as logs (default is Info)
options.MinimumLogLevel = NLog.LogLevel.Info;
});
LogManager.Configuration = nlogConfig;

try
Expand All @@ -54,7 +51,7 @@

app.MapGet("/", (ILogger<Program> logger) =>
{
logger.LogDebug("Below the Sentry rule's minimum level, so not sent to Sentry");
logger.LogDebug("Below every Sentry minimum level, so not sent to Sentry");
logger.LogInformation("Sent as a log");
logger.LogWarning("Sent as a log and added as a breadcrumb");
logger.LogError("Sent as a log and as an event, which includes the breadcrumb above");
Expand Down
3 changes: 2 additions & 1 deletion samples/Sentry.Samples.NLog/NLog.config
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
ignoreEventsWithNoException="False"
includeEventDataOnBreadcrumbs="False"
includeEventPropertiesAsTags="True"
minimumEventLevel="Error">
minimumEventLevel="Error"
minimumLogLevel="Info">

<!--Optionally add any desired additional Tags that will be sent with every message -->
<tag name="exception" layout="${exception:format=shorttype}" includeEmptyValue="false" />
Expand Down
1 change: 1 addition & 0 deletions samples/Sentry.Samples.NLog/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ private static void UsingCodeConfiguration()

options.MinimumBreadcrumbLevel = LogLevel.Debug; // Debug and higher are stored as breadcrumbs (default is Info)
options.MinimumEventLevel = LogLevel.Error; // Error and higher are sent as events (default is Error)
options.MinimumLogLevel = LogLevel.Info; // Info and higher are sent as logs (default is Info)

options.IncludeEventDataOnBreadcrumbs = true; // Optionally include event properties with breadcrumbs

Expand Down
9 changes: 8 additions & 1 deletion src/Sentry.NLog/ConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public static LoggingConfiguration AddSentry(
/// <remarks>
/// This doesn't initialise Sentry. Initialise Sentry separately, using <c>SentrySdk.Init</c> or another Sentry
/// integration (such as ASP.NET Core or MAUI).
/// The rule it adds starts at the lowest of the target's minimum levels.
/// </remarks>
/// <param name="configuration">The NLog configuration.</param>
/// <param name="optionsConfig">An optional action for configuring the Sentry target options.</param>
Expand Down Expand Up @@ -89,11 +90,17 @@ public static LoggingConfiguration AddSentry(

configuration.AddTarget(targetName, target);

configuration.AddRuleForAllLevels(targetName);
configuration.AddRule(LowestMinimumLevel(options), LogLevel.Fatal, targetName);

return configuration;
}

private static LogLevel LowestMinimumLevel(SentryNLogOptions options)
{
LogLevel?[] levels = [options.MinimumEventLevel, options.MinimumBreadcrumbLevel, options.MinimumLogLevel];
return levels.OfType<LogLevel>().DefaultIfEmpty(LogLevel.Off).Min()!;
}

/// <summary>
/// Add additional tags that will be sent with every message.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/Sentry.NLog/SentryNLogOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public class SentryNLogOptions
/// </summary>
public LogLevel? MinimumBreadcrumbLevel { get; set; } = LogLevel.Info;

/// <summary>
/// Minimum log level to be sent to Sentry as a structured log. Defaults to <see cref="M:LogLevel.Info" />.
/// </summary>
public LogLevel? MinimumLogLevel { get; set; } = LogLevel.Info;
Comment thread
jamescrosswell marked this conversation as resolved.
Resolved

/// <summary>
/// Set this to <see langword="true" /> to ignore log messages that don't contain an exception.
/// </summary>
Expand Down
33 changes: 19 additions & 14 deletions src/Sentry.NLog/SentryTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,32 +137,34 @@ 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>
/// Minimum log level to be sent to Sentry as a structured log. Defaults to <see cref="M:LogLevel.Info" />.
/// </summary>
public string MinimumLogLevel
{
get => Options.MinimumLogLevel?.ToString() ?? LogLevel.Off.ToString();
set => Options.MinimumLogLevel = LogLevel.FromString(value);
}

internal const string EnableLogsFalseIgnored =
"The Sentry target always sends logs, so enableLogs=\"false\" no longer turns them off. " +
"Remove enableLogs from the target configuration. " +
"To drop logs, use SetBeforeSendLog on the options passed to SentrySdk.Init and return null.";
internal const string ObsoleteEnableLogs =
"Use MinimumLogLevel instead. Setting this to false is the same as setting MinimumLogLevel to Off. " +
"This option will be removed in a future major version.";

/// <summary>
/// Logs are always generated and sent.
/// Setting this to <see langword="false"/> sets <see cref="MinimumLogLevel"/> to <c>Off</c>.
/// </summary>
/// <remarks>
/// This option no longer has any effect. The getter always returns <see langword="true"/>.
/// Setting it to <see langword="false"/> only writes a warning to standard error.
/// To filter or drop logs, use <see cref="SentryOptions.SetBeforeSendLog(Func{SentryLog, SentryLog})"/> and return <see langword="null"/>.
/// Setting it to <see langword="true"/> has no effect. Use <see cref="MinimumLogLevel"/> instead.
/// </remarks>
[Obsolete(ObsoleteEnableLogs)]
public bool EnableLogs
{
get => true;
get => Options.MinimumLogLevel is { } level && level != LogLevel.Off;
set
{
if (!value)
{
WriteToStandardError("Sentry: " + EnableLogsFalseIgnored);
Options.MinimumLogLevel = LogLevel.Off;
}
}
}
Expand Down Expand Up @@ -253,6 +255,9 @@ protected override void FlushAsync(AsyncContinuation asyncContinuation)
/// as a breadcrumb to the Sentry Sdk.
/// </para>
/// <para>
/// If the event level is &gt;= the <see cref="MinimumLogLevel"/>, the event is sent as a structured log.
/// </para>
/// <para>
/// If sentry is not enabled, this is a No-op.
/// </para>
/// </summary>
Expand Down Expand Up @@ -337,7 +342,7 @@ private void InnerWrite(LogEventInfo logEvent)
}

var sentryOptions = hub.GetSentryOptions();
if (sentryOptions is not null)
if (sentryOptions is not null && logEvent.Level >= Options.MinimumLogLevel)
{
try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace Sentry.NLog
public NLog.Layouts.Layout? Layout { get; set; }
public NLog.LogLevel? MinimumBreadcrumbLevel { get; set; }
public NLog.LogLevel? MinimumEventLevel { get; set; }
public NLog.LogLevel? MinimumLogLevel { get; set; }
[NLog.Config.NLogConfigurationIgnoreProperty]
public System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext> Tags { get; }
[NLog.Config.NLogConfigurationIgnoreProperty]
Expand All @@ -54,9 +55,8 @@ namespace Sentry.NLog
public NLog.Layouts.Layout? BreadcrumbLayout { get; set; }
[System.Obsolete(@"The Sentry target no longer initializes the SDK, so a DSN can no longer be supplied to it. Initialize Sentry with SentrySdk.Init (or UseSentry via one of the integrations), and remove 'dsn', 'initializeSdk' and any other core SDK settings from the target configuration.", true)]
public NLog.Layouts.Layout? Dsn { get; set; }
[System.Obsolete("The Sentry target always sends logs. This option is ignored and will be removed i" +
"n a future major version. To drop logs, use SetBeforeSendLog on the options pass" +
"ed to SentrySdk.Init and return null.")]
[System.Obsolete("Use MinimumLogLevel instead. Setting this to false is the same as setting Minimum" +
"LogLevel to Off. This option will be removed in a future major version.")]
public bool EnableLogs { get; set; }
public bool IgnoreEventsWithNoException { get; set; }
public bool IncludeEventDataOnBreadcrumbs { get; set; }
Expand All @@ -65,6 +65,7 @@ namespace Sentry.NLog
public bool InitializeSdk { get; set; }
public string MinimumBreadcrumbLevel { get; set; }
public string MinimumEventLevel { get; set; }
public string MinimumLogLevel { get; set; }
public Sentry.NLog.SentryNLogOptions Options { get; }
[NLog.Config.ArrayParameter(typeof(NLog.Targets.TargetPropertyWithContext), "tag")]
public System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext> Tags { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace Sentry.NLog
public NLog.Layouts.Layout? Layout { get; set; }
public NLog.LogLevel? MinimumBreadcrumbLevel { get; set; }
public NLog.LogLevel? MinimumEventLevel { get; set; }
public NLog.LogLevel? MinimumLogLevel { get; set; }
[NLog.Config.NLogConfigurationIgnoreProperty]
public System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext> Tags { get; }
[NLog.Config.NLogConfigurationIgnoreProperty]
Expand All @@ -54,9 +55,8 @@ namespace Sentry.NLog
public NLog.Layouts.Layout? BreadcrumbLayout { get; set; }
[System.Obsolete(@"The Sentry target no longer initializes the SDK, so a DSN can no longer be supplied to it. Initialize Sentry with SentrySdk.Init (or UseSentry via one of the integrations), and remove 'dsn', 'initializeSdk' and any other core SDK settings from the target configuration.", true)]
public NLog.Layouts.Layout? Dsn { get; set; }
[System.Obsolete("The Sentry target always sends logs. This option is ignored and will be removed i" +
"n a future major version. To drop logs, use SetBeforeSendLog on the options pass" +
"ed to SentrySdk.Init and return null.")]
[System.Obsolete("Use MinimumLogLevel instead. Setting this to false is the same as setting Minimum" +
"LogLevel to Off. This option will be removed in a future major version.")]
public bool EnableLogs { get; set; }
public bool IgnoreEventsWithNoException { get; set; }
public bool IncludeEventDataOnBreadcrumbs { get; set; }
Expand All @@ -65,6 +65,7 @@ namespace Sentry.NLog
public bool InitializeSdk { get; set; }
public string MinimumBreadcrumbLevel { get; set; }
public string MinimumEventLevel { get; set; }
public string MinimumLogLevel { get; set; }
public Sentry.NLog.SentryNLogOptions Options { get; }
[NLog.Config.ArrayParameter(typeof(NLog.Targets.TargetPropertyWithContext), "tag")]
public System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext> Tags { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace Sentry.NLog
public NLog.Layouts.Layout? Layout { get; set; }
public NLog.LogLevel? MinimumBreadcrumbLevel { get; set; }
public NLog.LogLevel? MinimumEventLevel { get; set; }
public NLog.LogLevel? MinimumLogLevel { get; set; }
[NLog.Config.NLogConfigurationIgnoreProperty]
public System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext> Tags { get; }
[NLog.Config.NLogConfigurationIgnoreProperty]
Expand All @@ -54,9 +55,8 @@ namespace Sentry.NLog
public NLog.Layouts.Layout? BreadcrumbLayout { get; set; }
[System.Obsolete(@"The Sentry target no longer initializes the SDK, so a DSN can no longer be supplied to it. Initialize Sentry with SentrySdk.Init (or UseSentry via one of the integrations), and remove 'dsn', 'initializeSdk' and any other core SDK settings from the target configuration.", true)]
public NLog.Layouts.Layout? Dsn { get; set; }
[System.Obsolete("The Sentry target always sends logs. This option is ignored and will be removed i" +
"n a future major version. To drop logs, use SetBeforeSendLog on the options pass" +
"ed to SentrySdk.Init and return null.")]
[System.Obsolete("Use MinimumLogLevel instead. Setting this to false is the same as setting Minimum" +
"LogLevel to Off. This option will be removed in a future major version.")]
public bool EnableLogs { get; set; }
public bool IgnoreEventsWithNoException { get; set; }
public bool IncludeEventDataOnBreadcrumbs { get; set; }
Expand All @@ -65,6 +65,7 @@ namespace Sentry.NLog
public bool InitializeSdk { get; set; }
public string MinimumBreadcrumbLevel { get; set; }
public string MinimumEventLevel { get; set; }
public string MinimumLogLevel { get; set; }
public Sentry.NLog.SentryNLogOptions Options { get; }
[NLog.Config.ArrayParameter(typeof(NLog.Targets.TargetPropertyWithContext), "tag")]
public System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext> Tags { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace Sentry.NLog
public NLog.Layouts.Layout? Layout { get; set; }
public NLog.LogLevel? MinimumBreadcrumbLevel { get; set; }
public NLog.LogLevel? MinimumEventLevel { get; set; }
public NLog.LogLevel? MinimumLogLevel { get; set; }
[NLog.Config.NLogConfigurationIgnoreProperty]
public System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext> Tags { get; }
[NLog.Config.NLogConfigurationIgnoreProperty]
Expand All @@ -54,9 +55,8 @@ namespace Sentry.NLog
public NLog.Layouts.Layout? BreadcrumbLayout { get; set; }
[System.Obsolete(@"The Sentry target no longer initializes the SDK, so a DSN can no longer be supplied to it. Initialize Sentry with SentrySdk.Init (or UseSentry via one of the integrations), and remove 'dsn', 'initializeSdk' and any other core SDK settings from the target configuration.", true)]
public NLog.Layouts.Layout? Dsn { get; set; }
[System.Obsolete("The Sentry target always sends logs. This option is ignored and will be removed i" +
"n a future major version. To drop logs, use SetBeforeSendLog on the options pass" +
"ed to SentrySdk.Init and return null.")]
[System.Obsolete("Use MinimumLogLevel instead. Setting this to false is the same as setting Minimum" +
"LogLevel to Off. This option will be removed in a future major version.")]
public bool EnableLogs { get; set; }
public bool IgnoreEventsWithNoException { get; set; }
public bool IncludeEventDataOnBreadcrumbs { get; set; }
Expand All @@ -65,6 +65,7 @@ namespace Sentry.NLog
public bool InitializeSdk { get; set; }
public string MinimumBreadcrumbLevel { get; set; }
public string MinimumEventLevel { get; set; }
public string MinimumLogLevel { get; set; }
public Sentry.NLog.SentryNLogOptions Options { get; }
[NLog.Config.ArrayParameter(typeof(NLog.Targets.TargetPropertyWithContext), "tag")]
public System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext> Tags { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace Sentry.NLog
public NLog.Layouts.Layout? Layout { get; set; }
public NLog.LogLevel? MinimumBreadcrumbLevel { get; set; }
public NLog.LogLevel? MinimumEventLevel { get; set; }
public NLog.LogLevel? MinimumLogLevel { get; set; }
[NLog.Config.NLogConfigurationIgnoreProperty]
public System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext> Tags { get; }
[NLog.Config.NLogConfigurationIgnoreProperty]
Expand All @@ -54,9 +55,8 @@ namespace Sentry.NLog
public NLog.Layouts.Layout? BreadcrumbLayout { get; set; }
[System.Obsolete(@"The Sentry target no longer initializes the SDK, so a DSN can no longer be supplied to it. Initialize Sentry with SentrySdk.Init (or UseSentry via one of the integrations), and remove 'dsn', 'initializeSdk' and any other core SDK settings from the target configuration.", true)]
public NLog.Layouts.Layout? Dsn { get; set; }
[System.Obsolete("The Sentry target always sends logs. This option is ignored and will be removed i" +
"n a future major version. To drop logs, use SetBeforeSendLog on the options pass" +
"ed to SentrySdk.Init and return null.")]
[System.Obsolete("Use MinimumLogLevel instead. Setting this to false is the same as setting Minimum" +
"LogLevel to Off. This option will be removed in a future major version.")]
public bool EnableLogs { get; set; }
public bool IgnoreEventsWithNoException { get; set; }
public bool IncludeEventDataOnBreadcrumbs { get; set; }
Expand All @@ -65,6 +65,7 @@ namespace Sentry.NLog
public bool InitializeSdk { get; set; }
public string MinimumBreadcrumbLevel { get; set; }
public string MinimumEventLevel { get; set; }
public string MinimumLogLevel { get; set; }
public Sentry.NLog.SentryNLogOptions Options { get; }
[NLog.Config.ArrayParameter(typeof(NLog.Targets.TargetPropertyWithContext), "tag")]
public System.Collections.Generic.IList<NLog.Targets.TargetPropertyWithContext> Tags { get; }
Expand Down
39 changes: 39 additions & 0 deletions test/Sentry.NLog.Tests/ConfigurationExtensionsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,45 @@ public void AddSentry_TargetName_TargetNamed()
Assert.Equal("custom", actual.AllTargets[0].Name);
}

[Fact]
public void AddSentry_DefaultOptions_RuleStartsAtInfo()
{
var actual = new LoggingConfiguration().AddSentry();

Assert.Equal(new[] { LogLevel.Info, LogLevel.Warn, LogLevel.Error, LogLevel.Fatal },
Assert.Single(actual.LoggingRules).Levels);
}

[Theory]
[InlineData("Trace", "Info", "Info", "Trace")]
[InlineData("Info", "Debug", "Info", "Debug")]
[InlineData("Info", "Info", "Trace", "Trace")]
[InlineData("Off", "Off", "Warn", "Warn")]
public void AddSentry_RuleStartsAtLowestMinimumLevel(string eventLevel, string breadcrumbLevel, string logLevel, string expected)
{
var actual = new LoggingConfiguration().AddSentry(o =>
{
o.MinimumEventLevel = LogLevel.FromString(eventLevel);
o.MinimumBreadcrumbLevel = LogLevel.FromString(breadcrumbLevel);
o.MinimumLogLevel = LogLevel.FromString(logLevel);
});

Assert.Equal(LogLevel.FromString(expected), Assert.Single(actual.LoggingRules).Levels.Min());
}

[Fact]
public void AddSentry_AllMinimumLevelsNull_RuleHasNoLevels()
{
var actual = new LoggingConfiguration().AddSentry(o =>
{
o.MinimumEventLevel = null;
o.MinimumBreadcrumbLevel = null;
o.MinimumLogLevel = null;
});

Assert.Empty(Assert.Single(actual.LoggingRules).Levels);
}

[Fact]
public void AddTag_SetToTarget()
{
Expand Down
Loading
Loading