Logging and Monitoring in API Gateway — Observability for API Traffic
In this tutorial, you will learn about Logging and Monitoring in API Gateway. We cover key concepts, practical examples, and best practices to help you master this topic.
Logging and monitoring in an API gateway captures every request and response passing through the system, providing centralized observability for latency, error rates, traffic patterns, and debugging across all backend services.
What You'll Learn
- Structured logging for API requests and responses
- Metrics collection: request count, latency, error rate, status codes
- Distributed tracing across gateway and backend services
Why It Matters
Without centralized logging at the gateway, debugging requires checking logs from every backend service individually. The gateway sees every request and response, making it the perfect single source of truth for API observability, error tracking, and performance monitoring.
Real-World Use
Durga Antivirus Pro's gateway logs every request with a unique trace ID, client IP, route, status code, and response time. When a partner reports slow responses, the operations team queries the gateway logs by trace ID and identifies which backend service caused the delay.
flowchart LR
Request["Request"] --> GW["Gateway"]
GW -->|"Log: trace_id, path, duration"| Logger["Central Logger"]
GW --> Metrics["Prometheus\nMetrics"]
Logger --> ELK["Elasticsearch /\nKibana"]
Metrics --> Grafana["Grafana\nDashboard"]
style GW fill:#dbeafe,stroke:#2563eb
Structured Request Logging
import logging
import uuid
import time
from flask import Flask, request, g
app = Flask(__name__)
logger = logging.getLogger("gateway")
@app.before_request
def start_logging():
g.start_time = time.time()
g.trace_id = request.headers.get("X-Trace-ID", str(uuid.uuid4()))
@app.after_request
def log_response(response):
duration = time.time() - g.start_time
log_data = {
"trace_id": g.trace_id,
"method": request.method,
"path": request.path,
"status": response.status_code,
"duration_ms": round(duration * 1000, 2),
"client_ip": request.remote_addr,
"user_agent": request.headers.get("User-Agent", ""),
"content_length": response.content_length,
}
logger.info("api_request", extra=log_data)
response.headers["X-Trace-ID"] = g.trace_id
return response
Metrics Collection with Prometheus
from prometheus_client import Counter, Histogram, generate_latest
from flask import Response
REQUEST_COUNT = Counter(
"gateway_requests_total",
"Total requests",
["method", "path", "status"]
)
REQUEST_DURATION = Histogram(
"gateway_request_duration_seconds",
"Request duration in seconds",
["method", "path"],
buckets=[0.01, 0.05, 0.1, 0.5, 1, 5]
)
@app.after_request
def record_metrics(response):
REQUEST_COUNT.labels(
method=request.method,
path=request.path,
status=response.status_code
).inc()
REQUEST_DURATION.labels(
method=request.method,
path=request.path
).observe(time.time() - g.start_time)
return response
@app.route("/metrics")
def metrics():
return Response(generate_latest(), mimetype="text/plain")
Distributed Tracing
Pass the trace context to backend services for end-to-end tracing:
@app.before_request
def inject_trace_context():
trace_id = g.trace_id
span_id = uuid.uuid4().hex[:16]
request.trace_context = {
"trace_id": trace_id,
"span_id": span_id,
"parent_span_id": request.headers.get("X-Span-ID", ""),
}
def forward_with_tracing(backend_url):
headers = {
"X-Trace-ID": g.trace_id,
"X-Span-ID": request.trace_context["span_id"],
}
resp = requests.get(backend_url, headers=headers)
return resp
Common Mistakes
1. Logging Sensitive Data
Never log authorization headers, API keys, passwords, or personal data. Configure log filters to redact sensitive fields.
2. No Sampling for High-Volume APIs
Logging every request on a high-traffic gateway generates terabytes per day. Use sampling strategies for debug-level logs.
3. Synchronous Logging Blocking Requests
Logging disk I/O can block the request. Use async loggers or offload logging to a background queue.
4. Metrics Without Labels
A single counter for all requests provides no actionable data. Label by route, status code, method, and backend service.
5. Not Propagating Trace Context
Without propagation, you cannot trace a request across gateway and backend services. Always forward trace headers.
Practice Questions
- Why is the gateway the best place for centralized API logging?
- What is the difference between structured logging and plain text logging?
- Why should trace IDs be propagated to backend services?
- What metrics should a gateway expose for monitoring?
- How can you prevent logging sensitive data?
Answers:
- The gateway handles every API request, providing complete visibility into traffic patterns, errors, and performance across all backends.
- Structured logging uses key-value pairs (JSON) that are machine-parseable, enabling queries like "find all requests with status 500 in the last hour."
- Trace IDs correlate the gateway request with backend logs, enabling end-to-end debugging of multi-service requests.
- Request count (by route/status), latency (average, p95, p99), error rate, active connections, and cache hit ratio.
- Use log filters or middleware that redacts headers and fields matching patterns like
Authorization,password,token,secret.
Challenge: Design a logging Strategy for a gateway handling 10,000 requests per second. Decide what to log at info vs. debug level, how to sample, where to store logs, and what to redact.
FAQ
Mini Project
Add structured logging and Prometheus metrics to a Flask gateway. Log trace ID, method, path, status, and duration for every request. Expose a /metrics endpoint with request count and latency histograms. Add a /logs endpoint that returns the last 100 log entries.
What's Next
Continue with Kong API Gateway to explore a production-grade gateway, or explore AWS API Gateway for cloud-managed solutions.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro