Available metrics
TheMicrometerRateLimitMetricsRecorder (from metrics/MicrometerRateLimitMetricsRecorder.java:14-61) publishes the following metrics:
Request outcomes
Counter:ratelimiter.requests
Tracks the total number of rate limit evaluations.
Tags:
name: The logical name from@RateLimit(name = "...")(or “unknown” if not set)scope: The rate limit scope (“global”, “user”, “ip”, etc.)outcome: Either “allowed” or “blocked”
metrics/MicrometerRateLimitMetricsRecorder.java:22-30):
Evaluation latency
Timer:ratelimiter.evaluate.latency
Measures how long it takes to evaluate a rate limit (including Redis roundtrip).
Tags:
name: The logical name from the annotationscope: The rate limit scope
metrics/MicrometerRateLimitMetricsRecorder.java:32-36):
Errors
Counter:ratelimiter.errors
Tracks rate limiter backend failures (e.g., Redis connection issues).
Tags:
name: The logical name from the annotationscope: The rate limit scopeexception: The exception class name (e.g., “RedisConnectionException”)
metrics/MicrometerRateLimitMetricsRecorder.java:39-53):
Viewing metrics
Actuator endpoint
Expose metrics via Spring Boot Actuator:http://localhost:8080/actuator/metrics(all metrics)http://localhost:8080/actuator/metrics/ratelimiter.requests(specific metric)http://localhost:8080/actuator/prometheus(Prometheus format)
Query examples
Total allowed requests:Prometheus integration
Configure Prometheus export
Add the Micrometer Prometheus dependency:Scrape configuration
Configure Prometheus to scrape your application:Example PromQL queries
Rate of blocked requests per second:Grafana dashboards
Example dashboard panels
Request rate by outcome:Sample dashboard JSON
Create a Grafana dashboard with these key panels:-
Total Requests (Stat panel)
- Query:
sum(ratelimiter_requests_total)
- Query:
-
Block Rate (Gauge panel)
- Query:
sum(rate(ratelimiter_requests_total{outcome="blocked"}[5m])) / sum(rate(ratelimiter_requests_total[5m])) * 100 - Unit: Percent (0-100)
- Query:
-
Requests Over Time (Graph panel)
- Query A:
sum(rate(ratelimiter_requests_total{outcome="allowed"}[5m])) - Query B:
sum(rate(ratelimiter_requests_total{outcome="blocked"}[5m]))
- Query A:
-
Latency Percentiles (Graph panel)
- Query p50:
histogram_quantile(0.50, sum(rate(ratelimiter_evaluate_latency_seconds_bucket[5m])) by (le)) - Query p95:
histogram_quantile(0.95, sum(rate(ratelimiter_evaluate_latency_seconds_bucket[5m])) by (le)) - Query p99:
histogram_quantile(0.99, sum(rate(ratelimiter_evaluate_latency_seconds_bucket[5m])) by (le))
- Query p50:
Custom metrics recorder
You can implement your own metrics recorder for custom backends:Alerting
High block rate alert
Alert when more than 20% of requests are blocked:Backend errors alert
Alert when Redis failures occur:High latency alert
Alert when p95 latency exceeds 100ms:Disabling metrics
If Micrometer is not on the classpath, the library automatically usesNoOpRateLimitMetricsRecorder, which does nothing.
To explicitly disable metrics:
Best practices
Name your rate limits
Always use thename parameter for better observability:
Use consistent naming conventions
Adopt a naming scheme for easier metric queries:Monitor both outcomes
Track both allowed and blocked requests to understand traffic patterns:Set up alerting
Create alerts for:- Unusually high block rates (potential abuse or misconfiguration)
- Backend errors (Redis connectivity issues)
- High latency (performance degradation)