-
-
Notifications
You must be signed in to change notification settings - Fork 221
WIP: Logs for Sentry.Extensions.Logging
and integrations for Sentry.AspNetCore
and Sentry.Maui
#4193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/logs
Are you sure you want to change the base?
WIP: Logs for Sentry.Extensions.Logging
and integrations for Sentry.AspNetCore
and Sentry.Maui
#4193
Changes from all commits
0add668
db7d558
d96b092
2958a47
a63371b
d8d2567
fefd24c
165996a
32e7e25
fc88722
2ba87e4
0f1d4a4
8dec5d5
a664f7e
96693d0
83964cf
dadc69b
c91cdde
0740c3b
eee06bf
8c61d8b
80683ae
cb20118
2cb306f
dcc0ec1
58dce74
f2e1ba2
0220015
6822b23
dd39fae
6eb5b9b
69c05b8
430cf82
31a8f1f
2ae4476
69678ce
97995a8
fbe747d
64adf33
cdfa901
d2ac53b
4011ba6
4ae82d0
bc1c465
79fb190
b4e80f4
b21adef
0032858
a9769f8
9a51033
8d03449
1bc3a6f
7624baa
11fe02b
fd532ca
1fe9cc0
476cbc3
9a09832
d9ce523
3e6dba5
23934dc
f133118
0985a76
72c9a93
c97f4ad
a9eea90
8bd0ed2
51892de
acc8995
6bd4c96
f673d1e
daafd7f
62ee5d5
6a54203
479cab8
f59160b
18a8284
97a87f8
0467449
54062d2
7107bce
c0a1cd5
45b8687
3192534
b8bcea6
d4c82a2
9193a96
7cb4043
e3ca5b5
afb135e
7f675aa
750a388
9f62d3b
5b00c21
6d17918
7e2c57b
7115c42
cd5246b
baf5569
e592d03
6e13e95
0a9a3b1
934fb36
2c1608e
2b09a79
2950be9
d428163
a936ec6
0fae148
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
using Sentry.Extensions.Logging; | ||
|
||
namespace Sentry.AspNetCore; | ||
|
||
/// <summary> | ||
/// Structured Logger Provider for Sentry. | ||
/// </summary> | ||
[ProviderAlias("SentryLogs")] | ||
[Experimental(Infrastructure.DiagnosticId.ExperimentalFeature)] | ||
internal sealed class SentryAspNetCoreStructuredLoggerProvider : SentryStructuredLoggerProvider | ||
{ | ||
public SentryAspNetCoreStructuredLoggerProvider(IOptions<SentryAspNetCoreOptions> options, IHub hub) | ||
: base(options, hub) | ||
{ | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,10 +93,16 @@ public static IWebHostBuilder UseSentry( | |
_ = logging.Services | ||
.AddSingleton<IConfigureOptions<SentryAspNetCoreOptions>, SentryAspNetCoreOptionsSetup>(); | ||
_ = logging.Services.AddSingleton<ILoggerProvider, SentryAspNetCoreLoggerProvider>(); | ||
_ = logging.Services.AddSingleton<ILoggerProvider, SentryAspNetCoreStructuredLoggerProvider>(); | ||
|
||
_ = logging.AddFilter<SentryAspNetCoreLoggerProvider>( | ||
"Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware", | ||
LogLevel.None); | ||
_ = logging.AddFilter<SentryAspNetCoreStructuredLoggerProvider>(static (string? categoryName, LogLevel logLevel) => | ||
{ | ||
return categoryName is null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are these guaranteed to be all of the categories we add? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm fairly certain ... not quite positive though. |
||
|| (categoryName != "Sentry.ISentryClient" && categoryName != "Sentry.AspNetCore.SentryMiddleware"); | ||
}); | ||
|
||
var sentryBuilder = logging.Services.AddSentry(); | ||
configureSentry?.Invoke(context, sentryBuilder); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Sentry.Extensions.Logging; | ||
|
||
[Experimental(Infrastructure.DiagnosticId.ExperimentalFeature)] | ||
internal sealed class SentryStructuredLogger : ILogger | ||
{ | ||
private readonly string _categoryName; | ||
private readonly SentryLoggingOptions _options; | ||
private readonly IHub _hub; | ||
|
||
internal SentryStructuredLogger(string categoryName, SentryLoggingOptions options, IHub hub) | ||
{ | ||
_categoryName = categoryName; | ||
_options = options; | ||
_hub = hub; | ||
} | ||
|
||
public IDisposable? BeginScope<TState>(TState state) where TState : notnull | ||
{ | ||
return NullDisposable.Instance; | ||
} | ||
|
||
public bool IsEnabled(LogLevel logLevel) | ||
{ | ||
return _hub.IsEnabled | ||
&& _options.Experimental.EnableLogs | ||
&& logLevel != LogLevel.None | ||
&& logLevel >= _options.ExperimentalLogging.MinimumLogLevel; | ||
} | ||
|
||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) | ||
{ | ||
if (!IsEnabled(logLevel)) | ||
{ | ||
return; | ||
} | ||
|
||
// not quite ideal as this is a boxing allocation from Microsoft.Extensions.Logging.FormattedLogValues | ||
/* | ||
string? template = null; | ||
object[]? parameters = null; | ||
if (state is IReadOnlyList<KeyValuePair<string, object?>> formattedLogValues) | ||
{ | ||
foreach (var formattedLogValue in formattedLogValues) | ||
{ | ||
if (formattedLogValue.Key == "{OriginalFormat}" && formattedLogValue.Value is string formattedString) | ||
{ | ||
template = formattedString; | ||
break; | ||
} | ||
} | ||
} | ||
*/ | ||
|
||
string message = formatter.Invoke(state, exception); | ||
|
||
switch (logLevel) | ||
{ | ||
case LogLevel.Trace: | ||
_hub.Logger.LogTrace(message); | ||
break; | ||
case LogLevel.Debug: | ||
_hub.Logger.LogDebug(message); | ||
break; | ||
case LogLevel.Information: | ||
_hub.Logger.LogInfo(message); | ||
break; | ||
case LogLevel.Warning: | ||
_hub.Logger.LogWarning(message); | ||
break; | ||
case LogLevel.Error: | ||
_hub.Logger.LogError(message); | ||
break; | ||
case LogLevel.Critical: | ||
_hub.Logger.LogFatal(message); | ||
break; | ||
case LogLevel.None: | ||
default: | ||
break; | ||
} | ||
} | ||
} | ||
|
||
file sealed class NullDisposable : IDisposable | ||
{ | ||
public static NullDisposable Instance { get; } = new NullDisposable(); | ||
|
||
private NullDisposable() | ||
{ | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Sentry.Extensions.Logging; | ||
|
||
/// <summary> | ||
/// Sentry Structured Logger Provider. | ||
/// </summary> | ||
[ProviderAlias("SentryLogs")] | ||
[Experimental(Infrastructure.DiagnosticId.ExperimentalFeature)] | ||
internal class SentryStructuredLoggerProvider : ILoggerProvider | ||
{ | ||
private readonly IOptions<SentryLoggingOptions> _options; | ||
private readonly IHub _hub; | ||
|
||
// TODO: convert this comment into an automated test | ||
// Constructor must be public for Microsoft.Extensions.DependencyInjection | ||
public SentryStructuredLoggerProvider(IOptions<SentryLoggingOptions> options, IHub hub) | ||
{ | ||
_options = options; | ||
_hub = hub; | ||
} | ||
|
||
public ILogger CreateLogger(string categoryName) | ||
{ | ||
return new SentryStructuredLogger(categoryName, _options.Value, _hub); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
using Sentry.Extensions.Logging; | ||
|
||
namespace Sentry.Maui.Internal; | ||
|
||
[ProviderAlias("SentryLogs")] | ||
[Experimental(Infrastructure.DiagnosticId.ExperimentalFeature)] | ||
internal sealed class SentryMauiStructuredLoggerProvider : SentryStructuredLoggerProvider | ||
{ | ||
public SentryMauiStructuredLoggerProvider(IOptions<SentryMauiOptions> options, IHub hub) | ||
: base(options, hub) | ||
{ | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If #4158 and #4193 are both going in the same release, we could probably compress it into a single changelog entry (referencing multiple PRs, as we often do for the dependency bumps)... maybe with some bullet/sub-list items for each of the integrations. It's a bit confusing otherwise having two change log entries announcing structured logging.