Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
38 changes: 26 additions & 12 deletions src/Sentry.Extensions.Logging/SentryLogger.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using Sentry.Extensibility;
using Sentry.Infrastructure;
using Sentry.Internal;

Expand Down Expand Up @@ -161,12 +162,7 @@ private bool ShouldCaptureEvent(
&& logLevel >= _options.MinimumEventLevel
&& !IsFromSentry()
&& !IsEfExceptionMessage(eventId)
&& _options.Filters.All(
f => !f.Filter(
CategoryName,
logLevel,
eventId,
exception));
&& !IsFiltered(logLevel, eventId, exception);

private bool ShouldAddBreadcrumb(
LogLevel logLevel,
Expand All @@ -176,12 +172,30 @@ private bool ShouldAddBreadcrumb(
&& logLevel >= _options.MinimumBreadcrumbLevel
&& !IsFromSentry()
&& !IsEfExceptionMessage(eventId)
&& _options.Filters.All(
f => !f.Filter(
CategoryName,
logLevel,
eventId,
exception));
&& !IsFiltered(logLevel, eventId, exception);

private bool IsFiltered(
LogLevel logLevel,
EventId eventId,
Exception? exception)
=> _options.Filters.Any(f => IsFiltered(f, logLevel, eventId, exception));

private bool IsFiltered(
ILogEntryFilter filter,
LogLevel logLevel,
EventId eventId,
Exception? exception)
{
try
{
return filter.Filter(CategoryName, logLevel, eventId, exception);
}
catch (Exception e)
{
_options.LogError(e, "The {0} log filter callback failed. The log entry will not be filtered.", filter.GetType().Name);
return false;
}
}


private bool IsFromSentry() => SentrySdkNamespaces.IsSentrySdk(CategoryName);
Expand Down
18 changes: 16 additions & 2 deletions src/Sentry.Maui/Internal/SentryMauiScreenshotProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,23 @@ public SentryMauiScreenshotProcessor(SentryMauiOptions options)

public SentryEvent? Process(SentryEvent @event, SentryHint hint)
{
if (!_options.BeforeCaptureInternal?.Invoke(@event, hint) ?? false)
if (_options.BeforeCaptureInternal is { } beforeCapture)
{
return @event;
bool shouldCapture;
try
{
shouldCapture = beforeCapture.Invoke(@event, hint);
}
catch (Exception e)
{
_options.LogError(e, "BeforeCaptureScreenshot callback failed.");
return @event;
}

if (!shouldCapture)
{
return @event;
}
}

hint.Attachments.Add(new ScreenshotAttachment(_options));
Expand Down
12 changes: 10 additions & 2 deletions src/Sentry/Internal/DefaultSentryMetricEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ private protected override void CaptureMetric<T>(SentryMetricType type, string n
{
if (!SentryMetric.IsSupported(typeof(T)))
{
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.Invalid, DataCategory.TraceMetric);
_options.DiagnosticLogger?.LogWarning("{0} is unsupported type for Sentry Metrics. The only supported types are byte, short, int, long, float, and double.", typeof(T));
return;
}

if (string.IsNullOrEmpty(name))
{
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.Invalid, DataCategory.TraceMetric);
_options.DiagnosticLogger?.LogWarning("Name of metrics cannot be null or empty. Metric-Type: {0}; Value-Type: {1}", type.ToString(), typeof(T));
return;
}
Expand All @@ -46,12 +48,14 @@ private protected override void CaptureMetric<T>(SentryMetricType type, string n
{
if (!SentryMetric.IsSupported(typeof(T)))
{
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.Invalid, DataCategory.TraceMetric);
_options.DiagnosticLogger?.LogWarning("{0} is unsupported type for Sentry Metrics. The only supported types are byte, short, int, long, float, and double.", typeof(T));
return;
}

if (string.IsNullOrEmpty(name))
{
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.Invalid, DataCategory.TraceMetric);
_options.DiagnosticLogger?.LogWarning("Name of metrics cannot be null or empty. Metric-Type: {0}; Value-Type: {1}", type.ToString(), typeof(T));
return;
}
Expand All @@ -76,15 +80,19 @@ private protected override void CaptureMetric<T>(SentryMetric<T> metric) where T
}
catch (Exception e)
{
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.BeforeSend, DataCategory.TraceMetric);
_options.DiagnosticLogger?.LogError(e, "The BeforeSendMetric callback threw an exception. The Metric will be dropped.");
return;
}
}

if (configuredMetric is not null)
if (configuredMetric is null)
{
_batchProcessor.Enqueue(configuredMetric);
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.BeforeSend, DataCategory.TraceMetric);
Comment thread
jamescrosswell marked this conversation as resolved.
return;
}

