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

Add Counters for Endpoints #21675

Closed
wants to merge 1 commit into from

Conversation

Kahbazi
Copy link
Member

@Kahbazi Kahbazi commented May 10, 2020

Fixes #19027

@ghost ghost added the area-servers label May 10, 2020
Copy link
Member

@gfoidl gfoidl left a comment

Choose a reason for hiding this comment

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

Are tests needed?

endpointCounter.Failed();
WriteEvent(3, endpoint);
}

Copy link
Member

Choose a reason for hiding this comment

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

Nit: one empty line too much.

{
DisplayName = $"{endpoint}:Failed Requests"
};

Copy link
Member

Choose a reason for hiding this comment

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

Nit: remove empty line

@@ -62,10 +63,13 @@ public Task Invoke(HttpContext httpContext)
}
catch (Exception exception)
{
EndpointMiddlewareEventSource.Log.ExecutedEndpoint(endpoint.DisplayName);
EndpointMiddlewareEventSource.Log.FailedEndpoint(endpoint.DisplayName);
Copy link
Member

Choose a reason for hiding this comment

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

May it be "better" to handle the executed within the failed?
So that here is just one method call, and in the internals of Log.FailedEndpoint this case gets handled and has the potential to adapt it later if needed.

@Kahbazi
Copy link
Member Author

Kahbazi commented May 11, 2020

Are tests needed?

Absolutely. I will add tests after the team approved the design.

[Event(1, Level = EventLevel.Informational)]
public void ExecutingEndpoint(string endpoint)
{
var endpointCounter = _endpointCounters.GetOrAdd(endpoint, key => new EndpointCounter(key, this));
Copy link
Member

Choose a reason for hiding this comment

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

Looking up a dictionary multiple times (executing, executed, failed) for every call would have a performance impact. This code is on a very hot path.

I don't know the best way to mitigate but EventSource.OnEventCommand provides a hook to decide to enable counters. We should only be initializing counters when needed.

Copy link
Member

Choose a reason for hiding this comment

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

protected override void OnEventCommand(EventCommandEventArgs command)
{
if (command.Command == EventCommand.Enable)
{
// This is the convention for initializing counters in the RuntimeEventSource (lazily on the first enable command).
// They aren't disabled afterwards...

Copy link
Member

Choose a reason for hiding this comment

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

The problem is that even if the event source is disabled, we would still need to do the dictionary lookup to ensure EndpointCounter._totalRequests/_currentRequests/_failedRequests are all accurate when the event source becomes enabled.

We can still override OnEventCommand to lazily initialize the PollingCounters, but we'd have to iterate _endpointCounters dictionary when the event source becomes enabled to do so.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, right. We could add counters as metadata or a property on the endpoint. However endpoints are intended to be immutable and Ryan would murder us all 😄

Copy link
Member

Choose a reason for hiding this comment

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

I was thinking the same thing. Problem with a property is that Endpoint is defined in another assembly and InternalsVisibleTo is bad. Putting it in Metadata doesn't work because it is immutable and Ryan would murder us. Retrieving the EndpointCounter from Metadata would involve a dictionary lookup anyway.

Copy link
Member

@JamesNK JamesNK May 21, 2020

Choose a reason for hiding this comment

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

Yes.

There would be some other challenges, like an application's endpoints can change. For example, dropping a new Razor file into a directory would change that endpoint data source to include the new endpoint and the matcher would recompute the DFA graph. When that happens we'd need to keep the endpoint+counter instances together. Not difficult, but something to take into account.

Copy link
Member Author

Choose a reason for hiding this comment

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

What should happen if someone wants to SetEndpoint without Routing Middleware. Do they need to provide the counter data as well?

Correct me if I'm wrong, but Routing matcher only gives RouteEndpoint not Endpoint, and If we are going with getting counters from Routing matcher, can we instead add a property to RouteEndpoint and since it's in the same assembly as there's no need to InternalVisibleTo.

Copy link
Member

Choose a reason for hiding this comment

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

Routing matching usual matches RouteEndpoint but can return Endpoint from a policy.

That's a good point about SetEndpoint. Matching is the primary way of setting endpoints, but not the only way. Matching providing the counter type wouldn't work.

Copy link
Member

Choose a reason for hiding this comment

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

@davidfowl Thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

@noahfalk This is an example of where we want dimensions for metrics to avoid the dictionary workaround.

@BrennanConroy
Copy link
Member

Thanks for trying this out @Kahbazi, we're going to wait for dimensions support in counters before doing this.

@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Aug 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

We need a way to get an event for the routing template
6 participants