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

Capture built in metrics from System.Diagnostics.Metrics API #3052

Merged
merged 40 commits into from
Jan 30, 2024

Conversation

jamescrosswell
Copy link
Collaborator

@jamescrosswell jamescrosswell commented Jan 16, 2024

The PR makes a start on implementing:

For this first integration we'd like to make it easy for Sentry SDK Users to be able to capture any of the Built In Metrics that are accessible via the System.Diagnostics.Metrics API.

SDK users can use SentryOptions.ExperimentalMetrics.CaptureInstruments to configure one or more System.Diagnostics.Metrics.Instrument that they are interested in. The SystemDiagnosticsMetricsIntegration (if enabled) will then capture any metrics for those instruments and send them to Sentry.

Currently the integration supports the following Instruments:

Dependencies

This integration needs System.Diagnostics.DiagnosticSource (version 8 I think) to work... Applications that target .NET 8+ include this reference by default so, for the time being, this integration is only available for .NET 8 or greater. I'm not sure if there's a way to enable the integration on previous TFMs if people are OK to add System.Diagnostics.DiagnosticSource... I was thinking maybe a separate NuGet package (with that as a dependency) for older TFMs but have it built in for .NET 8 or greater. Two things:

  1. I'm not quite sure how to do this... some MS Build trickery now doubt.
  2. Would we even want to do this? It would be another NuGet package to maintain. Maybe we wait to see if anyone actually wants this in the first place?

At the very least, I think let's not do it in this PR (we can create a separate issue and PR for this if/when we decide to do it).

Copy link
Member

@bruno-garcia bruno-garcia left a comment

Choose a reason for hiding this comment

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

quick pass

Copy link

codecov bot commented Jan 16, 2024

Codecov Report

Attention: 12 lines in your changes are missing coverage. Please review.

Comparison is base (741e088) 75.39% compared to head (e26175e) 76.43%.

Files Patch % Lines
...entry/Internal/SystemDiagnosticsMetricsListener.cs 72.09% 10 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3052      +/-   ##
==========================================
+ Coverage   75.39%   76.43%   +1.04%     
==========================================
  Files         351      355       +4     
  Lines       13175    13381     +206     
  Branches     2613     2656      +43     
==========================================
+ Hits         9933    10228     +295     
+ Misses       2572     2474      -98     
- Partials      670      679       +9     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jamescrosswell jamescrosswell changed the title Added SystemDiagnosticsMetricsIntegration Capturing built in metrics from the System.Diagnostics.Metrics API Jan 17, 2024
@jamescrosswell jamescrosswell changed the title Capturing built in metrics from the System.Diagnostics.Metrics API Capture built in metrics from System.Diagnostics.Metrics API Jan 17, 2024
@jamescrosswell jamescrosswell marked this pull request as ready for review January 18, 2024 02:17
@bruno-garcia
Copy link
Member

bruno-garcia commented Jan 18, 2024

This integration needs System.Diagnostics.DiagnosticSource (version 8 I think) to work... Applications that target .NET 8+ include this reference by default so, for the time being, this integration is only available for .NET 8 or greater. I'm not sure if there's a way to enable the integration on previous TFMs if people are OK to add System.Diagnostics.DiagnosticSource... I was thinking maybe a separate NuGet package (with that as a dependency) for older TFMs but have it built in for .NET 8 or greater. Two things:

I'm not quite sure how to do this... some MS Build trickery now doubt.
Would we even want to do this? It would be another NuGet package to maintain. Maybe we wait to see if anyone actually wants this in the first place?

At the very least, I think let's not do it in this PR (we can create a separate issue and PR for this if/when we decide to do it)

We have already a package, that's only used for older frameworks:

https://github.com/getsentry/sentry-dotnet/tree/main/src/Sentry.DiagnosticSource#when-shouldnt-i-include-this-package

Note that this can be confusing sometimes as a setup so docs here needs to be excellent.

Starting with version 3.9.0, the SDK automatically integrates with Entity Framework Core and SQLClient whenever available. Those integrations are automatically activated if your projectRepresents your service in Sentry and allows you to scope events to a distinct application.
matches one of the following conditions:

Includes Sentry.AspNet 3.9.0 or higher

Includes Sentry.AspNetCore 3.9.0 or higher
Includes Sentry 3.9.0 and targets .NET Core 3.0 or higher (for example, .NET 5)

Folks have been confused with this: https://docs.sentry.io/platforms/dotnet/performance/instrumentation/automatic-instrumentation/#diagnosticsource-integration

On newer frameworks we include the source in the core Sentry package:

