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

Support performance #633

Merged
merged 55 commits into from
Dec 16, 2020
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
f31adac
wip
Tyrrrz Nov 30, 2020
79d2397
wip
Tyrrrz Nov 30, 2020
d7c9974
wip
Tyrrrz Dec 1, 2020
51783e8
wip
Tyrrrz Dec 1, 2020
c99635d
wip
Tyrrrz Dec 1, 2020
7ad5ab5
wip
Tyrrrz Dec 2, 2020
96c443e
wip
Tyrrrz Dec 2, 2020
98e567d
wip
Tyrrrz Dec 2, 2020
e0eb730
wip
Tyrrrz Dec 2, 2020
748670c
wip
Tyrrrz Dec 2, 2020
dfdec31
wip
Tyrrrz Dec 2, 2020
fa64053
wip
Tyrrrz Dec 2, 2020
8338381
wip
Tyrrrz Dec 3, 2020
8fc5c2b
wip
Tyrrrz Dec 4, 2020
6a05871
wip
Tyrrrz Dec 4, 2020
6c0b928
wip
Tyrrrz Dec 4, 2020
5a47bd9
wip
Tyrrrz Dec 4, 2020
e67597e
wip
Tyrrrz Dec 7, 2020
52ec0a5
wip
Tyrrrz Dec 7, 2020
15d7001
wip
Tyrrrz Dec 7, 2020
3a705f0
wip
Tyrrrz Dec 8, 2020
c4f9371
wip
Tyrrrz Dec 8, 2020
00ef2b5
wip
Tyrrrz Dec 8, 2020
b0487cf
wip
Tyrrrz Dec 8, 2020
0a713f3
wip
Tyrrrz Dec 8, 2020
c314a66
wip
Tyrrrz Dec 8, 2020
9e2b7e1
Merge remote-tracking branch 'origin/main' into performance
Tyrrrz Dec 8, 2020
d0c5358
wip
Tyrrrz Dec 8, 2020
a4e01d8
wip
Tyrrrz Dec 8, 2020
d960d7f
wip
Tyrrrz Dec 8, 2020
a0fb93e
wip
Tyrrrz Dec 9, 2020
6c1b413
wip
Tyrrrz Dec 9, 2020
258ed5c
wip
Tyrrrz Dec 9, 2020
f2e5a8b
wip
Tyrrrz Dec 10, 2020
41bcb99
wip
Tyrrrz Dec 10, 2020
da7ee94
wip
Tyrrrz Dec 10, 2020
1371006
wip
Tyrrrz Dec 10, 2020
bafe82a
wip
Tyrrrz Dec 10, 2020
7abdb4f
wip
Tyrrrz Dec 11, 2020
a1e48f8
wip
Tyrrrz Dec 11, 2020
fd13150
wip
Tyrrrz Dec 11, 2020
134d0ec
wip
Tyrrrz Dec 14, 2020
6b92788
wip
Tyrrrz Dec 14, 2020
b6f3ee2
wip
Tyrrrz Dec 14, 2020
0e91066
wip
Tyrrrz Dec 14, 2020
ea06cfb
wip
Tyrrrz Dec 14, 2020
2cb49ef
wip
Tyrrrz Dec 14, 2020
e908cee
wip
Tyrrrz Dec 14, 2020
e8aa3cc
wip
Tyrrrz Dec 14, 2020
71c87ca
wip
Tyrrrz Dec 14, 2020
0c512b1
wip
Tyrrrz Dec 14, 2020
fbd6f17
wip
Tyrrrz Dec 14, 2020
13b88db
wip
Tyrrrz Dec 14, 2020
eb37814
wip
Tyrrrz Dec 14, 2020
61085a4
wip
Tyrrrz Dec 15, 2020
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
* Add `SentryScopeStateProcessor` #603
* Add net5.0 TFM to libraries #606
* Add more logging to CachingTransport #619
* Bump Microsoft.Bcl.AsyncInterfaces to 5.0.0 #618
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's on the line below (it got some ` on another PR)

Suggested change
* Bump Microsoft.Bcl.AsyncInterfaces to 5.0.0 #618

