-
-
Notifications
You must be signed in to change notification settings - Fork 207
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
Capture built in metrics from System.Diagnostics.Metrics API #3052
Merged
Merged
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
95d6484
Added SystemDiagnosticsMetricsIntegration
jamescrosswell 1887b87
Fixed verify tests
jamescrosswell 345b3bd
Replaced double lock with a singleton
jamescrosswell 1b77a91
Replaced singleton with Lazy<T>
jamescrosswell 4686e06
Demonstrate capturing built in metrics in the Sample application
jamescrosswell e4e6c78
Refactoring + Changelog
jamescrosswell b4d9036
Update Sentry.EntityFramework.csproj
jamescrosswell 2a1d608
Updated verified files
jamescrosswell a51bb02
Update build.yml
jamescrosswell 237b6cf
Create SentryOptionsTests.Integrations_default_ones_are_properly_regi…
jamescrosswell 17e8c92
Update build.yml
jamescrosswell 24d102a
Merge branch 'default-metrics' of github.com:getsentry/sentry-dotnet …
jamescrosswell 06da2b8
Merge branch 'main' into default-metrics
jamescrosswell c91840b
Update SubstringOrRegexPatternTests.cs
jamescrosswell 40eef42
Update SentryOptionsExtensionsTests.cs
jamescrosswell fb561cf
Some basic SystemDiagnosticsMetricsListenerTests
jamescrosswell 421a4d8
SystemDiagnosticsMetricsIntegrationTests
jamescrosswell 72c744b
Added tests to check aggregates
jamescrosswell 9ecdbe7
Added support for UpDownCounters
jamescrosswell 8e22090
Fixed tests to avoid metric collisions between different tests
jamescrosswell a27d50c
Delay resolution of MetricAggregator until SentryInit has completed (…
jamescrosswell d987528
Renamed SetWithConfigBinding to WIthConfigBinding
jamescrosswell bb9b269
Convert to async
jamescrosswell 79352dc
Fixed typo
jamescrosswell ebf8ddb
Added ability to configure Meters to listen to (in addition to specif…
jamescrosswell 7bdc9a4
Update ApiApprovalTests.Run.Net4_8.verified.txt
jamescrosswell d23afaf
Programmatically ensure unique names for test meters/instruments
jamescrosswell 4bc84b1
Merge branch 'main' into default-metrics
jamescrosswell 383d0c7
Merge branch 'main' into default-metrics
jamescrosswell e2bad12
Update SentryOptionsTests.verify.cs
jamescrosswell a9a6c93
Updated verify tests
jamescrosswell 3baaa0b
Updated verify tests
jamescrosswell c1ac0fc
Update SentryOptionsTests.verify.cs
jamescrosswell 77e6880
Added Windows specific SentryOptions verify tests
jamescrosswell 33d8af9
Collect all built in metrics by default
jamescrosswell 4f84c9d
Refactoring
jamescrosswell 93b7afb
Update SystemDiagnosticsMetricsIntegrationTests.cs
jamescrosswell c358a60
Merge branch 'main' into default-metrics
jamescrosswell a7a8e1f
Update Program.cs
jamescrosswell e26175e
Integrating review feedback
jamescrosswell File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
namespace Sentry; | ||
|
||
/// <summary> | ||
/// Well known values for built in metrics that can be configured for | ||
/// <see cref="ExperimentalMetricsOptions.CaptureSystemDiagnosticsMeters"/> | ||
/// </summary> | ||
public static partial class BuiltInSystemDiagnosticsMeters | ||
{ | ||
private const string MicrosoftAspNetCoreHostingPattern = @"^Microsoft\.AspNetCore\.Hosting$"; | ||
private const string MicrosoftAspNetCoreRoutingPattern = @"^Microsoft\.AspNetCore\.Routing$"; | ||
private const string MicrosoftAspNetCoreDiagnosticsPattern = @"^Microsoft\.AspNetCore\.Diagnostics$"; | ||
private const string MicrosoftAspNetCoreRateLimitingPattern = @"^Microsoft\.AspNetCore\.RateLimiting$"; | ||
private const string MicrosoftAspNetCoreHeaderParsingPattern = @"^Microsoft\.AspNetCore\.HeaderParsing$"; | ||
private const string MicrosoftAspNetCoreServerKestrelPattern = @"^Microsoft\.AspNetCore\.Server\.Kestrel$"; | ||
private const string MicrosoftAspNetCoreHttpConnectionsPattern = @"^Microsoft\.AspNetCore\.Http\.Connections$"; | ||
private const string MicrosoftExtensionsDiagnosticsHealthChecksPattern = @"^Microsoft\.Extensions\.Diagnostics\.HealthChecks$"; | ||
private const string MicrosoftExtensionsDiagnosticsResourceMonitoringPattern = @"^Microsoft\.Extensions\.Diagnostics\.ResourceMonitoring$"; | ||
private const string SystemNetNameResolutionPattern = @"^System\.Net\.NameResolution$"; | ||
private const string SystemNetHttpPattern = @"^System\.Net\.Http$"; | ||
|
||
/// <summary> | ||
/// Matches the built in Microsoft.AspNetCore.Hosting metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreHosting = MicrosoftAspNetCoreHostingRegex(); | ||
|
||
[GeneratedRegex(MicrosoftAspNetCoreHostingPattern, RegexOptions.Compiled)] | ||
private static partial Regex MicrosoftAspNetCoreHostingRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreHosting = new Regex(MicrosoftAspNetCoreHostingPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
/// <summary> | ||
/// Matches the built in Microsoft.AspNetCore.Routing metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreRouting = MicrosoftAspNetCoreRoutingRegex(); | ||
|
||
[GeneratedRegex(MicrosoftAspNetCoreRoutingPattern, RegexOptions.Compiled)] | ||
private static partial Regex MicrosoftAspNetCoreRoutingRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreRouting = new Regex(MicrosoftAspNetCoreRoutingPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
/// <summary> | ||
/// Matches the built in Microsoft.AspNetCore.Diagnostics metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreDiagnostics = MicrosoftAspNetCoreDiagnosticsRegex(); | ||
|
||
[GeneratedRegex(MicrosoftAspNetCoreDiagnosticsPattern, RegexOptions.Compiled)] | ||
private static partial Regex MicrosoftAspNetCoreDiagnosticsRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreDiagnostics = new Regex(MicrosoftAspNetCoreDiagnosticsPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
/// <summary> | ||
/// Matches the built in Microsoft.AspNetCore.RateLimiting metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreRateLimiting = MicrosoftAspNetCoreRateLimitingRegex(); | ||
|
||
[GeneratedRegex(MicrosoftAspNetCoreRateLimitingPattern, RegexOptions.Compiled)] | ||
private static partial Regex MicrosoftAspNetCoreRateLimitingRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreRateLimiting = new Regex(MicrosoftAspNetCoreRateLimitingPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
/// <summary> | ||
/// Matches the built in Microsoft.AspNetCore.HeaderParsing metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreHeaderParsing = MicrosoftAspNetCoreHeaderParsingRegex(); | ||
|
||
[GeneratedRegex(MicrosoftAspNetCoreHeaderParsingPattern, RegexOptions.Compiled)] | ||
private static partial Regex MicrosoftAspNetCoreHeaderParsingRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreHeaderParsing = new Regex(MicrosoftAspNetCoreHeaderParsingPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
/// <summary> | ||
/// Matches the built in Microsoft.AspNetCore.Server.Kestrel metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreServerKestrel = MicrosoftAspNetCoreServerKestrelRegex(); | ||
|
||
[GeneratedRegex(MicrosoftAspNetCoreServerKestrelPattern, RegexOptions.Compiled)] | ||
private static partial Regex MicrosoftAspNetCoreServerKestrelRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreServerKestrel = new Regex(MicrosoftAspNetCoreServerKestrelPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
/// <summary> | ||
/// Matches the built in Microsoft.AspNetCore.Http.Connections metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreHttpConnections = MicrosoftAspNetCoreHttpConnectionsRegex(); | ||
|
||
[GeneratedRegex(MicrosoftAspNetCoreHttpConnectionsPattern, RegexOptions.Compiled)] | ||
private static partial Regex MicrosoftAspNetCoreHttpConnectionsRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern MicrosoftAspNetCoreHttpConnections = new Regex(MicrosoftAspNetCoreHttpConnectionsPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
/// <summary> | ||
/// Matches the built in Microsoft.Extensions.Diagnostics.HealthChecks metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern MicrosoftExtensionsDiagnosticsHealthChecks = MicrosoftExtensionsDiagnosticsHealthChecksRegex(); | ||
|
||
[GeneratedRegex(MicrosoftExtensionsDiagnosticsHealthChecksPattern, RegexOptions.Compiled)] | ||
private static partial Regex MicrosoftExtensionsDiagnosticsHealthChecksRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern MicrosoftExtensionsDiagnosticsHealthChecks = new Regex(MicrosoftExtensionsDiagnosticsHealthChecksPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
/// <summary> | ||
/// Matches the built in Microsoft.Extensions.Diagnostics.ResourceMonitoring metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern MicrosoftExtensionsDiagnosticsResourceMonitoring = MicrosoftExtensionsDiagnosticsResourceMonitoringRegex(); | ||
|
||
[GeneratedRegex(MicrosoftExtensionsDiagnosticsResourceMonitoringPattern, RegexOptions.Compiled)] | ||
private static partial Regex MicrosoftExtensionsDiagnosticsResourceMonitoringRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern MicrosoftExtensionsDiagnosticsResourceMonitoring = new Regex(MicrosoftExtensionsDiagnosticsResourceMonitoringPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
/// <summary> | ||
/// Matches the built in System.Net.NameResolution metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern SystemNetNameResolution = SystemNetNameResolutionRegex(); | ||
|
||
[GeneratedRegex(SystemNetNameResolutionPattern, RegexOptions.Compiled)] | ||
private static partial Regex SystemNetNameResolutionRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern SystemNetNameResolution = new Regex(SystemNetNameResolutionPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
/// <summary> | ||
/// Matches the built in <see cref="System.Net.Http"/> metrics | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
public static readonly SubstringOrRegexPattern SystemNetHttp = SystemNetHttpRegex(); | ||
|
||
[GeneratedRegex(SystemNetHttpPattern, RegexOptions.Compiled)] | ||
private static partial Regex SystemNetHttpRegex(); | ||
#else | ||
public static readonly SubstringOrRegexPattern SystemNetHttp = new Regex(SystemNetHttpPattern, RegexOptions.Compiled); | ||
#endif | ||
|
||
private static readonly Lazy<IList<SubstringOrRegexPattern>> LazyAll = new(() => new List<SubstringOrRegexPattern> | ||
{ | ||
MicrosoftAspNetCoreHosting, | ||
MicrosoftAspNetCoreRouting, | ||
MicrosoftAspNetCoreDiagnostics, | ||
MicrosoftAspNetCoreRateLimiting, | ||
MicrosoftAspNetCoreHeaderParsing, | ||
MicrosoftAspNetCoreServerKestrel, | ||
MicrosoftAspNetCoreHttpConnections, | ||
SystemNetNameResolution, | ||
SystemNetHttp, | ||
MicrosoftExtensionsDiagnosticsHealthChecks, | ||
MicrosoftExtensionsDiagnosticsResourceMonitoring | ||
}); | ||
|
||
/// <summary> | ||
/// Matches all built in metrics | ||
/// </summary> | ||
/// <returns></returns> | ||
public static IList<SubstringOrRegexPattern> All => LazyAll.Value; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
namespace Sentry; | ||
|
||
/// <summary> | ||
/// Settings for the experimental Metrics feature. This feature is preview only and will very likely change in the future | ||
/// without a major version bump... so use at your own risk. | ||
/// </summary> | ||
public class ExperimentalMetricsOptions | ||
{ | ||
/// <summary> | ||
/// Determines whether code locations should be recorded for Metrics | ||
/// </summary> | ||
public bool EnableCodeLocations { get; set; } = true; | ||
|
||
private IList<SubstringOrRegexPattern> _captureSystemDiagnosticsInstruments = new List<SubstringOrRegexPattern>(); | ||
|
||
/// <summary> | ||
/// <para> | ||
/// A list of Substrings or Regular Expressions. Any `System.Diagnostics.Metrics.Instrument` whose name | ||
/// matches one of the items in this list will be collected and reported to Sentry. | ||
/// </para> | ||
/// <para> | ||
/// These can be either custom Instruments that you have created or any of the built in metrics that are available. | ||
/// </para> | ||
/// <para> | ||
/// See https://learn.microsoft.com/en-us/dotnet/core/diagnostics/built-in-metrics for more information. | ||
/// </para> | ||
/// </summary> | ||
public IList<SubstringOrRegexPattern> CaptureSystemDiagnosticsInstruments | ||
{ | ||
// NOTE: During configuration binding, .NET 6 and lower used to just call Add on the existing item. | ||
// .NET 7 changed this to call the setter with an array that already starts with the old value. | ||
// We have to handle both cases. | ||
get => _captureSystemDiagnosticsInstruments; | ||
set => _captureSystemDiagnosticsInstruments = value.WithConfigBinding(); | ||
} | ||
|
||
private IList<SubstringOrRegexPattern> _captureSystemDiagnosticsMeters = BuiltInSystemDiagnosticsMeters.All; | ||
|
||
/// <summary> | ||
/// <para> | ||
/// A list of Substrings or Regular Expressions. Instruments for any `System.Diagnostics.Metrics.Meter` | ||
/// whose name matches one of the items in this list will be collected and reported to Sentry. | ||
/// </para> | ||
/// <para> | ||
/// These can be either custom Instruments that you have created or any of the built in metrics that are available. | ||
/// </para> | ||
/// <para> | ||
/// See https://learn.microsoft.com/en-us/dotnet/core/diagnostics/built-in-metrics for more information. | ||
/// </para> | ||
/// </summary> | ||
public IList<SubstringOrRegexPattern> CaptureSystemDiagnosticsMeters | ||
{ | ||
// NOTE: During configuration binding, .NET 6 and lower used to just call Add on the existing item. | ||
// .NET 7 changed this to call the setter with an array that already starts with the old value. | ||
// We have to handle both cases. | ||
get => _captureSystemDiagnosticsMeters; | ||
set => _captureSystemDiagnosticsMeters = value.WithConfigBinding(); | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In terms of defaults, we could capture none/some/all of these build in metrics.
Are there quotas that we need to be mindful of (so are we potentially going to chew through someone's entire Sentry Quota if we start collecting routing match attempt metrics?
If not, all of those built in metrics are potentially useful/interesting to people so we could enable these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated this PR to include all of the built in metrics by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is experimental I think it's fine to include it by default but definitely worth keeping an eye on impact.
Cost is usually driven by cardinality so if the metrics have no tags it could be OK. cc @bitsandfoxes to own this conversation internally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The metrics definitely have tags. For example,
http.server.request.duration
has 7 attributes, which add dimensionality represented as tags in Sentry. In most situations, that will result in 1 different metric per route configured in the ASP.NET Core application... but that's just one example.Basically anything that's documented as an Attribute in the built in metrics documentation turns up as a tag in Sentry.
Maybe we don't need some of the built in metrics as the insights are already available via our Tracing instrumentation for many of them?