Implementing Global API Metrics: Real-Time Tracking with Redis
Learn how to build high-performance global API metrics using Redis atomic counters. Master real-time tracking, storage, and querying for better observability.

Previously in this course, we explored Project Refactoring: Service Integration with Redis, where we unified our various caching and locking services into a cohesive architecture. In this lesson, we build on that foundation by adding observability. We will implement global API metrics to track total request volumes and error rates, giving us immediate, low-latency insights into our system's performance.
Understanding Metrics from First Principles
In a distributed system, logging everything to a traditional database can quickly become a bottleneck. If you attempt to INSERT a row into a SQL table for every single API request, you will soon face I/O saturation.
Metrics are different from logs. While logs track individual events (e.g., "User X requested resource Y"), metrics track aggregate state (e.g., "Total requests in the last minute"). Redis is purpose-built for this. Because it operates in memory, we can increment counters thousands of times per second without impacting the performance of our main application logic.
Implementing Global Counters with INCR
To track global API metrics, we use the INCR command. INCR is atomic, meaning that even if ten different requests hit your API at the exact same millisecond, Redis guarantees that the counter will be incremented correctly by 10.
Let’s extend our project to track the total number of requests and the total number of 5xx errors.
Worked Example: Integrating Metrics into the API
We will create a simple MetricsService that intercepts our requests.
JAVASCRIPT// metricsService.js const redis = require(CE9178">'redis'); const client = redis.createClient(); async function trackRequest(route) { const timestamp = new Date().toISOString().split(CE9178">'T')[0]; // Daily granularity const pipe = client.multi(); // Increment global total pipe.incr(CE9178">'metrics:global:total'); // Increment per-route counter pipe.incr(CE9178">`metrics:route:${route}:total`); await pipe.exec(); } async function trackError(route) { await client.incr(CE9178">'metrics:global:errors'); await client.incr(CE9178">`metrics:route:${route}:errors`); } async function getMetrics() { const total = await client.get(CE9178">'metrics:global:total'); const errors = await client.get(CE9178">'metrics:global:errors'); return { total: parseInt(total || 0), errors: parseInt(errors || 0) }; } module.exports = { trackRequest, trackError, getMetrics };
In your main API middleware, you would simply invoke these methods:
JAVASCRIPTapp.use(async (req, res, next) => { await trackRequest(req.path); next(); }); // Inside error handler app.use((err, req, res, next) => { trackError(req.path); res.status(500).send(CE9178">'Internal Server Error'); });
Hands-on Exercise: Building a Reset Strategy
Metrics are only useful if they are relevant. Tracking "total requests since the dawn of time" is rarely helpful for monitoring performance trends.
Your Task:
Modify the getMetrics function (or create a new one) to implement a "Reset" command. Use the DEL command to clear the metrics:global:total and metrics:global:errors keys. Then, implement a cron job or a simple setInterval in your Node.js application that resets these counters every 24 hours at midnight.
Common Pitfalls
- Over-instrumentation: While Redis is fast, incrementing a hundred different keys for every single request adds latency. Stick to high-level indicators like total throughput and error counts.
- Key Explosion: Avoid creating keys based on unbounded data (like
metrics:user:ID). If you have a million users, you will create a million keys, which will bloat your memory usage. Stick to fixed categories like routes or status codes. - Missing Persistence: Remember that if you don't enable AOF persistence (as discussed in Understanding Redis Persistence), your metrics will vanish if the Redis server restarts.
Frequently Asked Questions
Q: Should I use Hashes or Strings for metrics?
A: Use Hashes if you want to group related metrics (e.g., metrics:api_stats containing fields total and errors). Use Strings if you need high-frequency, independent increments.
Q: Can I use these metrics to calculate error rates?
A: Absolutely. By fetching both the total and error counts, you can calculate (errors / total) * 100 in your application layer to determine your current failure rate percentage.
Q: Does this replace logging? A: No. Metrics tell you that something is happening; logs tell you why it is happening. Use Redis for your dashboard metrics and a tool like ELK or Datadog for detailed request logs.
Recap
In this lesson, we moved beyond basic caching to observability. We learned that:
- Atomic Increments:
INCRis the gold standard for high-concurrency counting. - Granularity: You can track global metrics or segment them by route using descriptive key naming.
- Aggregation: Metrics provide the "what," while logs provide the "why."
By implementing these patterns, you’ve added a vital layer of visibility to your project, moving you toward professional-grade API management.
Up next: We will discuss how to implement TTL-based windowing to track metrics over specific time intervals, such as "requests per minute."
Work with me

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs — the backend engine for your app, mobile client, or SaaS. Built by an API specialist.

React & Next.js Dashboard / Admin UI Development
A clean, data-rich dashboard UI in React or Next.js — charts, tables, and real-time data that your users will actually enjoy using.