_batchProcessor.Enqueue(configuredMetric);
}

/// <inheritdoc />
Expand Down
10 changes: 8 additions & 2 deletions src/Sentry/Internal/DefaultSentryStructuredLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ private protected override void CaptureLog(SentryLogLevel level, string template
}
catch (FormatException e)
{
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.Invalid, DataCategory.LogItem);
_options.DiagnosticLogger?.LogError(e, "Template string does not match the provided argument. The Log will be dropped.");
return;
}
Expand Down Expand Up @@ -70,6 +71,7 @@ private protected override void CaptureLog(SentryLogLevel level, string template
}
catch (Exception e)
{
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.BeforeSend, DataCategory.LogItem);
_options.DiagnosticLogger?.LogError(e, "The configureLog callback threw an exception. The Log will be dropped.");
return;
}
Expand All @@ -93,15 +95,19 @@ protected internal override void CaptureLog(SentryLog log)
}
catch (Exception e)
{
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.BeforeSend, DataCategory.LogItem);
_options.DiagnosticLogger?.LogError(e, "The BeforeSendLog callback threw an exception. The Log will be dropped.");
return;
}
}

if (configuredLog is not null)
if (configuredLog is null)
{
_batchProcessor.Enqueue(configuredLog);
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.BeforeSend, DataCategory.LogItem);
Comment thread
jamescrosswell marked this conversation as resolved.
return;
}

_batchProcessor.Enqueue(configuredLog);
}

/// <inheritdoc />
Expand Down
1 change: 1 addition & 0 deletions src/Sentry/Internal/DiscardReason.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace Sentry.Internal;
public static DiscardReason BufferOverflow = new("buffer_overflow");
public static DiscardReason CacheOverflow = new("cache_overflow");
public static DiscardReason EventProcessor = new("event_processor");
public static DiscardReason Invalid = new("invalid");
public static DiscardReason NetworkError = new("network_error");
public static DiscardReason QueueOverflow = new("queue_overflow");
public static DiscardReason SendError = new("send_error");
Expand Down
12 changes: 11 additions & 1 deletion src/Sentry/Internal/SentryEventHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ internal static class SentryEventHelper

foreach (var processor in processors)
{
processedEvent = processor.DoProcessEvent(processedEvent, effectiveHint);
try
{
processedEvent = processor.DoProcessEvent(processedEvent, effectiveHint);
}
catch (Exception e)
{
options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.EventProcessor, dataCategory);
options.LogError(e, "Event processor {0} threw an exception. The event will be dropped.", processor.GetType().Name);
return null;
}

if (processedEvent == null)
{
options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.EventProcessor, dataCategory);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
using Sentry.Android.Extensions;
using Sentry.Extensibility;

namespace Sentry.Android.Callbacks;

