From f2abba1f8bc60683dd2fec2ce854df721d47c0b1 Mon Sep 17 00:00:00 2001 From: Alexey Golub Date: Fri, 20 Nov 2020 20:05:00 +0200 Subject: [PATCH] Hook for BaseScope.Apply (#596) --- src/Sentry.Protocol/BaseScopeExtensions.cs | 35 +-------------- .../DefaultSentryScopeProcessor.cs | 45 +++++++++++++++++++ src/Sentry.Protocol/IScopeOptions.cs | 5 +++ src/Sentry.Protocol/ISentryScopeProcessor.cs | 7 +++ src/Sentry/Internal/SentryScopeManager.cs | 10 ++++- src/Sentry/SentryOptions.cs | 3 ++ 6 files changed, 70 insertions(+), 35 deletions(-) create mode 100644 src/Sentry.Protocol/DefaultSentryScopeProcessor.cs create mode 100644 src/Sentry.Protocol/ISentryScopeProcessor.cs diff --git a/src/Sentry.Protocol/BaseScopeExtensions.cs b/src/Sentry.Protocol/BaseScopeExtensions.cs index 284c9ef63e..f9ed0383db 100644 --- a/src/Sentry.Protocol/BaseScopeExtensions.cs +++ b/src/Sentry.Protocol/BaseScopeExtensions.cs @@ -2,7 +2,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; -using System.Linq; using Sentry.Protocol; // ReSharper disable once CheckNamespace @@ -308,38 +307,8 @@ public static void Apply(this BaseScope from, BaseScope to) /// The state object to apply. public static void Apply(this BaseScope scope, object state) { - switch (state) - { - case string scopeString: - // TODO: find unique key to support multiple single-string scopes - scope.SetTag("scope", scopeString); - break; - case IEnumerable> keyValStringString: - scope.SetTags(keyValStringString - .Where(kv => !string.IsNullOrEmpty(kv.Value))); - break; - case IEnumerable> keyValStringObject: - { - scope.SetTags(keyValStringObject - .Select(k => new KeyValuePair( - k.Key, - k.Value?.ToString())) - .Where(kv => !string.IsNullOrEmpty(kv.Value))); - - break; - } -#if HAS_VALUE_TUPLE - case ValueTuple tupleStringString: - if (!string.IsNullOrEmpty(tupleStringString.Item2)) - { - scope.SetTag(tupleStringString.Item1, tupleStringString.Item2); - } - break; -#endif - default: - scope.SetExtra("state", state); - break; - } + var processor = scope.ScopeOptions.SentryScopeProcessor ?? new DefaultSentryScopeProcessor(); + processor.Apply(scope, state); } } } diff --git a/src/Sentry.Protocol/DefaultSentryScopeProcessor.cs b/src/Sentry.Protocol/DefaultSentryScopeProcessor.cs new file mode 100644 index 0000000000..1ffcf7235e --- /dev/null +++ b/src/Sentry.Protocol/DefaultSentryScopeProcessor.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Sentry.Protocol +{ + public class DefaultSentryScopeProcessor : ISentryScopeProcessor + { + public void Apply(BaseScope scope, object state) + { + switch (state) + { + case string scopeString: + // TODO: find unique key to support multiple single-string scopes + scope.SetTag("scope", scopeString); + break; + case IEnumerable> keyValStringString: + scope.SetTags(keyValStringString + .Where(kv => !string.IsNullOrEmpty(kv.Value))); + break; + case IEnumerable> keyValStringObject: + { + scope.SetTags(keyValStringObject + .Select(k => new KeyValuePair( + k.Key, + k.Value?.ToString())) + .Where(kv => !string.IsNullOrEmpty(kv.Value))); + + break; + } +#if HAS_VALUE_TUPLE + case ValueTuple tupleStringString: + if (!string.IsNullOrEmpty(tupleStringString.Item2)) + { + scope.SetTag(tupleStringString.Item1, tupleStringString.Item2); + } + break; +#endif + default: + scope.SetExtra("state", state); + break; + } + } + } +} diff --git a/src/Sentry.Protocol/IScopeOptions.cs b/src/Sentry.Protocol/IScopeOptions.cs index 4f7e0fffc9..b992497c4b 100644 --- a/src/Sentry.Protocol/IScopeOptions.cs +++ b/src/Sentry.Protocol/IScopeOptions.cs @@ -7,6 +7,11 @@ namespace Sentry.Protocol /// public interface IScopeOptions { + /// + /// Configured scope processor. + /// + ISentryScopeProcessor SentryScopeProcessor { get; set; } + /// /// Gets or sets the maximum breadcrumbs. /// diff --git a/src/Sentry.Protocol/ISentryScopeProcessor.cs b/src/Sentry.Protocol/ISentryScopeProcessor.cs new file mode 100644 index 0000000000..17ad0c2e7b --- /dev/null +++ b/src/Sentry.Protocol/ISentryScopeProcessor.cs @@ -0,0 +1,7 @@ +namespace Sentry.Protocol +{ + public interface ISentryScopeProcessor + { + void Apply(BaseScope scope, object state); + } +} diff --git a/src/Sentry/Internal/SentryScopeManager.cs b/src/Sentry/Internal/SentryScopeManager.cs index 68fc83b964..f5d6994981 100644 --- a/src/Sentry/Internal/SentryScopeManager.cs +++ b/src/Sentry/Internal/SentryScopeManager.cs @@ -58,9 +58,15 @@ public IDisposable PushScope(TState state) if (scope.Key.Locked) { - // TODO: keep state on current scope? _options?.DiagnosticLogger?.LogDebug("Locked scope. No new scope pushed."); - return DisabledHub.Instance; + + // Apply to current scope + if (state != null) + { + scope.Key.Apply(state); + } + + return new ScopeSnapshot(_options, currentScopeAndClientStack, this); } var clonedScope = scope.Key.Clone(); diff --git a/src/Sentry/SentryOptions.cs b/src/Sentry/SentryOptions.cs index 77fb538011..300fb90a02 100644 --- a/src/Sentry/SentryOptions.cs +++ b/src/Sentry/SentryOptions.cs @@ -60,6 +60,9 @@ public class SentryOptions : IScopeOptions internal ISentryHttpClientFactory SentryHttpClientFactory { get; set; } + /// + public ISentryScopeProcessor SentryScopeProcessor { get; set; } = new DefaultSentryScopeProcessor(); + /// /// A list of namespaces (or prefixes) considered not part of application code ///