Micrometer: Create tags for request headers in @Timed

Created on 6 Mar 2019  路  4Comments  路  Source: micrometer-metrics/micrometer

Hello!

I think a nice enhancement to the @Timed annotation would be to create tags for arbitrarily named HTTP web request headers, something like this:

@RestController
public class MyController {

    @GetMapping(...)
    @Timed(headers = { "my-header" })
    public MyResponse doSomething(...) { ... }

}

In the example above, the implementation of @Timed would look for a header named my-header in the HttpServletRequest and if found, it would add a tag with the header name as tag key, and the header value as tag value.

An example scenario is when you have a header like client-id that you receive from clients of your API, and you want metrics/dashboards that distinguish the calls from the different clients.

Do you think this can be interesting? Happy to discuss more and contribute with a PR.

Thanks a lot in advance for your feedback!

Most helpful comment

Thanks a lot for the feedback!

Yes I am using Spring, and I wasn't aware of WebMvcTagsProvider and WebFluxTagsProvider, it's a good hint, thanks for pointing me to that. Still, as you say that would apply to all timers, while I am looking for a way to customize differently the endpoints within the same application and I'd like using an annotation for that. On the other hand I understand your concern on tying @Timed to HTTP so I am trying to come up with higher level abstractions.

So far, I think of two possible ways to do that:

Using extraTags and SpEL

Something like this:

@Timed(extraTags = { "my-header", "#{request.headers['my-header']}" })

The idea here is to have SpEL resolve the header value and then treat it as a "normal" extraTag. Of course, this would allow to use SpEL to resolve anything else, not just headers. It would be a "dynamic" extraTag. I am not sure implementing this is possible, I'll try with a sample project.

Using additional annotation @HeaderMetered and WebMvcTagsProvider

Something like this:

@Timed
@HeaderMetered(headers = { "my-header" })

and implementing WebMvcTagsProvider to look for @HeaderMetered associated to the handler object. So @Timed wouldn't be touched, I would add @HeaderMetered on top of that; I wonder if there is a way to generalize this even further.

Any feedback so far? Thanks a lot!

All 4 comments

Thank you for sharing your use case and the suggestion.

@Timed right now is not HTTP specific and I'm not sure we would want to make it so.
As for an alternative right now, based on the other annotations in your example, I will assume you are using Spring. With Spring Boot, you can make your own implementation of WebMvcTagsProvider or WebFluxTagsProvider depending on whether you are using WebMVC or WebFlux (see the documentation). In your own implementation (you can extend DefaultWebMvcTagsProvider, for example) it would be easy to add the logic of tagging by a header of your choosing. The difference in effect would be that that will apply to all WebMVC/WebFlux timers, whereas I believe your suggestion is for customizing just one specific endpoint.

Does the TagsProvider alternative above suite your use case well enough?

Thanks a lot for the feedback!

Yes I am using Spring, and I wasn't aware of WebMvcTagsProvider and WebFluxTagsProvider, it's a good hint, thanks for pointing me to that. Still, as you say that would apply to all timers, while I am looking for a way to customize differently the endpoints within the same application and I'd like using an annotation for that. On the other hand I understand your concern on tying @Timed to HTTP so I am trying to come up with higher level abstractions.

So far, I think of two possible ways to do that:

Using extraTags and SpEL

Something like this:

@Timed(extraTags = { "my-header", "#{request.headers['my-header']}" })

The idea here is to have SpEL resolve the header value and then treat it as a "normal" extraTag. Of course, this would allow to use SpEL to resolve anything else, not just headers. It would be a "dynamic" extraTag. I am not sure implementing this is possible, I'll try with a sample project.

Using additional annotation @HeaderMetered and WebMvcTagsProvider

Something like this:

@Timed
@HeaderMetered(headers = { "my-header" })

and implementing WebMvcTagsProvider to look for @HeaderMetered associated to the handler object. So @Timed wouldn't be touched, I would add @HeaderMetered on top of that; I wonder if there is a way to generalize this even further.

Any feedback so far? Thanks a lot!

This is useful.

Would this affect the cardinality?

Hi! Sorry, I am not sure what you mean with cardinality? Are you referring to the number of headers that you could capture with the above methods? If so, it looks to me that you could configure both methods to capture either a single header or multiple headers.

I am currently experimenting with the second approach (adding a @HeaderMetered annotation on top of @Timed), I'll share my results here.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adrianboimvaser picture adrianboimvaser  路  3Comments

samanthacatania picture samanthacatania  路  4Comments

ITman1 picture ITman1  路  4Comments

ericsogm picture ericsogm  路  3Comments

nickcodefresh picture nickcodefresh  路  3Comments