-
Notifications
You must be signed in to change notification settings - Fork 784
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
Allow to filter requests when collecting ASP.NET Core metrics. #3323
Allow to filter requests when collecting ASP.NET Core metrics. #3323
Conversation
This change updates ASP.NET Core instrumentation to respect the filter, specified in the `AspNetCoreInstrumentationOptions.Filter`. When using the OpenTelemetry library we already could filter out ASP.NET Core request traces, but not metrics. This forced us to completely disable standard metrics instrumentation, because health checks were polluting the measurements and we could not exclude them. This change updates the `MeterProviderBuilderExtensions` for ASP.NET Core, to accept the `AspNetCoreInstrumentationOptions` configuration delegate and the `HttpInMetricsListener` to respect the filter option. Code is very similar to the traces instrumentation with one exception - instead of creating the listener in the extension method and passing it to the instrumentation class, I decided to keep listener initialization in the instrumentation class (`AspNetCodeMetrics`), because it already encapsulated .NET diagnostics `Meter`, which is required by the metrics listener. I didn't want to push that code out of the instrumentation class (and deal with new disposable in the outer scope), so I just updated the instrumentation class to take in options in the constructor and pass them through to the listener. Lastly, I updated the events emitted by the instrumentation itself to, namely `RequestIsFilteredOut` and `RequestFilterException`, to include the name of the handler that was running the filter. This will allow us to distinguish filter delegates specified for metrics vs traces. It is worth mentioning that I did not update the ASP.NET (non-Core), as it is not an immediate need for us at this point. There are also few more TODOs left to respect other options. We can work on them separately later, if needed.
|
@nahk-ivanov Please sign the EasyCLA so we can accept contributions. |
because health checks were polluting the measurements and we could not exclude them. Could you open an issue describing the problem? I am not sure if we want to run Filters in the Metric path, so if you describe the issue, we can see if there are alternates. |
@cijothomas Created #3324. If you are using health check APIs (which you should be), then by default these requests will be counted as well by the standard instrumentation that this library provides. I don't know how many people are interested in the number of health check requests (we are not), so the filter will allow to eliminate them. I described an alternative (filter downstream) in the issue, but I'd rather prefer to cut it as soon as possible, rather than consuming resources generating, serializing and sending unnecessary data. What is the concern with this code path? Performance? This should not be more than an additional null check, if you don't use the feature, so I'd assume not a big deal. If you use the feature, then you are committing to the perf impact of your filter delegate code. |
[Event(2, Message = "Request is filtered out.", Level = EventLevel.Verbose)] | ||
public void RequestIsFilteredOut(string eventName) | ||
[Event(2, Message = "Request is filtered out from handler '{0}'.", Level = EventLevel.Verbose)] | ||
public void RequestIsFilteredOut(string handlerName, string eventName) |
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 didn't bump the event versions. It doesn't seem like we care about ETW consumers that cache manifests.
Action<AspNetCoreInstrumentationOptions> configure = null) | ||
{ | ||
configure?.Invoke(options); | ||
return AddAspNetCoreInstrumentation( |
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.
This is where the discrepancy is between traces and metrics - in traces we will new-up HttpInLIstener
here and pass it to the instrumentation (AspNetCoreMetrics
in this case). Here it is a little bit more complicated, because metrics listener also expects the Meter
instance, which is disposable. Currently AspNetCoreMetrics
will maintain meter's lifecycle, and I didn't want to push it out to here, which will be hard to do, given that this is a static POP by itself. So I just pass in options to the instrumentation class, and it passes them to the listener. Should not be a big deal, just one thing to note.
This PR was marked stale due to lack of activity and will be closed in 7 days. Commenting or Pushing will instruct the bot to automatically remove the label. This bot runs once per day. |
Ping? Don't make me fork it. 😄 |
In General, we need to try to be as close as feasible to the OpenTelemetry specification. The Enrich and Filter in some of these instrumentation libraries are our own creations, and not following a OTel general spec. For tracing, the only way spec-ed out is to use SpanProcessor (activityProcessor in .NET). (Enrich/Filter provided easy access to context..) I am not convinced that it should be extended to Metrics as well.. Maybe the right way here would be to have a OTel semantic convention, to mark "health" requests with special attribute (like "synthetic_request" : "true/false"), as opposed to exposing new API surface, for multiple instrumentation libraries. |
I think we need to separate the spec and an application that is being instrumented for this conversation. This change only applies to the application (ASP.NET) that is being instrumented with OpenTelemetry. For instance, if I was to instrument my own code, I could decide which metrics and in what situations I want to emit. ASP.NET is not instrumented for metrics to begin with and this library is essentially instrumenting the ASP.NET application to emit metrics with standard schema. We would not need this for any other implementation of the OpenTelemetry, as ASP.NET is, well, for .NET and not "for multiple instrumentation libraries". Following your interpretation of the OpenTelemetry concept, I should not be allowed to expose configuration for my application as to which metrics it should or should not emit in a particular environment, which is obviously not true as I can instrument my application any way I like. If there is not configuration exposed as to how ASP.NET application should be instrumented in this instrumentation library, then other people can write their own ASP.NET instrumentation libraries (fork this one) and emit the same metric, but filtered based on the filter, inclusion list, or whatever they see fit. I'm not sure how that is a concern of OpenTelemetry specification. I'm not sure why OpenTelemetry would want to step in to the territory of prescribing what exact metrics data application should be emitting (even in terms of common schema like As to the |
This PR was marked stale due to lack of activity and will be closed in 7 days. Commenting or Pushing will instruct the bot to automatically remove the label. This bot runs once per day. |
Closed as inactive. Feel free to reopen if this PR is still being worked on. |
This change updates ASP.NET Core instrumentation to respect the filter, specified in the
AspNetCoreInstrumentationOptions.Filter
.When using the OpenTelemetry library we already could filter out ASP.NET Core request traces, but not metrics. This forced us to completely disable standard metrics instrumentation, because health checks were polluting the measurements and we could not exclude them.
This change updates the
MeterProviderBuilderExtensions
for ASP.NET Core, to accept theAspNetCoreInstrumentationOptions
configuration delegate and theHttpInMetricsListener
to respect the filter option.Code is very similar to the traces instrumentation with one exception - instead of creating the listener in the extension method and passing it to the instrumentation class, I decided to keep listener initialization in the instrumentation class (
AspNetCodeMetrics
), because it already encapsulated .NET diagnosticsMeter
, which is required by the metrics listener. I didn't want to push that code out of the instrumentation class (and deal with new disposable in the outer scope), so I just updated the instrumentation class to take in options in the constructor and pass them through to the listener.Lastly, I updated the events emitted by the instrumentation itself to, namely
RequestIsFilteredOut
andRequestFilterException
, to include the name of the handler that was running the filter. This will allow us to distinguish filter delegates specified for metrics vs traces.It is worth mentioning that I did not update the ASP.NET (non-Core), as it is not an immediate need for us at this point. There are also few more TODOs left to respect other options. We can work on them separately later, if needed.
Fixes #3324.