micrometer-metrics / micrometer-metrics/micrometer
Alternative approach to build metric names from tags in Dropwizard and other path-based backends
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 4.9k
- Forks
- 1.2k
- Avg merge
- 8h 56m
- Merged PRs (30d)
- 87
Description
Hello, I'd like to propose an alternative way to create metric names in backends like Dropwizard, which don't support tags natively. Either to consider implementing it in Micrometer or as a suggestion for other developers on how to solve this problem in their systems.
We've been using Dropwizard metrics reported to Graphite in our company for a couple of years. Now we're moving to Micrometer as part of Spring Boot 2 migration, also adding Prometheus as an alternative storage. I describe problems we faced and our solution.
Issues when migrating to Micrometer
One of our concerns during migration was not to change Graphite metric paths when migrating from Spring Boot 1 on Dropwizard to Spring Boot 2 on Micrometer. Some exemplary metric paths were:
# at Graphite before Micrometer
process.jvm.memory.heap.used
process.jvm.memory.non-heap.used
api-requests.SomeController.someHandler.GET.200
api-requests.SomeController.someHandler.GET.500
Introducing tags in vanilla Micrometer results in the following:
# at Prometheus on Micrometer, great
process_jvm_memory_used_bytes {area=heap|non-heap}
api_requests_seconds {controller=SomeController, handler=someHandler, method=GET, code=200|500}
# at Graphite on Micrometer, totally different tree
process.jvm.memory.area.heap.used
process.jvm.memory.area.non-heap.used
api-requests.code.200.controller.SomeController.handler.someHandler.method.GET
api-requests.code.500.controller.SomeController.handler.someHandler.method.GET
Which brings a couple of problems:
- Graphite metric tree is different, preventing a smooth migration to Spring Boot 2.
- Metric tree structure emerges from tags alphabetic order, no longer follows the logical order of
controller->handler->method->code(captured in #595). - Metric paths are much longer –
api-requests.SomeController.someHandler.GET.200is clear enough, we don't needcontroller,handler,methodandcodesegments. - Whenever a new tag is added the metric tree can get changed depending on alphabetic order.
Controlling path encoding with placeholders
Our approach is to give control over creating the metric path to the developer instead of relying on encoding logic in Micrometer. We provide our own HierarchicalNameMapper and PrometheusNamingConvention implementations which support placeholders in metric names:
meterRegistry.gauge("process.jvm.memory.{area}.used", Tags.of("area", "heap")), ...);
meterRegistry.gauge("process.jvm.memory.{area}.used", Tags.of("area", "non-heap")), ...);
metricRegistry.timer(
"api-requests.{controller}.{handler}.{method}.{code}",
"controller", "SomeController", "handler", "someHandler", "method", "GET", "code", "200"
).record(...);
Our HierarchicalNameMapper implementation replaces all placeholders with their matching tags, mapping to our previous Graphite structure:
# at Graphite on Micrometer, with placeholders resolved
process.jvm.memory.heap.used
process.jvm.memory.non-heap.used
api-requests.SomeController.someHandler.GET.200
Our PrometheusNamingConvention removes all placeholders from metric name, mapping to the same name as just after introducing Micrometer:
# at Prometheus on Micrometer, with placeholders stripped
process_jvm_memory_used_bytes {area=heap|non-heap}
api_requests_seconds {controller=SomeController, handler=someHandler, method=GET, code=200}
Where to use placeholders
We use placeholders in all our code that is expected to support both Graphite and Prometheus. Either:
- Library code, e.g. memory metrics.
- Application code in process of migration from Graphite to Prometheus.
If an application doesn't need to report to Graphite and Prometheus simultaneously – either it's not using Prometheus yet or it's already completely migrated from Graphite – then placeholders are not required. When using Graphite only the application can define its metric names explicitly and ignore the tags argument. When using Prometheus only the application can use Micrometer API as it was designed.
Adoption
We started adopting this solution in our ~400 microservices stack. We register all our metrics from internal libraries using the placeholders mechanism and have a few services in the process of migration from Graphite to Prometheus also registering their metrics this way.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Review the proposed HierarchicalNameMapper and PrometheusNamingConvention implementations and the placeholder examples in the issue. Determine whether placeholder-based naming should be implemented in Micrometer or documented as an external approach, and consider the Graphite and Prometheus naming behavior shown as the completion criteria.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- observability-sre
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100