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
///