Skip to content
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

Data from Scope in options should be applied on each request #1270

Merged
merged 20 commits into from
Nov 1, 2021
Merged
Show file tree
Hide file tree
Changes from 11 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

### Fixes

- ASP.NET Core: Data from Scope in options should be applied on each request ([#1270](https://github.com/getsentry/sentry-dotnet/pull/1270))
- Add missing `ConfigureAwaits(false)` for `async using` ([#1276](https://github.com/getsentry/sentry-dotnet/pull/1276))

## 3.10.0

### Features
Expand Down
26 changes: 20 additions & 6 deletions src/Sentry.AspNetCore/SentryMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ internal class SentryMiddleware
{
private readonly RequestDelegate _next;
private readonly Func<IHub> _getHub;
private IHub? _previousHub;
private readonly SentryAspNetCoreOptions _options;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly ILogger<SentryMiddleware> _logger;
Expand Down Expand Up @@ -56,13 +57,9 @@ public SentryMiddleware(
_next = next ?? throw new ArgumentNullException(nameof(next));
_getHub = getHub ?? throw new ArgumentNullException(nameof(getHub));
_options = options.Value;
var hub = _getHub();
foreach (var callback in _options.ConfigureScopeCallbacks)
{
hub.ConfigureScope(callback);
}
_hostingEnvironment = hostingEnvironment;
_logger = logger;
_previousHub = null;
}

/// <summary>
Expand Down Expand Up @@ -104,7 +101,16 @@ public async Task InvokeAsync(HttpContext context)
// In case of event, all data made available through the HTTP Context at the time of the
// event creation will be sent to Sentry

scope.OnEvaluating += (_, _) => PopulateScope(context, scope);
scope.OnEvaluating += (_, _) =>
{
if (!object.ReferenceEquals(hub, _previousHub))
lucas-zimerman marked this conversation as resolved.
Show resolved Hide resolved
{
SyncOptionsScope(hub);
_previousHub = hub;
}

PopulateScope(context, scope);
};
});

try
Expand Down Expand Up @@ -156,6 +162,14 @@ void CaptureException(Exception e, string mechanism)
}
}

private void SyncOptionsScope(IHub newHub)
{
foreach (var callback in _options.ConfigureScopeCallbacks)
{
newHub.ConfigureScope(callback);
}
}

internal void PopulateScope(HttpContext context, Scope scope)
{
scope.Sdk.Name = Constants.SdkName;
Expand Down
3 changes: 3 additions & 0 deletions test/Sentry.AspNetCore.Tests/MiddlewareLoggerIntegration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public Fixture()
};
loggingOptions.InitializeSdk = false;

Client.When(client => client.CaptureEvent(Arg.Any<SentryEvent>(), Arg.Any<Scope>()))
.Do(callback => callback.Arg<Scope>().Evaluate());

var hub = new Hub(new SentryOptions { Dsn = DsnSamples.ValidDsnWithSecret });
hub.BindClient(Client);
Hub = hub;
Expand Down
88 changes: 88 additions & 0 deletions test/Sentry.AspNetCore.Tests/SentryMiddlewareTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Diagnostics;
#if NETCOREAPP2_1 || NET461
Expand Down Expand Up @@ -31,9 +33,17 @@ private class Fixture
public ILogger<SentryMiddleware> Logger { get; set; } = Substitute.For<ILogger<SentryMiddleware>>();
public HttpContext HttpContext { get; set; } = Substitute.For<HttpContext>();
public IFeatureCollection FeatureCollection { get; set; } = Substitute.For<IFeatureCollection>();
public Scope Scope { get; set; }

public Fixture()
{
Scope = new();
Hub.When(hub => hub.ConfigureScope(Arg.Any<Action<Scope>>()))
.Do(callback => callback.Arg<Action<Scope>>().Invoke(Scope));

Hub.When(hub => hub.CaptureEvent(Arg.Any<SentryEvent>(), Arg.Any<Scope>()))
.Do(_ => Scope.Evaluate());

HubAccessor = () => Hub;
_ = Hub.IsEnabled.Returns(true);
_ = Hub.StartTransaction("", "").ReturnsForAnyArgs(new TransactionTracer(Hub, "test", "test"));
Expand Down Expand Up @@ -521,5 +531,83 @@ public async Task InvokeAsync_FlushBeforeRequestCompletedTrue_RespectsTimeout()

await _fixture.Hub.Received(1).FlushAsync(timeout);
}

[Fact]
public async Task InvokeAsync_ScopeNotPopulated_CopyOptionsToScope()
{
// Arrange
var expectedAction = new Action<Scope>(scope => scope.SetTag("A", "B"));
_fixture.Options.ConfigureScope(expectedAction);
_fixture.RequestDelegate = _ => throw new Exception();
var sut = _fixture.GetSut();

// Act
try
{
await sut.InvokeAsync(_fixture.HttpContext);
}
catch { }
SimonCropp marked this conversation as resolved.
Show resolved Hide resolved

// Assert
_fixture.Hub.Received(1).ConfigureScope(Arg.Is(expectedAction));
}

[Fact]
public async Task InvokeAsync_SameMiddleWareWithSameHubs_CopyOptionsOnce()
{
// Arrange
var expectedAction = new Action<Scope>(scope => scope.SetTag("A", "B"));
_fixture.RequestDelegate = _ => throw new Exception();
_fixture.Options.ConfigureScope(expectedAction);
var sut = _fixture.GetSut();

// Act
try
{
await sut.InvokeAsync(_fixture.HttpContext);
}
catch { }
try
{
await sut.InvokeAsync(_fixture.HttpContext);
}
catch { }

// Assert
_fixture.Hub.Received(1).ConfigureScope(Arg.Is(expectedAction));
}

[Fact]
public async Task InvokeAsync_SameMiddleWareWithDifferentHubs_CopyOptionsToAllHubs()
{
// Arrange
var firstHub = _fixture.Hub;
_fixture.RequestDelegate = _ => throw new Exception();
var expectedAction = new Action<Scope>(scope => scope.SetTag("A", "B"));
_fixture.Options.ConfigureScope(expectedAction);
var sut = _fixture.GetSut();

// Act
try
{
await sut.InvokeAsync(_fixture.HttpContext);
}
catch { }
// Replacing the Hub
// Arrange
var secondHub = new Fixture().Hub;
_fixture.Hub = secondHub;

// Act
try
{
await sut.InvokeAsync(_fixture.HttpContext);
}
catch { }

// Assert
firstHub.Received(1).ConfigureScope(Arg.Is(expectedAction));
secondHub.Received(1).ConfigureScope(Arg.Is(expectedAction));
}
}
}