* Add support for performance
* Bump `Microsoft.Bcl.AsyncInterfaces` to 5.0.0 #618
* `DefaultTags` moved from `SentryLoggingOptions` to `SentryOptions` (#637) @PureKrome
* `Sentry.Serilog` can accept DefaultTags (#637) @PureKrome
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion samples/Sentry.Samples.Console.Customized/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ await SentrySdk.ConfigureScopeAsync(async scope =>
SentrySdk.WithScope(s =>
{
s.Level = SentryLevel.Fatal;
s.Transaction = "main";
s.TransactionName = "main";
s.Environment = "SpecialEnvironment";

SentrySdk.CaptureMessage("Fatal message!");
Expand Down
4 changes: 3 additions & 1 deletion src/Sentry.AspNetCore/ScopeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ public static void Populate(this Scope scope, HttpContext context, SentryAspNetC
scope.SetTag("route.area", area);
}

scope.Transaction = area == null ? $"{controller}.{action}" : $"{area}.{controller}.{action}";
scope.TransactionName = area == null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have this in some internal static method to make sure changing its stays aligned with the one on the middleware?

? $"{controller}.{action}"
: $"{area}.{controller}.{action}";
}
}
catch(Exception e)
Expand Down
41 changes: 41 additions & 0 deletions src/Sentry.AspNetCore/SentryMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IWebHostEnvironment;
#endif
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Sentry.Extensibility;
Expand Down Expand Up @@ -85,6 +86,7 @@ public async Task InvokeAsync(HttpContext context)
{
context.Request.EnableBuffering();
}

if (_options.FlushOnCompletedRequest)
{
context.Response.OnCompleted(async () =>
Expand All @@ -94,6 +96,17 @@ public async Task InvokeAsync(HttpContext context)
});
}

var routeData = context.GetRouteData();
var controller = routeData.Values["controller"]?.ToString();
var action = routeData.Values["action"]?.ToString();
var area = routeData.Values["area"]?.ToString();

// TODO: What if it's not using controllers (i.e. endpoints)?

var transactionName = area == null
Tyrrrz marked this conversation as resolved.
Show resolved Hide resolved
? $"{controller}.{action}"
: $"{area}.{controller}.{action}";

hub.ConfigureScope(scope =>
{
// At the point lots of stuff from the request are not yet filled
Expand All @@ -105,6 +118,9 @@ public async Task InvokeAsync(HttpContext context)

scope.OnEvaluating += (_, __) => PopulateScope(context, scope);
});

var transaction = hub.CreateTransaction(transactionName, "http.server");

try
{
await _next(context).ConfigureAwait(false);
Expand All @@ -122,6 +138,12 @@ public async Task InvokeAsync(HttpContext context)

ExceptionDispatchInfo.Capture(e).Throw();
}
finally
{
transaction.Finish(
GetSpanStatusFromCode(context.Response.StatusCode)
);
}

void CaptureException(Exception e)
{
Expand Down Expand Up @@ -161,5 +183,24 @@ internal void PopulateScope(HttpContext context, Scope scope)
scope.Populate(Activity.Current);
}
}

private static SpanStatus GetSpanStatusFromCode(int statusCode) => statusCode switch
{
< 400 => SpanStatus.Ok,
400 => SpanStatus.InvalidArgument,
401 => SpanStatus.Unauthenticated,
403 => SpanStatus.PermissionDenied,
404 => SpanStatus.NotFound,
409 => SpanStatus.AlreadyExists,
429 => SpanStatus.ResourceExhausted,
499 => SpanStatus.Cancelled,
< 500 => SpanStatus.InvalidArgument,
500 => SpanStatus.InternalError,
501 => SpanStatus.Unimplemented,
503 => SpanStatus.Unavailable,
504 => SpanStatus.DeadlineExceeded,
< 600 => SpanStatus.InternalError,
_ => SpanStatus.UnknownError
};
}
}
11 changes: 5 additions & 6 deletions src/Sentry.AspNetCore/SentryStartupFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ namespace Sentry.AspNetCore
/// <inheritdoc />
internal class SentryStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
=> e =>
{
_ = e.UseSentry();
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) => e =>
{
e.UseSentry();

next(e);
};
next(e);
};
}
}
19 changes: 19 additions & 0 deletions src/Sentry/Extensibility/DisabledHub.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Sentry.Protocol;

