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

Feat: Enhance GCP Integraction. #1286

Merged
merged 9 commits into from
Oct 29, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Features

- Enhance GCP Integraction with performance monitoring and revision number ([#1286](https://github.com/getsentry/sentry-dotnet/pull/1286))

### Fixes

- Add missing `ConfigureAwaits(false)` for `async using` ([#1276](https://github.com/getsentry/sentry-dotnet/pull/1276))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"Sentry": {
"Dsn": "https://eb18e953812b41c3aeb042e666fd3b5c@o447951.ingest.sentry.io/5428537",
"MaxRequestBodySize": "Always",
"SendDefaultPii": true
"SendDefaultPii": true,
"TracesSampleRate": 1
}
}
10 changes: 8 additions & 2 deletions src/Sentry.AspNetCore/Extensions/HttpContextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ internal static class HttpContextExtensions
{
public static string? TryGetRouteTemplate(this HttpContext context)
{

#if !NETSTANDARD2_0 // endpoint routing is only supported after ASP.NET Core 3.0
// Requires .UseRouting()/.UseEndpoints()
var endpoint = context.Features.Get<IEndpointFeature?>()?.Endpoint as RouteEndpoint;
Expand All @@ -24,7 +23,14 @@ internal static class HttpContextExtensions
return formattedRoute;
}
#endif
return LegacyRouteFormat(context);
if (LegacyRouteFormat(context) is { } legacyFormat)
{
return legacyFormat;
}

var sentryRouteName = context.Features.Get<ISentryRouteName>();

return sentryRouteName?.GetRouteName();
}

// Internal for testing.
Expand Down
7 changes: 7 additions & 0 deletions src/Sentry.AspNetCore/ISentryRouteName.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Sentry.AspNetCore
{
internal interface ISentryRouteName
{
string? GetRouteName();
}
}
1 change: 1 addition & 0 deletions src/Sentry.Extensions.Logging/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
[assembly: InternalsVisibleTo("Sentry.AspNetCore, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
[assembly: InternalsVisibleTo("Sentry.AspNetCore.Grpc, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
[assembly: InternalsVisibleTo("Sentry.AspNetCore.Grpc.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
[assembly: InternalsVisibleTo("Sentry.Google.Cloud.Functions.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
52 changes: 52 additions & 0 deletions src/Sentry.Google.Cloud.Functions/SentryStartup.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
using System;
using System.Threading.Tasks;
using Google.Cloud.Functions.Hosting;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Sentry;
using Sentry.AspNetCore;
using Sentry.Extensibility;
using Sentry.Internal;
using Sentry.Reflection;

namespace Google.Cloud.Functions.Framework
Expand All @@ -15,6 +20,7 @@ namespace Google.Cloud.Functions.Framework
/// </summary>
public class SentryStartup : FunctionsStartup
{

/// <summary>
/// Configure Sentry logging.
/// </summary>
Expand All @@ -25,6 +31,17 @@ public override void ConfigureLogging(WebHostBuilderContext context, ILoggingBui

logging.Services.AddSingleton<ISentryEventProcessor, SentryGoogleCloudFunctionEventProcessor>();

ReleaseLocator.FromEnvironmentLazy = new Lazy<string?>(() =>
{
var environmentRelease = ReleaseLocator.LocateFromEnvironment();
if (environmentRelease != null &&
Environment.GetEnvironmentVariable("K_REVISION") is { } revision)
{
environmentRelease = $"{environmentRelease}+{revision}";
}
return environmentRelease;
});

// TODO: refactor this with SentryWebHostBuilderExtensions
var section = context.Configuration.GetSection("Sentry");
logging.Services.Configure<SentryAspNetCoreOptions>(section);
Expand Down Expand Up @@ -56,6 +73,16 @@ public override void ConfigureServices(WebHostBuilderContext context, IServiceCo
services.AddTransient<IStartupFilter, SentryStartupFilter>();
}

/// <summary>
/// Configure Sentry middlewares./>.
/// </summary>
public override void Configure(WebHostBuilderContext context, IApplicationBuilder app)
{
base.Configure(context, app);
app.UseMiddleware<SentryGoogleCloudFunctionsMiddleware>();
app.UseSentryTracing();
}

private class SentryGoogleCloudFunctionEventProcessor : ISentryEventProcessor
{
private static readonly SdkVersion NameAndVersion
Expand All @@ -78,5 +105,30 @@ public SentryEvent Process(SentryEvent @event)
return @event;
}
}

private class SentryGoogleCloudFunctionsMiddleware
{
private readonly RequestDelegate _next;

public SentryGoogleCloudFunctionsMiddleware(RequestDelegate next) => _next = next;

/// <summary>
/// Handles the <see cref="HttpContext"/>.
/// </summary>
public async Task InvokeAsync(HttpContext httpContext)
{
httpContext.Features.Set<ISentryRouteName>(new SentryGoogleCloudFunctionsRouteName());
await _next(httpContext).ConfigureAwait(false);
}
}

private class SentryGoogleCloudFunctionsRouteName : ISentryRouteName
{
private static readonly Lazy<string?> RouteName = new Lazy<string?>(() => Environment.GetEnvironmentVariable("K_SERVICE"));

// K_SERVICE is where the name of the FAAS is stored.
// It'll return null. if GCP Function is running locally.
public string? GetRouteName() => RouteName.Value;
}
}
}
2 changes: 1 addition & 1 deletion src/Sentry/Internal/ReleaseLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Sentry.Internal
{
internal static class ReleaseLocator
{
private static readonly Lazy<string?> FromEnvironmentLazy = new(LocateFromEnvironment);
internal static Lazy<string?> FromEnvironmentLazy = new(LocateFromEnvironment);

// Internal for testing
internal static string? LocateFromEnvironment() =>
Expand Down
2 changes: 2 additions & 0 deletions src/Sentry/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
[assembly: InternalsVisibleTo("Sentry.AspNetCore, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
[assembly: InternalsVisibleTo("Sentry.AspNetCore.Grpc, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
[assembly: InternalsVisibleTo("Sentry.AspNetCore.Grpc.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
[assembly: InternalsVisibleTo("Sentry.Google.Cloud.Functions, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
[assembly: InternalsVisibleTo("Sentry.Google.Cloud.Functions.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
[assembly: InternalsVisibleTo("Sentry.DiagnosticSource, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
[assembly: InternalsVisibleTo("Sentry.DiagnosticSource.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
[assembly: InternalsVisibleTo("Sentry.Extensions.Logging, PublicKey=002400000480000094000000060200000024000052534131000400000100010059964a931488bcdbd14657f1ee0df32df61b57b3d14d7290c262c2cc9ddaad6ec984044f761f778e1823049d2cb996a4f58c8ea5b46c37891414cb34b4036b1c178d7b582289d2eef3c0f1e9b692c229a306831ee3d371d9e883f0eb0f74aeac6c6ab8c85fd1ec04b267e15a31532c4b4e2191f5980459db4dce0081f1050fb8")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#if !NETCOREAPP2_1
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using NSubstitute;
using Sentry.AspNetCore.Extensions;
using Xunit;

Expand Down Expand Up @@ -192,6 +193,37 @@ public void LegacyRouteFormat_ValidRoutes_MatchPreviousImplementationResult(stri
// Assert
Assert.Equal(LegacyFormat(controller, action, area), filteredRoute);
}

[Fact]
public void TryGetRouteTemplate_NoRoute_NullOutput()
{
// Arrange
var httpContext = _fixture.GetSut();

// Act
var filteredRoute = HttpContextExtensions.TryGetRouteTemplate(httpContext);

// Assert
Assert.Null(filteredRoute);
}

[Fact]
public void TryGetRouteTemplate_WithSentryRouteName_RouteName()
{
// Arrange
var sentryRouteName = Substitute.For<ISentryRouteName>();
var httpContext = _fixture.GetSut();
var expectedName = "abc";
sentryRouteName.GetRouteName().Returns(expectedName);
httpContext.Features.Set(sentryRouteName);

// Act
var filteredRoute = HttpContextExtensions.TryGetRouteTemplate(httpContext);

// Assert
Assert.Equal(expectedName, filteredRoute);
}

}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Google.Cloud.Functions.Framework
public class SentryStartup : Google.Cloud.Functions.Hosting.FunctionsStartup
{
public SentryStartup() { }
public override void Configure(Microsoft.AspNetCore.Hosting.WebHostBuilderContext context, Microsoft.AspNetCore.Builder.IApplicationBuilder app) { }
public override void ConfigureLogging(Microsoft.AspNetCore.Hosting.WebHostBuilderContext context, Microsoft.Extensions.Logging.ILoggingBuilder logging) { }
public override void ConfigureServices(Microsoft.AspNetCore.Hosting.WebHostBuilderContext context, Microsoft.Extensions.DependencyInjection.IServiceCollection services) { }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Google.Cloud.Functions.Framework
public class SentryStartup : Google.Cloud.Functions.Hosting.FunctionsStartup
{
public SentryStartup() { }
public override void Configure(Microsoft.AspNetCore.Hosting.WebHostBuilderContext context, Microsoft.AspNetCore.Builder.IApplicationBuilder app) { }
public override void ConfigureLogging(Microsoft.AspNetCore.Hosting.WebHostBuilderContext context, Microsoft.Extensions.Logging.ILoggingBuilder logging) { }
public override void ConfigureServices(Microsoft.AspNetCore.Hosting.WebHostBuilderContext context, Microsoft.Extensions.DependencyInjection.IServiceCollection services) { }
}
Expand Down
35 changes: 35 additions & 0 deletions test/Sentry.Google.Cloud.Functions.Tests/SentryStartupTests.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
using System;
using System.Collections.Generic;
using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NSubstitute;
using Sentry.AspNetCore;
using Sentry.Internal;
using Xunit;

namespace Sentry.Google.Cloud.Functions.Tests
Expand All @@ -17,6 +20,8 @@ public class SentryStartupTests
public IWebHostEnvironment HostingEnvironment { get; set; } = Substitute.For<IWebHostEnvironment>();
public WebHostBuilderContext WebHostBuilderContext { get; set; }

public IApplicationBuilder ApplicationBuilder { get; set; } = Substitute.For<IApplicationBuilder>();

public ILoggingBuilder LoggingBuilder { get; set; }

public SentryStartupTests()
Expand All @@ -36,6 +41,36 @@ private class TestLoggingBuilder : ILoggingBuilder
public IServiceCollection Services { get; } = new ServiceCollection();
}

[Fact]
public void ConfigureLogging_SentryAspNetCoreOptions_ReleaseOptionsSet()
{
var sut = new SentryStartup();
var scope = new Scope(null);
Environment.SetEnvironmentVariable("K_REVISION", "1");
sut.ConfigureLogging(WebHostBuilderContext, LoggingBuilder);

var provider = LoggingBuilder.Services.BuildServiceProvider();
var option = provider.GetRequiredService<IOptions<SentryAspNetCoreOptions>>();

Assert.Null(option.Value.Release);
Assert.Equal("testhost@16.11.0+1", ReleaseLocator.Resolve(option.Value));
}

[Fact]
public void Configure_TracingMiddlewaresRegistered()
{
// Arrange
var sut = new SentryStartup();
var ApplicationBuilder = Substitute.For<IApplicationBuilder>();

// Act
sut.Configure(WebHostBuilderContext, ApplicationBuilder);

// Assert
// AspNetCore and GCP MiddleWare
ApplicationBuilder.Received(2).Use(Arg.Any<Func<RequestDelegate, RequestDelegate>>());
}

[Fact]
public void ConfigureLogging_SentryAspNetCoreOptions_FlushOnCompletedRequestTrue()
{
Expand Down