<!-- Sentry.DiagnosticSource is compiled directly into Sentry for .NET Core and .NET targets only. -->
<PropertyGroup Condition="!$(TargetFramework.StartsWith('netstandard')) and !$(TargetFramework.StartsWith('net4'))">
<DefineConstants>$(DefineConstants);HAS_DIAGNOSTIC_INTEGRATION</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="!$(TargetFramework.StartsWith('netstandard')) and !$(TargetFramework.StartsWith('net4'))">
<Compile Include="..\Sentry.DiagnosticSource\Internal\**\*.cs">
<Link>Internal\%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>

We could bump the min version it depends on:

<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="4.5.0" />

Seems to work on older frameworks but they do a trick of copying older DLLs for old targets sometimes to the new package:
image

So worth testing it out.

where T: struct
{
var unit = MeasurementUnit.Parse(instrument.Unit);
var tagDict = tags.ToImmutableArray().ToImmutableDictionary(
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 almost midnight I need to get back to this and do a proper review 😅

Copy link
Member

Choose a reason for hiding this comment

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

Worth profiling this to see the impact. This being ReadOnlySpan and us allocating immutableArray then dictionary from it seems like could show up depending how often this is called.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

/// See https://learn.microsoft.com/en-us/dotnet/core/diagnostics/built-in-metrics for more information.
/// </para>
/// </summary>
public IList<SubstringOrRegexPattern> CaptureSystemDiagnosticsInstruments
Copy link
Collaborator Author

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.

Copy link
Collaborator Author

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.

Copy link
Member

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

Copy link
Collaborator Author

@jamescrosswell jamescrosswell Jan 30, 2024

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?

@jamescrosswell
Copy link
Collaborator Author

jamescrosswell commented Jan 19, 2024

We have already a package, that's only used for older frameworks:

https://github.com/getsentry/sentry-dotnet/tree/main/src/Sentry.DiagnosticSource#when-shouldnt-i-include-this-package

OK, interesting. So we have:

Sentry DiagnosticSource integration

  • Baked in on net6.0 and later at the moment

System DiagnosticsMetrics integration

  • Baked in on net8.0 and later at the moment

Assuming we can bump the System.Diagnostics.DiagnosticSource version from 4.5.0 to 8.0.0, I could a .src/Sentry.DiagnosticSource/Internal/DiagnosticsMetrics folder containing the Metrics integration... include that in the root project for net8.0 and later and then people could grab the Sentry.DiagnosticSource either if they wanted the DiagnosticSource integration for netstandard/netframework or if they wanted the Metrics integration for net6.0 or below.

I am wondering whether that might create a clash however. If someone was running net6.0 and added a reference to Sentry.DiagnosticSource so that they could use the metrics integration... presumably their Sentry.nupkg would already include everything from src/Sentry.DiagnosticSource/Internal/DiagnosticSource but now so would the Sentry.DiagnosticSource.nupkg that they referred to as well.

Seems like actually these would have to exist as separate packages then... So we'd need a new Sentry.DiagnosticSource.Metrics package that people could add if they're on net6.0 or below, and we just do the same trick for that that we've done already for Sentry.DiagnosticSource.

@jamescrosswell
Copy link
Collaborator Author

Seems like actually these would have to exist as separate packages then... So we'd need a new Sentry.DiagnosticSource.Metrics package that people could add if they're on net6.0 or below, and we just do the same trick for that that we've done already for Sentry.DiagnosticSource.

I've added a separate issue to track that work:

src/Sentry/BuiltInSystemDiagnosticsMeters.cs Outdated Show resolved Hide resolved
/// See https://learn.microsoft.com/en-us/dotnet/core/diagnostics/built-in-metrics for more information.
/// </para>
/// </summary>
public IList<SubstringOrRegexPattern> CaptureSystemDiagnosticsInstruments
Copy link
Member

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

where T: struct
{
var unit = MeasurementUnit.Parse(instrument.Unit);
var tagDict = tags.ToImmutableArray().ToImmutableDictionary(
Copy link
Member

Choose a reason for hiding this comment

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

Worth profiling this to see the impact. This being ReadOnlySpan and us allocating immutableArray then dictionary from it seems like could show up depending how often this is called.

Copy link
Member

@bruno-garcia bruno-garcia left a comment

Choose a reason for hiding this comment

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

No blockers so approving, we can follow up with improvements before GA

@jamescrosswell jamescrosswell merged commit 467676e into main Jan 30, 2024
20 checks passed
@jamescrosswell jamescrosswell deleted the default-metrics branch January 30, 2024 03:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants