Skip to content

Commit 6e50eaa

Browse files
authored
Add non allocating ConfigureScope overload (#4244)
1 parent d47d66f commit 6e50eaa

34 files changed

+307
-77
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Features
6+
7+
- Added non-allocating `ConfigureScope` and `ConfigureScopeAsync` overloads ([#4244](https://github.com/getsentry/sentry-dotnet/pull/4244))
8+
59
### Fixes
610

711
- The HTTP instrumentation uses the span created for the outgoing request in the sentry-trace header, fixing the parent-child relationship between client and server ([#4264](https://github.com/getsentry/sentry-dotnet/pull/4264))

src/Sentry.AspNetCore/SentryMiddleware.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
118118
context.Items.TryAdd(BaggageHeaderItemKey, baggageHeader);
119119
context.Items.TryAdd(TransactionContextItemKey, transactionContext);
120120

121-
hub.ConfigureScope(scope =>
121+
hub.ConfigureScope(static (scope, arg) =>
122122
{
123123
// At the point lots of stuff from the request are not yet filled
124124
// Identity for example is added later on in the pipeline
@@ -131,16 +131,16 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
131131
// when the event fires. Use `activeScope`, not `scope` or `hub`.
132132
scope.OnEvaluating += (_, activeScope) =>
133133
{
134-
SyncOptionsScope(activeScope);
135-
PopulateScope(context, activeScope);
134+
arg.middleware.SyncOptionsScope(activeScope);
135+
arg.middleware.PopulateScope(arg.context, activeScope);
136136
};
137-
});
137+
}, (middleware: this, context));
138138

139139
// Pre-create the Sentry Event ID and save it on the scope it so it's available throughout the pipeline,
140140
// even if there's no event actually being sent to Sentry. This allows for things like a custom exception
141141
// handler page to access the event ID, enabling user feedback, etc.
142142
var eventId = SentryId.Create();
143-
hub.ConfigureScope(scope => scope.LastEventId = eventId);
143+
hub.ConfigureScope(static (scope, eventId) => scope.LastEventId = eventId, eventId);
144144

145145
try
146146
{
@@ -167,7 +167,7 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
167167
{
168168
// The middleware pipeline finishes up before the Otel Activity.OnEnd callback is invoked so we need
169169
// so save a copy of the scope that can be restored by our SentrySpanProcessor
170-
hub.ConfigureScope(scope => activity.SetFused(scope));
170+
hub.ConfigureScope(static (scope, activity) => activity.SetFused(scope), activity);
171171
}
172172

173173
// When an exception was handled by other component (i.e: UseExceptionHandler feature).
@@ -179,12 +179,12 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
179179
"The web server likely returned a customized error page as a result of this exception.";
180180

181181
#if NET6_0_OR_GREATER
182-
hub.ConfigureScope(scope =>
182+
hub.ConfigureScope(static (scope, arg) =>
183183
{
184184
scope.ExceptionProcessors.Add(
185-
new ExceptionHandlerFeatureProcessor(originalMethod, exceptionFeature)
185+
new ExceptionHandlerFeatureProcessor(arg.originalMethod, arg.exceptionFeature)
186186
);
187-
});
187+
}, (originalMethod, exceptionFeature));
188188
#endif
189189
CaptureException(exceptionFeature.Error, eventId, "IExceptionHandlerFeature", description);
190190
}

src/Sentry.AspNetCore/SentryTracingMiddleware.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,7 @@ public async Task InvokeAsync(HttpContext context)
130130

131131
// Expose the transaction on the scope so that the user
132132
// can retrieve it and start child spans off of it.
133-
hub.ConfigureScope(scope =>
134-
{
135-
scope.Transaction = transaction;
136-
});
133+
hub.ConfigureScope(static (scope, transaction) => scope.Transaction = transaction, transaction);
137134

138135
Exception? exception = null;
139136
try

src/Sentry.Extensions.Logging/SentryLoggerProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ internal SentryLoggerProvider(
4848
if (hub.IsEnabled)
4949
{
5050
_scope = hub.PushScope();
51-
hub.ConfigureScope(s =>
51+
hub.ConfigureScope(static s =>
5252
{
5353
if (s.Sdk is { } sdk)
5454
{

src/Sentry.OpenTelemetry/AspNetCoreEnricher.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ public void Enrich(ISpan span, Activity activity, IHub hub, SentryOptions? optio
1010
{
1111
if (options?.SendDefaultPii is true)
1212
{
13-
hub.ConfigureScope(scope =>
13+
hub.ConfigureScope(static (scope, enricher) =>
1414
{
15-
if (!scope.HasUser() && _userFactory.Create() is { } user)
15+
if (!scope.HasUser() && enricher._userFactory.Create() is { } user)
1616
{
1717
scope.User = user;
1818
}
19-
});
19+
}, this);
2020
}
2121
}
2222
}

src/Sentry.OpenTelemetry/SentrySpanProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ private void CreateRootSpan(Activity data)
172172
tracer.Contexts.Trace.Origin = OpenTelemetryOrigin;
173173
tracer.StartTimestamp = data.StartTimeUtc;
174174
}
175-
_hub.ConfigureScope(scope => scope.Transaction = transaction);
175+
_hub.ConfigureScope(static (scope, transaction) => scope.Transaction = transaction, transaction);
176176
transaction.SetFused(data);
177177
_map[data.SpanId] = transaction;
178178
}

src/Sentry/Extensibility/DisabledHub.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,23 @@ public void ConfigureScope(Action<Scope> configureScope)
3030
{
3131
}
3232

33+
/// <summary>
34+
/// No-Op.
35+
/// </summary>
36+
public void ConfigureScope<TArg>(Action<Scope, TArg> configureScope, TArg arg)
37+
{
38+
}
39+
3340
/// <summary>
3441
/// No-Op.
3542
/// </summary>
3643
public Task ConfigureScopeAsync(Func<Scope, Task> configureScope) => Task.CompletedTask;
3744

45+
/// <summary>
46+
/// No-Op.
47+
/// </summary>
48+
public Task ConfigureScopeAsync<TArg>(Func<Scope, TArg, Task> configureScope, TArg arg) => Task.CompletedTask;
49+
3850
/// <summary>
3951
/// No-Op.
4052
/// </summary>

src/Sentry/Extensibility/HubAdapter.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,27 @@ private HubAdapter() { }
3939
public void ConfigureScope(Action<Scope> configureScope)
4040
=> SentrySdk.ConfigureScope(configureScope);
4141

42+
/// <summary>
43+
/// Forwards the call to <see cref="SentrySdk"/>.
44+
/// </summary>
45+
[DebuggerStepThrough]
46+
public void ConfigureScope<TArg>(Action<Scope, TArg> configureScope, TArg arg)
47+
=> SentrySdk.ConfigureScope(configureScope, arg);
48+
4249
/// <summary>
4350
/// Forwards the call to <see cref="SentrySdk"/>.
4451
/// </summary>
4552
[DebuggerStepThrough]
4653
public Task ConfigureScopeAsync(Func<Scope, Task> configureScope)
4754
=> SentrySdk.ConfigureScopeAsync(configureScope);
4855

56+
/// <summary>
57+
/// Forwards the call to <see cref="SentrySdk"/>.
58+
/// </summary>
59+
[DebuggerStepThrough]
60+
public Task ConfigureScopeAsync<TArg>(Func<Scope, TArg, Task> configureScope, TArg arg)
61+
=> SentrySdk.ConfigureScopeAsync(configureScope, arg);
62+
4963
/// <summary>
5064
/// Forwards the call to <see cref="SentrySdk"/>.
5165
/// </summary>

src/Sentry/HubExtensions.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,11 @@ public static ITransactionTracer StartTransaction(
5656
/// </summary>
5757
public static ISpan StartSpan(this IHub hub, string operation, string description)
5858
{
59-
ITransactionTracer? currentTransaction = null;
60-
hub.ConfigureScope(s => currentTransaction = s.Transaction);
61-
return currentTransaction is { } transaction
59+
return hub.GetTransaction() is { } transaction
6260
? transaction.StartChild(operation, description)
6361
: hub.StartTransaction(operation, description); // this is actually in the wrong order but changing it may break other things
6462
}
6563

66-
6764
/// <summary>
6865
/// Adds a breadcrumb to the current scope.
6966
/// </summary>
@@ -158,8 +155,8 @@ public static void AddBreadcrumb(
158155
}
159156

160157
hub.ConfigureScope(
161-
s => s.AddBreadcrumb(breadcrumb, hint ?? new SentryHint())
162-
);
158+
static (s, arg) => s.AddBreadcrumb(arg.breadcrumb, arg.hint ?? new SentryHint()),
159+
(breadcrumb, hint));
163160
}
164161

165162
/// <summary>
@@ -175,13 +172,13 @@ public static void AddBreadcrumb(
175172
/// like Loggers which guarantee log messages are not lost.
176173
/// </remarks>
177174
[EditorBrowsable(EditorBrowsableState.Never)]
178-
public static void LockScope(this IHub hub) => hub.ConfigureScope(c => c.Locked = true);
175+
public static void LockScope(this IHub hub) => hub.ConfigureScope(static s => s.Locked = true);
179176

180177
/// <summary>
181178
/// Unlocks the current scope to allow subsequent calls to <see cref="ISentryScopeManager.PushScope"/> create new scopes.
182179
/// </summary>
183180
[EditorBrowsable(EditorBrowsableState.Never)]
184-
public static void UnlockScope(this IHub hub) => hub.ConfigureScope(c => c.Locked = false);
181+
public static void UnlockScope(this IHub hub) => hub.ConfigureScope(static s => s.Locked = false);
185182

186183
private sealed class LockedScope : IDisposable
187184
{
@@ -247,6 +244,11 @@ internal static ITransactionTracer StartTransaction(
247244

248245
internal static ITransactionTracer? GetTransaction(this IHub hub)
249246
{
247+
if (hub is Hub fullHub)
248+
{
249+
return fullHub.ScopeManager.GetCurrent().Key.Transaction;
250+
}
251+
250252
ITransactionTracer? transaction = null;
251253
hub.ConfigureScope(scope => transaction = scope.Transaction);
252254
return transaction;

src/Sentry/ISentryScopeManager.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,33 @@ namespace Sentry;
1010
public interface ISentryScopeManager
1111
{
1212
/// <summary>
13-
/// Configures the current scope.
13+
/// Configures the current scope through the callback.
1414
/// </summary>
15-
/// <param name="configureScope">The configure scope.</param>
15+
/// <param name="configureScope">The configure scope callback.</param>
1616
public void ConfigureScope(Action<Scope> configureScope);
1717

1818
/// <summary>
19-
/// Asynchronously configure the current scope.
19+
/// Configures the current scope through the callback.
2020
/// </summary>
21-
/// <param name="configureScope">The configure scope.</param>
21+
/// <param name="configureScope">The configure scope callback.</param>
22+
/// <param name="arg">The argument to pass to the configure scope callback.</param>
23+
public void ConfigureScope<TArg>(Action<Scope, TArg> configureScope, TArg arg);
24+
25+
/// <summary>
26+
/// Configures the current scope through the callback asynchronously.
27+
/// </summary>
28+
/// <param name="configureScope">The configure scope callback.</param>
2229
/// <returns>A task that completes when the callback is done or a completed task if the SDK is disabled.</returns>
2330
public Task ConfigureScopeAsync(Func<Scope, Task> configureScope);
2431

32+
/// <summary>
33+
/// Configures the current scope through the callback asynchronously.
34+
/// </summary>
35+
/// <param name="configureScope">The configure scope callback.</param>
36+
/// <param name="arg">The argument to pass to the configure scope callback.</param>
37+
/// <returns>A task that completes when the callback is done or a completed task if the SDK is disabled.</returns>
38+
public Task ConfigureScopeAsync<TArg>(Func<Scope, TArg, Task> configureScope, TArg arg);
39+
2540
/// <summary>
2641
/// Sets a tag on the current scope.
2742
/// </summary>

0 commit comments

Comments
 (0)