Skip to content

Commit 57163c1

Browse files
authored
Merge pull request #188 from josh-degraw/feature/NLog-integration
Adds NLog Integration
2 parents 4f132f2 + 5a82a09 commit 57163c1

File tree

15 files changed

+1143
-1
lines changed

15 files changed

+1143
-1
lines changed

Sentry.sln

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sentry.Samples.Serilog", "s
8181
EndProject
8282
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sentry.Samples.AspNetCore.Serilog", "samples\Sentry.Samples.AspNetCore.Serilog\Sentry.Samples.AspNetCore.Serilog.csproj", "{1930A5D5-356B-43F9-AEDF-CB76254C5933}"
8383
EndProject
84+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sentry.NLog", "src\Sentry.NLog\Sentry.NLog.csproj", "{998AC5A8-8D13-46EA-B889-8A733CA152F7}"
85+
EndProject
86+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sentry.NLog.Tests", "test\Sentry.NLog.Tests\Sentry.NLog.Tests.csproj", "{21A360C7-338F-4A9D-A9A3-83152D0C9303}"
87+
EndProject
88+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Samples.NLog", "samples\Sentry.Samples.NLog\Sentry.Samples.NLog.csproj", "{DC90D63E-E4F3-40CB-AF6D-2EAEE5F619B7}"
89+
EndProject
8490
Global
8591
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8692
Debug|Any CPU = Debug|Any CPU
@@ -171,6 +177,18 @@ Global
171177
{1930A5D5-356B-43F9-AEDF-CB76254C5933}.Debug|Any CPU.Build.0 = Debug|Any CPU
172178
{1930A5D5-356B-43F9-AEDF-CB76254C5933}.Release|Any CPU.ActiveCfg = Release|Any CPU
173179
{1930A5D5-356B-43F9-AEDF-CB76254C5933}.Release|Any CPU.Build.0 = Release|Any CPU
180+
{998AC5A8-8D13-46EA-B889-8A733CA152F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
181+
{998AC5A8-8D13-46EA-B889-8A733CA152F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
182+
{998AC5A8-8D13-46EA-B889-8A733CA152F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
183+
{998AC5A8-8D13-46EA-B889-8A733CA152F7}.Release|Any CPU.Build.0 = Release|Any CPU
184+
{21A360C7-338F-4A9D-A9A3-83152D0C9303}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
185+
{21A360C7-338F-4A9D-A9A3-83152D0C9303}.Debug|Any CPU.Build.0 = Debug|Any CPU
186+
{21A360C7-338F-4A9D-A9A3-83152D0C9303}.Release|Any CPU.ActiveCfg = Release|Any CPU
187+
{21A360C7-338F-4A9D-A9A3-83152D0C9303}.Release|Any CPU.Build.0 = Release|Any CPU
188+
{DC90D63E-E4F3-40CB-AF6D-2EAEE5F619B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
189+
{DC90D63E-E4F3-40CB-AF6D-2EAEE5F619B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
190+
{DC90D63E-E4F3-40CB-AF6D-2EAEE5F619B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
191+
{DC90D63E-E4F3-40CB-AF6D-2EAEE5F619B7}.Release|Any CPU.Build.0 = Release|Any CPU
174192
EndGlobalSection
175193
GlobalSection(SolutionProperties) = preSolution
176194
HideSolutionNode = FALSE
@@ -197,6 +215,9 @@ Global
197215
{EBABB411-4481-478B-BEAD-009D1EE6D259} = {83263231-1A2A-4733-B759-EEFF14E8C5D5}
198216
{B7EDB922-4024-4546-B6E4-E5AB9016369F} = {77454495-55EE-4B40-A089-71B9E8F82E89}
199217
{1930A5D5-356B-43F9-AEDF-CB76254C5933} = {77454495-55EE-4B40-A089-71B9E8F82E89}
218+
{998AC5A8-8D13-46EA-B889-8A733CA152F7} = {AF6AF4C7-8AA2-4D59-8064-2D79560904EB}
219+
{21A360C7-338F-4A9D-A9A3-83152D0C9303} = {83263231-1A2A-4733-B759-EEFF14E8C5D5}
220+
{DC90D63E-E4F3-40CB-AF6D-2EAEE5F619B7} = {77454495-55EE-4B40-A089-71B9E8F82E89}
200221
EndGlobalSection
201222
GlobalSection(ExtensibilityGlobals) = postSolution
202223
SolutionGuid = {0C652B1A-DF72-4EE5-A98B-194FE2C054F6}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
>
5+
<extensions>
6+
<add assembly="Sentry.NLog" />
7+
</extensions>
8+
9+
<targets>
10+
<target name="logconsole" xsi:type="ColoredConsole" />
11+
<target xsi:type="Sentry" name="sentry"
12+
dsn="https://[email protected]/1188141"
13+
layout="${message}"
14+
breadcrumbLayout="${message}"
15+
minimumBreadcrumbLevel="Debug"
16+
minimumEventLevel="Error">
17+
18+
<!-- Advanced options can be configured here-->
19+
<options
20+
environment="Development"
21+
attachStacktrace="true"
22+
sendDefaultPii="true"
23+
shutdownTimeoutSeconds="5"
24+
>
25+
<!--Advanced options can be specified as attributes or elements-->
26+
<includeEventDataOnBreadcrumbs>true</includeEventDataOnBreadcrumbs>
27+
</options>
28+
29+
30+
<!--Add any desired additional tags that will be sent with every message -->
31+
<tag name="logger" layout="${logger}" />
32+
</target>
33+
</targets>
34+
35+
<rules>
36+
<logger name="*" writeTo="logconsole" />
37+
<logger name="*" writeTo="sentry" />
38+
</rules>
39+
</nlog>
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using System;
2+
3+
using NLog;
4+
using NLog.Config;
5+
using NLog.Targets;
6+
7+
// ReSharper disable ConvertToConstant.Local
8+
9+
namespace Sentry.Samples.NLog
10+
{
11+
public static class Program
12+
{
13+
private static void Main(string[] args)
14+
{
15+
try
16+
{
17+
// You can configure your logger using a configuration file:
18+
UsingNLogConfigFile();
19+
20+
// Or you can configure it with code:
21+
UsingCodeConfiguration();
22+
}
23+
catch (Exception e)
24+
{
25+
Console.WriteLine(e);
26+
}
27+
finally
28+
{
29+
LogManager.Shutdown();
30+
}
31+
}
32+
33+
private static void DemoLogger(ILogger logger)
34+
{
35+
// Minimum Breadcrumb and Event log levels are set to levels higher than Trace.
36+
// In this case, Trace messages are ignored
37+
logger.Trace("Verbose message which is not sent.");
38+
39+
// Minimum Breadcrumb level is set to Debug so the following message is stored in memory and sent
40+
// with following events of the same Scope
41+
logger.Debug("Debug message stored as breadcrumb.");
42+
43+
// Sends an event and stores the message as a breadcrumb too, to be sent with any upcoming events.
44+
logger.Error("Some event that includes the previous breadcrumbs. mood = {mood}", "happy that my error is reported");
45+
46+
try
47+
{
48+
DoWork(logger);
49+
}
50+
catch (Exception e)
51+
{
52+
e.Data.Add("details", "DoWork always throws.");
53+
logger.Fatal(e, "Error: with exception. {data}", new { title = "compound data object", wowFactor = 11, errorReported = true });
54+
LogManager.Flush();
55+
}
56+
}
57+
58+
private static void DoWork(ILogger logger)
59+
{
60+
int a = 0, b = 10;
61+
62+
logger.Info("Dividing {b} by {a}", b, a);
63+
64+
logger.Warn("a is 0");
65+
66+
_ = 10 / a;
67+
}
68+
69+
private static void UsingNLogConfigFile()
70+
{
71+
// If using an NLog.config xml file, NLog will load the configuration automatically Or, if using a
72+
// different file, you can call the following to load it for you: LogManager.Configuration = LogManager.LoadConfiguration("NLog.config").Configuration;
73+
74+
var logger = LogManager.GetCurrentClassLogger();
75+
DemoLogger(logger);
76+
}
77+
78+
private static void UsingCodeConfiguration()
79+
{
80+
// Other overloads exist, for example, configure the SDK with only the DSN or no parameters at all.
81+
var config = LogManager.Configuration = new LoggingConfiguration();
82+
config
83+
.AddSentry(o =>
84+
{
85+
o.Layout = "${message}";
86+
o.BreadcrumbLayout = "${logger}: ${message}"; // Optionally specify a separate format for breadcrumbs
87+
88+
o.MinimumBreadcrumbLevel = LogLevel.Debug; // Debug and higher are stored as breadcrumbs (default is Info)
89+
o.MinimumEventLevel = LogLevel.Error; // Error and higher is sent as event (default is Error)
90+
91+
// If DSN is not set, the SDK will look for an environment variable called SENTRY_DSN. If
92+
// nothing is found, SDK is disabled.
93+
o.Dsn = new Dsn("https://[email protected]/1188141");
94+
95+
o.AttachStacktrace = true;
96+
o.SendDefaultPii = true; // Send Personal Identifiable information like the username of the user logged in to the device
97+
98+
o.IncludeEventDataOnBreadcrumbs = true; // Optionally include event properties with breadcrumbs
99+
o.ShutdownTimeoutSeconds = 5;
100+
101+
o.AddTag("logger", "${logger}"); // Send the logger name as a tag
102+
103+
// Other configuration
104+
});
105+
106+
config.AddTarget(new DebuggerTarget("debugger"));
107+
108+
config.AddTarget(new ColoredConsoleTarget("console"));
109+
config.AddRuleForAllLevels("console");
110+
config.AddRuleForAllLevels("debugger");
111+
112+
LogManager.Configuration = config;
113+
114+
var Log = LogManager.GetCurrentClassLogger();
115+
DemoLogger(Log);
116+
}
117+
}
118+
119+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net462</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<ProjectReference Include="..\..\src\Sentry.NLog\Sentry.NLog.csproj">
10+
<Private>true</Private>
11+
</ProjectReference>
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<None Update="NLog.config">
16+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
17+
</None>
18+
</ItemGroup>
19+
20+
21+
</Project>
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System;
2+
3+
using NLog.Config;
4+
using NLog.Layouts;
5+
using NLog.Targets;
6+
7+
using Sentry;
8+
using Sentry.NLog;
9+
10+
// ReSharper disable once CheckNamespace
11+
namespace NLog
12+
{
13+
public static class ConfigurationExtensions
14+
{
15+
private const string DefaultTargetName = "sentry";
16+
17+
/// <summary>
18+
/// Adds a target for Sentry to the NLog configuration.
19+
/// </summary>
20+
/// <remarks>
21+
/// If DSN is not set, the SDK will look for an environment variable called SENTRY_DSN. If nothing is
22+
/// found, SDK is disabled.
23+
/// </remarks>
24+
/// <param name="configuration">The NLog configuration.</param>
25+
/// <param name="optionsConfig">An optional action for configuring the Sentry target options.</param>
26+
/// <returns>The configuration.</returns>
27+
public static LoggingConfiguration AddSentry(this LoggingConfiguration configuration,
28+
Action<SentryNLogOptions> optionsConfig = null)
29+
{
30+
return configuration.AddSentry(null, DefaultTargetName, optionsConfig);
31+
}
32+
33+
/// <summary>
34+
/// Adds a target for Sentry to the NLog configuration.
35+
/// </summary>
36+
/// <param name="configuration">The NLog configuration.</param>
37+
/// <param name="dsn">
38+
/// The sentry DSN. If DSN is not set, the SDK will look for an environment variable called SENTRY_DSN.
39+
/// If nothing is found, SDK is disabled.
40+
/// </param>
41+
/// <param name="optionsConfig">An optional action for configuring the Sentry target options.</param>
42+
/// <returns>The configuration.</returns>
43+
public static LoggingConfiguration AddSentry(this LoggingConfiguration configuration,
44+
string dsn,
45+
Action<SentryNLogOptions> optionsConfig = null)
46+
{
47+
return configuration.AddSentry(dsn, DefaultTargetName, optionsConfig);
48+
}
49+
50+
/// <summary>
51+
/// Adds a target for Sentry to the NLog configuration.
52+
/// </summary>
53+
/// <param name="configuration">The NLog configuration.</param>
54+
/// <param name="dsn"> The sentry DSN.</param>
55+
/// <param name="targetName"> The name to give the new target.</param>
56+
/// <param name="optionsConfig">An optional action for configuring the Sentry target options.</param>
57+
/// <returns>The configuration.</returns>
58+
public static LoggingConfiguration AddSentry(this LoggingConfiguration configuration,
59+
string dsn,
60+
string targetName,
61+
Action<SentryNLogOptions> optionsConfig = null)
62+
{
63+
var options = new SentryNLogOptions();
64+
65+
optionsConfig?.Invoke(options);
66+
67+
68+
Target.Register<SentryTarget>("Sentry");
69+
70+
var target = new SentryTarget(options)
71+
{
72+
Name = targetName,
73+
Layout = "${message}",
74+
};
75+
76+
if (dsn != null && options.Dsn == null)
77+
{
78+
options.Dsn = new Dsn(dsn);
79+
}
80+
81+
configuration?.AddTarget(targetName, target);
82+
83+
configuration?.AddRuleForAllLevels(targetName);
84+
85+
return configuration;
86+
}
87+
88+
/// <summary>
89+
/// Add any desired additional tags that will be sent with every message.
90+
/// </summary>
91+
/// <param name="options">The options being configured.</param>
92+
/// <param name="name"> The name of the tag.</param>
93+
/// <param name="layout"> The layout to be rendered for the tag</param>
94+
public static void AddTag(this SentryNLogOptions options, string name, Layout layout)
95+
{
96+
options.Tags.Add(new TargetPropertyWithContext(name, layout));
97+
}
98+
99+
}
100+
}

src/Sentry.NLog/Constants.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Sentry.NLog
2+
{
3+
internal static class Constants
4+
{
5+
public const string SdkName = "sentry.dotnet.nlog";
6+
}
7+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
// ReSharper disable LoopCanBePartlyConvertedToQuery
5+
// ReSharper disable LoopCanBeConvertedToQuery
6+
7+
namespace Sentry.NLog
8+
{
9+
internal static class HelperExtensions
10+
{
11+
internal static IEnumerable<KeyValuePair<TKey, TValue>> ToKeyValuePairs<TSource, TKey, TValue>(
12+
this IEnumerable<TSource> source,
13+
Func<TSource, TKey> keySelector,
14+
Func<TSource, TValue> valueSelector)
15+
{
16+
if (source is null)
17+
{
18+
yield break;
19+
}
20+
21+
foreach (var item in source)
22+
{
23+
yield return new KeyValuePair<TKey, TValue>(keySelector(item), valueSelector(item));
24+
}
25+
}
26+
27+
internal static IEnumerable<KeyValuePair<TKey, TNewValue>> MapValues<TKey, TValue, TNewValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source, Func<TValue,TNewValue> valueSelector)
28+
{
29+
if (source is null)
30+
{
31+
yield break;
32+
}
33+
34+
foreach (var item in source)
35+
{
36+
yield return new KeyValuePair<TKey, TNewValue>(item.Key, valueSelector(item.Value));
37+
}
38+
39+
}
40+
41+
internal static void AddRange<T>(this ICollection<T> source, IEnumerable<T> items)
42+
{
43+
if (source is null || items is null)
44+
{
45+
return;
46+
}
47+
48+
foreach (var item in items)
49+
{
50+
source.Add(item);
51+
}
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)