Flask API Logging en Tracing voor Geavanceerde Foutopsporing
description
Met deze prompt kan de gebruiker een krachtig logging- en tracingframework opzetten dat diepgaande inzicht geeft in API-activiteiten en fouten. Dit helpt bij het snel identificeren en oplossen van problemen, verbetert de monitoring en maakt prestatieoptimalisaties mogelijk. Het is effectiever dan standaard logging doordat het ook gedistribueerde tracing omvat, wat cruciaal is in moderne microservices-architecturen.
prompt
Help me bij het implementeren van een uitgebreid logging- en tracing-systeem in mijn Flask API. Mijn huidige logging setup is: <beschrijf je huidige logging configuratie>. Leg uit hoe ik gedetailleerde logs kan vastleggen, inclusief ...
try_prompt
generate_helper
disclaimerOnPageApi
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een uitgebreide gids voor het verbeteren van je logging- en tracing-systeem in je Flask API:
1. Verbeteren van je bestaande logging setup
a. Configuratie van gedetailleerde logging
- Stel het logging niveau in op DEBUG of INFO afhankelijk van je behoefte:
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
- Gebruik loggers per module:
logger = logging.getLogger(__name__)
b. Log request- en responsegegevens
- Gebruik Flask’s `before_request` en `after_request` hooks:
from flask import Flask, request, g
app = Flask(__name__)
@app.before_request
def log_request_info():
g.start_time = datetime.now()
app.logger.info(f'Incoming request: {request.method} {request.url}')
app.logger.debug(f'Headers: {dict(request.headers)}')
if request.is_json:
app.logger.debug(f'Request JSON: {request.get_json()}')
@app.after_request
def log_response_info(response):
duration = (datetime.now() - g.start_time).total_seconds()
app.logger.info(f'Response status: {response.status}')
app.logger.info(f'Request processed in {duration} seconden')
# Log response data indien nodig
return response
c. Log foutmeldingen
- Gebruik exception handlers:
import traceback
@app.errorhandler(Exception)
def handle_exception(e):
app.logger.error(f'Fout opgetreden: {str(e)}')
app.logger.debug(traceback.format_exc())
return {"error": "Server error"}, 500
2. Structureren van logs voor betere analyse
- Gebruik gestructureerde logging met JSON-formaat:
import json
import logging
from pythonjsonlogger import jsonlogger
logger = logging.getLogger()
logHandler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter(
'%(asctime)s %(name)s %(levelname)s %(message)s %(request_id)s %(trace_id)s'
)
logHandler.setFormatter(formatter)
logger.addHandler(logHandler)
logger.setLevel(logging.INFO)
- Voeg contextuele data toe via log filters of gebruik van contextvars:
van Python 3.7+:
import contextvars
request_id = contextvars.ContextVar('request_id')
@app.before_request
def set_request_id():
request_id.set(str(uuid.uuid4()))
# Voeg request_id toe aan logs via filter of formatter
3. Integratie met tracing tools (OpenTelemetry, Jaeger)
a. OpenTelemetry integratie
- Installeer benodigde packages:
pip install opentelemetry-api opentelemetry-sdk opentelemetry-instrumentation-flask opentelemetry-exporter-jaeger
- Configureer OpenTelemetry:
from opentelemetry import trace
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.jaeger.thrift import JaegerExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
trace.set_tracer_provider(
TracerProvider(
resource=Resource.create({SERVICE_NAME: "mijn-flask-api"})
)
)
jaeger_exporter = JaegerExporter(
agent_host_name='localhost',
agent_port=6831,
)
span_processor = BatchSpanProcessor(jaeger_exporter)
trace.get_tracer_provider().add_span_processor(span_processor)
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)
b. Logging trace-id en span-id in logs
- Gebruik contextvars of OpenTelemetry hooks om tracegegevens in logberichten te embedden.
4. Best practices voor analyse en monitoring
- Gebruik een log aggregator zoals ELK (Elasticsearch, Logstash, Kibana) of Graylog
- Correlatie logs en traces door trace-id en span-id in logs op te nemen
- Automatiseer alerting op basis van foutmeldingen of prestatieproblemen
Kort samengevat:
- Gebruik gestructureerde JSON-logs met contextuele data zoals request-id en trace-id.
- Voeg gedetailleerde request-, response- en foutinformatie toe.
- Integreer OpenTelemetry met Jaeger voor distributed tracing.
- Correleer logs en traces voor betere inzichtelijkheid.
Wil je dat ik een voorbeeldcode voor je opstel met alle bovengenoemde onderdelen?
provider: deepseek
model: deepseek-chat
Absoluut! Laten we stap voor stap je logging- en tracing-systeem naar een professioneel niveau tillen. Hier is een uitgebreide handleiding specifiek voor Flask.
---
### **Stap 1: Verbeter je Standaard Logging Setup**
Je huidige console logging is een begin, maar we gaan het structureren, formatteren en naar bestanden schrijven.
**1. Geavanceerde Logging Configuratie (`app.py` of `__init__.py`)**
```python
import logging
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
import os
from pythonjsonlogger import jsonlogger # Installeer via: pip install python-json-logger
def setup_logging(app):
# Verwijder standaard handlers om dubbele logs te voorkomen
for handler in list(app.logger.handlers):
app.logger.removeHandler(handler)
# Maak een log directory aan
log_dir = 'logs'
if not os.path.exists(log_dir):
os.makedirs(log_dir)
# 1. JSON Formatter voor gestructureerde logs (ideaal voor analyse)
json_formatter = jsonlogger.JsonFormatter(
'%(asctime)s %(levelname)s %(name)s %(message)s %(module)s %(funcName)s %(lineno)s'
)
# 2. Gestructureerde Tekst Formatter (leesbaar voor mensen)
detailed_formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(funcName)s:%(lineno)d - %(message)s'
)
# Handlers
# a) Console Handler (voor ontwikkeling)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(detailed_formatter)
# b) Roterend Bestand Handler voor ALLES (WARNING en hoger)
file_handler_all = RotatingFileHandler(
os.path.join(log_dir, 'app.log'),
maxBytes=10*1024*1024, # 10 MB
backupCount=5
)
file_handler_all.setLevel(logging.WARNING)
file_handler_all.setFormatter(json_formatter) # Gebruik JSON voor bestanden
# c) Roterend Bestand Handler voor FOUTEN (ERROR en CRITICAL)
file_handler_errors = RotatingFileHandler(
os.path.join(log_dir, 'errors.log'),
maxBytes=5*1024*1024, # 5 MB
backupCount=3
)
file_handler_errors.setLevel(logging.ERROR)
file_handler_errors.setFormatter(json_formatter)
# Voeg handlers toe aan de app logger
app.logger.addHandler(console_handler)
app.logger.addHandler(file_handler_all)
app.logger.addHandler(file_handler_errors)
# Stel het loglevel in voor de app logger zelf
app.logger.setLevel(logging.INFO)
# Onderdruk overmatige logging van dependencies (optioneel)
logging.getLogger('werkzeug').setLevel(logging.WARNING)
```
**2. Logging in je Flask App Initialiseren**
```python
from flask import Flask
app = Flask(__name__)
setup_logging(app) # Roep de setup functie aan
@app.route('/')
def home():
app.logger.info('Home endpoint was called')
return "Hello, World!"
if __name__ == '__main__':
app.run(debug=True)
```
---
### **Stap 2: Vastleggen van Request- en Responsegegevens**
Hiervoor gebruiken we Flask's `before_request` en `after_request` hooks.
```python
from flask import request, jsonify
import time
from datetime import datetime
@app.before_request
def log_request_info():
# Sla een timestamp op om de duur van het request te meten
request.start_time = time.time()
app.logger.info(
'Inkomend Request',
extra={
'http_method': request.method,
'url': request.url,
'user_agent': str(request.user_agent),
'remote_addr': request.remote_addr,
'headers': dict(request.headers)
}
)
@app.after_request
def log_response_info(response):
# Bereken de verstreken tijd
duration = round((time.time() - request.start_time) * 1000, 2) # in milliseconden
app.logger.info(
'Uitgaande Response',
extra={
'http_status': response.status_code,
'duration_ms': duration, # Prestatiegegevens!
'url': request.url,
'response_size': response.calculate_content_length(),
'timestamp': datetime.utcnow().isoformat() + 'Z'
}
)
return response
# Voorbeeld van een foutlog
@app.errorhandler(500)
def internal_server_error(e):
app.logger.error(
'Interne Serverfout',
extra={
'error': str(e),
'stack_trace': traceback.format_exc() # Importeer traceback
},
exc_info=True # Voeg automatisch exception info toe
)
return jsonify({'error': 'Internal Server Error'}), 500
```
---
### **Stap 3: Integratie met OpenTelemetry voor Gedistribueerde Tracing**
OpenTelemetry is de standaard voor observability. Het koppelt logs, metrics en traces.
**1. Installatie**
```bash
pip install opentelemetry-api opentelemetry-sdk opentelemetry-instrumentation-flask opentelemetry-exporter-jaeger
```
**2. Basisconfiguratie in je App**
```python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.jaeger.thrift import JaegerExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.sdk.resources import Resource
def setup_tracing(app, service_name):
# Stel een tracer provider in
trace.set_tracer_provider(
TracerProvider(
resource=Resource.create({'service.name': service_name})
)
)
tracer = trace.get_tracer(__name__)
# Configureer de Jaeger exporter
jaeger_exporter = JaegerExporter(
agent_host_name="localhost", # Pas aan naar je Jaeger host
agent_port=6831,
)
# Voeg een BatchSpanProcessor toe aan de tracer provider
span_processor = BatchSpanProcessor(jaeger_exporter)
trace.get_tracer_provider().add_span_processor(span_processor)
# Instrumenteer je Flask app automatisch
FlaskInstrumentor().instrument_app(app)
return tracer
# Initialiseer je app
app = Flask(__name__)
setup_logging(app)
tracer = setup_tracing(app, "mijn-flask-api")
# Gebruik de tracer in je endpoints
@app.route('/api/data')
def get_data():
with tracer.start_as_current_span("get_data_operation") as span:
# Je bedrijfslogica hier
span.set_attribute("http.method", "GET")
span.set_attribute("custom.parameter", "some_value")
app.logger.info("Verwerken van data request", extra={"span_id": span.get_span_context().span_id})
return jsonify({"data": "hier is je data"})
```
---
### **Stap 4: Logstructuur voor Betere Analyse & Monitoring**
Gebruik consistent gestructureerde logs (JSON is ideaal). Hier is een voorbeeld van een logentry:
```json
// Voorbeeld log entry in errors.log
{
"asctime": "2023-10-27 14:32:18,123",
"levelname": "ERROR",
"name": "flask.app",
"message": "Interne Serverfout",
"module": "app",
"funcName": "internal_server_error",
"lineno": 42,
"error": "Division by zero",
"stack_trace": "Traceback (most recent call last):\n File \"/app/app.py\", line 30, in dangerous_route\n result = 10 / 0\nZeroDivisionError: division by zero",
"http_method": "GET",
"url": "http://localhost:5000/api/broken",
"remote_addr": "127.0.0.1",
"trace_id": "abc123def456...", // Van OpenTelemetry
"span_id": "789ghi012jkl..." // Van OpenTelemetry
}
```
**Belangrijke velden om altijd op te nemen:**
* `timestamp`: ISO 8601 timestamp.
* `level`: log niveau (DEBUG, INFO, WARNING, ERROR, CRITICAL).
* `service.name`: Naam van je service (consistent met OpenTelemetry).
* `http_method`, `url`, `status_code`: Voor request context.
* `duration_ms`: Prestatiemeting.
* `trace_id` en `span_id**: **De heilige graal**. Dit koppelt je logs direct aan de specifieke trace in Jaeger/Zipkin, waardoor je de volledige reis van een request kunt volgen over meerdere services.
---
### **Samenvatting en Aanbevelingen**
1. **Logging Niveaus**: Gebruik `logger.debug()` voor gedetailleerde debug info, `logger.info()` voor normale operaties, `logger.warning()` voor waarschuwingen, en `logger.error()`/`logger.critical()` voor fouten.
2. **Centralisatie**: Gebruik tools zoals de **ELK Stack** (Elasticsearch, Logstash, Kibana), **Grafana Loki**, of cloudservices zoals **AWS CloudWatch** of **Google Cloud Logging** om je logs te centraliseren, doorzoeken en visualiseren.
3. **Tracing**: Draai **Jaeger** of **Zipkin** lokaal of in je cluster om de traces te visualiseren. OpenTelemetry exporteert daar naartoe.
4. **Performance**: Wees voorzichtig met het loggen van zeer grote request/response bodies in productie. Log enkel headers en metadata tenzij debuggen essentieel is.
5. **Gevoelige Data**: Filter gevoelige informatie (wachtwoorden, tokens, PII) *voordat* je logt. Schrijf een custom filter voor je logger.
Door deze stappen te volgen, transformeer je je eenvoudige Flask API naar een goed observeerbare applicatie die klaar is voor productie en complexe, gedistribueerde architecturen.