internal class BeforeBreadcrumbCallback : JavaObject, JavaSdk.SentryOptions.IBeforeBreadcrumbCallback
{
private readonly Func<Breadcrumb, SentryHint, Breadcrumb?> _beforeBreadcrumb;
private readonly SentryOptions _options;

public BeforeBreadcrumbCallback(Func<Breadcrumb, SentryHint, Breadcrumb?> beforeBreadcrumb)
public BeforeBreadcrumbCallback(
Func<Breadcrumb, SentryHint, Breadcrumb?> beforeBreadcrumb,
SentryOptions options)
{
_beforeBreadcrumb = beforeBreadcrumb;
_options = options;
}

public JavaSdk.Breadcrumb? Execute(JavaSdk.Breadcrumb b, JavaSdk.Hint h)
Expand All @@ -18,7 +23,17 @@ public BeforeBreadcrumbCallback(Func<Breadcrumb, SentryHint, Breadcrumb?> before

var breadcrumb = b.ToBreadcrumb();
var hint = h.ToHint();
var result = _beforeBreadcrumb.Invoke(breadcrumb, hint);

Breadcrumb? result;
try
{
result = _beforeBreadcrumb.Invoke(breadcrumb, hint);
}
catch (Exception exception)
{
_options.LogError(exception, "BeforeBreadcrumb callback failed.");
return null;
}

if (result == breadcrumb)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Sentry/Platforms/Android/SentrySdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private static void InitSentryAndroidSdk(SentryOptions options)

if (options.BeforeBreadcrumbInternal is { } beforeBreadcrumb)
{
o.BeforeBreadcrumb = new BeforeBreadcrumbCallback(beforeBreadcrumb);
o.BeforeBreadcrumb = new BeforeBreadcrumbCallback(beforeBreadcrumb, options);
}

// These options we have behind feature flags
Expand Down
12 changes: 11 additions & 1 deletion src/Sentry/Platforms/Cocoa/SentrySdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,17 @@ private static void InitSentryCocoaSdk(SentryOptions options)
// See https://github.com/getsentry/sentry-cocoa/issues/2325
var hint = new SentryHint();
var breadcrumb = b.ToBreadcrumb(options.DiagnosticLogger);
var result = beforeBreadcrumb(breadcrumb, hint)?.ToCocoaBreadcrumb();

CocoaSdk.SentryObjCBreadcrumb? result;
try
{
result = beforeBreadcrumb(breadcrumb, hint)?.ToCocoaBreadcrumb();
}
catch (Exception ex)
{
options.LogError(ex, "BeforeBreadcrumb callback failed.");
result = null;
}

// Note: Nullable result is allowed but delegate is generated incorrectly
// See https://github.com/xamarin/xamarin-macios/issues/15299#issuecomment-1201863294
Expand Down
15 changes: 12 additions & 3 deletions src/Sentry/Scope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -335,15 +335,24 @@ public void AddBreadcrumb(Breadcrumb breadcrumb, SentryHint hint)
{
hint.AddAttachmentsFromScope(this);

if (beforeBreadcrumb(breadcrumb, hint) is { } processedBreadcrumb)
Breadcrumb? processedBreadcrumb;
try
{
breadcrumb = processedBreadcrumb;
processedBreadcrumb = beforeBreadcrumb(breadcrumb, hint);
}
else
catch (Exception e)
{
Options.LogError(e, "BeforeBreadcrumb callback failed.");
return;
}

if (processedBreadcrumb is null)
{
// Callback returned null, which means the breadcrumb should be dropped
return;
}

breadcrumb = processedBreadcrumb;
}

if (Options.MaxBreadcrumbs <= 0)
Expand Down
13 changes: 12 additions & 1 deletion src/Sentry/SentryClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,18 @@ public void CaptureTransaction(SentryTransaction transaction, Scope? scope, Sent
var processedTransaction = transaction;
foreach (var processor in scope.GetAllTransactionProcessors())
{
processedTransaction = processor.DoProcessTransaction(transaction, hint);
try
{
processedTransaction = processor.DoProcessTransaction(transaction, hint);
Comment thread
jamescrosswell marked this conversation as resolved.
Outdated
}
catch (Exception e)
{
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.EventProcessor, DataCategory.Transaction);
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.EventProcessor, DataCategory.Span, spanCount);
_options.LogError(e, "Transaction processor {0} threw an exception. The transaction will be dropped.", processor.GetType().Name);
return;
}

if (processedTransaction == null) // Rejected transaction
{
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.EventProcessor, DataCategory.Transaction);
Expand Down
31 changes: 31 additions & 0 deletions test/Sentry.Extensions.Logging.Tests/SentryLoggerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,37 @@ public void LogCritical_NotMatchingFilter_CapturesEvent()
.CaptureEvent(Arg.Any<SentryEvent>());
}

[Fact]
public void LogCritical_FilterThrows_CapturesEventAndLogsError()
{
var exception = new InvalidOperationException("filter failed");
_fixture.Options.AddLogEntryFilter((_, _, _, _) => throw exception);
_fixture.Options.AddDiagnosticLoggerSubstitute();

var sut = _fixture.GetSut();

sut.LogCritical("message");

_ = _fixture.Hub.Received(1).CaptureEvent(Arg.Any<SentryEvent>());
_fixture.Options.ReceivedLogError(exception,
"The {0} log filter callback failed. The log entry will not be filtered.",
nameof(DelegateLogEntryFilter));
}

[Fact]
public void LogCritical_FilterThrows_OtherFiltersStillApply()
{
_fixture.Options.AddLogEntryFilter((_, _, _, _) => throw new InvalidOperationException("filter failed"));
_fixture.Options.AddLogEntryFilter((_, _, _, _) => true);
_fixture.Options.AddDiagnosticLoggerSubstitute();

var sut = _fixture.GetSut();

sut.LogCritical("message");

_ = _fixture.Hub.DidNotReceive().CaptureEvent(Arg.Any<SentryEvent>());
}

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