namespace Sentry.Extensibility
{
Expand Down Expand Up @@ -51,6 +52,17 @@ public void WithScope(Action<Scope> scopeCallback)
{
}

/// <summary>
/// Returns a dummy transaction.
/// </summary>
public Transaction CreateTransaction(string name, string operation) =>
new Transaction(this, null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have a singleton NoOp instance here instead.
Having a disabled hub means we should reduce the instrumentations overhead


/// <summary>
/// Returns null.
/// </summary>
public SentryTraceHeader? GetSentryTrace() => null;

/// <summary>
/// No-Op.
/// </summary>
Expand All @@ -63,6 +75,13 @@ public void BindClient(ISentryClient client)
/// </summary>
public SentryId CaptureEvent(SentryEvent evt, Scope? scope = null) => SentryId.Empty;

/// <summary>
/// No-Op.
/// </summary>
public void CaptureTransaction(Transaction transaction)
{
}

/// <summary>
/// No-Op.
/// </summary>
Expand Down
22 changes: 22 additions & 0 deletions src/Sentry/Extensibility/HubAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ public IDisposable PushScope<TState>(TState state)
public void WithScope(Action<Scope> scopeCallback)
=> SentrySdk.WithScope(scopeCallback);

/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
[DebuggerStepThrough]
public Transaction CreateTransaction(string name, string operation)
=> SentrySdk.CreateTransaction(name, operation);

/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
[DebuggerStepThrough]
public SentryTraceHeader? GetSentryTrace()
=> SentrySdk.GetTraceHeader();

/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
Expand Down Expand Up @@ -132,6 +146,14 @@ public SentryId CaptureException(Exception exception)
public SentryId CaptureEvent(SentryEvent evt, Scope? scope)
=> SentrySdk.CaptureEvent(evt, scope);

/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
[DebuggerStepThrough]
[EditorBrowsable(EditorBrowsableState.Never)]
public void CaptureTransaction(Transaction transaction)
=> SentrySdk.CaptureTransaction(transaction);

/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions src/Sentry/IHub.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Sentry.Protocol;

namespace Sentry
{
/// <summary>
Expand All @@ -18,5 +20,15 @@ public interface IHub :
/// Last event id recorded in the current scope.
/// </summary>
SentryId LastEventId { get; }

/// <summary>
/// Creates a transaction.
/// </summary>
Transaction CreateTransaction(string name, string operation);

/// <summary>
/// Gets the sentry trace header.
/// </summary>
SentryTraceHeader? GetSentryTrace();
}
}
7 changes: 7 additions & 0 deletions src/Sentry/ISentryClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Sentry.Protocol;

namespace Sentry
{
Expand Down Expand Up @@ -27,6 +28,12 @@ public interface ISentryClient
/// <param name="userFeedback">The user feedback to send to Sentry.</param>
void CaptureUserFeedback(UserFeedback userFeedback);

/// <summary>
/// Captures a transaction.
/// </summary>
/// <param name="transaction">The transaction.</param>
void CaptureTransaction(Transaction transaction);

/// <summary>
/// Flushes events queued up.
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions src/Sentry/ISentryTraceSampler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Sentry
{
/// <summary>
/// Trace sampler.
/// </summary>
public interface ISentryTraceSampler
{
/// <summary>
/// Gets the sample rate based on context.
/// </summary>
double GetSampleRate(TraceSamplingContext context);
}
}
9 changes: 9 additions & 0 deletions src/Sentry/Internal/Extensions/JsonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ public static void WriteDictionaryValue(
}
}

public static void WriteDictionary(
this Utf8JsonWriter writer,
string propertyName,
IEnumerable<KeyValuePair<string, object?>>? dic)
{
writer.WritePropertyName(propertyName);
writer.WriteDictionaryValue(dic);
}

public static void WriteDictionary(
this Utf8JsonWriter writer,
string propertyName,
Expand Down
47 changes: 47 additions & 0 deletions src/Sentry/Internal/Hub.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Sentry.Extensibility;
using Sentry.Integrations;
using Sentry.Protocol;

namespace Sentry.Internal
{
Expand Down Expand Up @@ -99,6 +101,39 @@ public void WithScope(Action<Scope> scopeCallback)

public void BindClient(ISentryClient client) => ScopeManager.BindClient(client);

public Transaction CreateTransaction(string name, string operation)
{
var trans = new Transaction(this, _options)
{
Name = name,
Operation = operation
};

var nameAndVersion = MainSentryEventProcessor.NameAndVersion;
var protocolPackageName = MainSentryEventProcessor.ProtocolPackageName;

if (trans.Sdk.Version == null && trans.Sdk.Name == null)
{
trans.Sdk.Name = Constants.SdkName;
trans.Sdk.Version = nameAndVersion.Version;
}

if (nameAndVersion.Version != null)
{
trans.Sdk.AddPackage(protocolPackageName, nameAndVersion.Version);
}

ConfigureScope(scope => scope.Transaction = trans);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe by default we won't do this. The snippets I saw from JS require the caller to decide whether the transaction should be bound to the scope or not.

For now this looks good and lets try like this.


return trans;
}

public SentryTraceHeader? GetSentryTrace()
{
var (currentScope, _) = ScopeManager.GetCurrent();
return currentScope.Transaction?.GetTraceHeader();
}

public SentryId CaptureEvent(SentryEvent evt, Scope? scope = null)
{
try
Expand Down Expand Up @@ -128,6 +163,18 @@ public void CaptureUserFeedback(UserFeedback userFeedback)
}
}

public void CaptureTransaction(Transaction transaction)
{
try
{
_ownedClient.CaptureTransaction(transaction);
}
catch (Exception e)
{
_options.DiagnosticLogger?.LogError("Failure to capture transaction: {0}", e, transaction.SpanId);
}
}

public async Task FlushAsync(TimeSpan timeout)
{
try
Expand Down
25 changes: 11 additions & 14 deletions src/Sentry/Internal/MainSentryEventProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ internal class MainSentryEventProcessor : ISentryEventProcessor
: null;
});

private static readonly SdkVersion NameAndVersion
internal static readonly SdkVersion NameAndVersion
= typeof(ISentryClient).Assembly.GetNameAndVersion();

private static readonly string ProtocolPackageName = "nuget:" + NameAndVersion.Name;
internal static readonly string ProtocolPackageName = "nuget:" + NameAndVersion.Name;

private readonly SentryOptions _options;
internal Func<ISentryStackTraceFactory> SentryStackTraceFactoryAccessor { get; }
Expand Down Expand Up @@ -96,20 +96,17 @@ public SentryEvent Process(SentryEvent @event)

@event.Platform = Protocol.Constants.Platform;

if (@event.Sdk != null)
// SDK Name/Version might have be already set by an outer package
// e.g: ASP.NET Core can set itself as the SDK
if (@event.Sdk.Version == null && @event.Sdk.Name == null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are transactions going through this at the end? Doesn't seem like it since this take SentryEvent.

So transactions will always be reported as sentry.dotnet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah... The SDK is set separately when creating the transaction right now. Transactions also don't get all the other default metadata either, which is populated by event processors.

{
// SDK Name/Version might have be already set by an outer package
// e.g: ASP.NET Core can set itself as the SDK
if (@event.Sdk.Version == null && @event.Sdk.Name == null)
{
@event.Sdk.Name = Constants.SdkName;
@event.Sdk.Version = NameAndVersion.Version;
}
@event.Sdk.Name = Constants.SdkName;
@event.Sdk.Version = NameAndVersion.Version;
}

if (NameAndVersion.Version != null)
{
@event.Sdk.AddPackage(ProtocolPackageName, NameAndVersion.Version);
}
if (NameAndVersion.Version != null)
{
@event.Sdk.AddPackage(ProtocolPackageName, NameAndVersion.Version);
}

// Report local user if opt-in PII, no user was already set to event and feature not opted-out:
Expand Down
Loading