Logging Best Practices
Logging Best Practices: Fehler finden und verstehen
Gutes Logging ist die Basis für Debugging und Monitoring. Lernen Sie, wie Sie effektiv loggen ohne in Daten zu ertrinken.
Log Levels
| Level | Verwendung | Beispiel |
|---|---|---|
| FATAL/CRITICAL | Anwendung kann nicht weiterlaufen | Datenbank nicht erreichbar |
| ERROR | Fehler, der behandelt werden sollte | API-Request fehlgeschlagen |
| WARN | Ungewöhnlich, aber handhabbar | Veraltete API verwendet |
| INFO | Wichtige Ereignisse | Server gestartet, User eingeloggt |
| DEBUG | Entwickler-Details | Funktionsparameter, Zwischenergebnisse |
| TRACE | Sehr detailliert | Jeder Funktionsaufruf |
Was loggen?
✅ Immer loggen:
- Anwendungsstart und -stop
- Authentifizierung (Login, Logout, fehlgeschlagen)
- Kritische Geschäftsoperationen
- Externe API-Aufrufe und Responses
- Fehler und Exceptions mit Stack Trace
- Performance-Metriken (langsame Queries)
❌ Nie loggen:
- Passwörter und Tokens
- Kreditkartennummern
- Persönliche Daten (DSGVO!)
- API-Keys und Secrets
Strukturiertes Logging (JSON)
// ❌ Unstrukturiert (schwer zu parsen)
console.log('User 123 logged in from 192.168.1.1 at 2024-01-15 10:30:00');
// ✅ Strukturiert (JSON)
{
"timestamp": "2024-01-15T10:30:00.000Z",
"level": "info",
"message": "User logged in",
"userId": 123,
"ip": "192.168.1.1",
"userAgent": "Mozilla/5.0...",
"requestId": "abc-123-def"
}
PHP: Monolog
composer require monolog/monolog
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Formatter\JsonFormatter;
// Logger erstellen
$log = new Logger('app');
// Handler für verschiedene Outputs
$log->pushHandler(new StreamHandler('php://stdout', Logger::DEBUG));
$log->pushHandler(new RotatingFileHandler('/var/log/app/app.log', 14, Logger::INFO));
// JSON-Format
$handler = new StreamHandler('/var/log/app/app.json', Logger::INFO);
$handler->setFormatter(new JsonFormatter());
$log->pushHandler($handler);
// Logging
$log->info('User logged in', ['userId' => 123, 'ip' => $_SERVER['REMOTE_ADDR']]);
$log->error('Database error', ['exception' => $e->getMessage()]);
Node.js: Winston
npm install winston
const winston = require('winston');
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
// In Development auch Console
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple(),
}));
}
// Logging
logger.info('Server started', { port: 3000 });
logger.error('Database connection failed', { error: err.message });
Python: logging
import logging
import json
# JSON Formatter
class JsonFormatter(logging.Formatter):
def format(self, record):
log_record = {
'timestamp': self.formatTime(record),
'level': record.levelname,
'message': record.getMessage(),
'module': record.module,
}
if record.exc_info:
log_record['exception'] = self.formatException(record.exc_info)
return json.dumps(log_record)
# Logger konfigurieren
logger = logging.getLogger('app')
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
logger.addHandler(handler)
# Logging
logger.info('User logged in', extra={'userId': 123})
logger.error('Database error', exc_info=True)
Request ID / Correlation ID
Eine ID pro Request für zusammenhängende Logs:
// Middleware: Request ID generieren
app.use((req, res, next) => {
req.requestId = req.headers['x-request-id'] || uuid();
res.setHeader('x-request-id', req.requestId);
next();
});
// Bei jedem Log mitgeben
logger.info('Processing order', {
requestId: req.requestId,
orderId: order.id
});
// So können alle Logs einer Anfrage gefunden werden:
// grep "abc-123-def" combined.log
Log Rotation
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 www-data www-data
postrotate
systemctl reload myapp
endscript
}
Zentrales Logging
Bei mehreren Servern: Logs zentral sammeln
- ELK Stack: Elasticsearch, Logstash, Kibana
- Loki + Grafana: Leichtgewichtiger
- Cloud: CloudWatch, Stackdriver, Papertrail
Log-Meldungen formulieren
// ❌ Schlecht
logger.error('Error');
logger.info('Done');
logger.debug('Here');
// ✅ Gut
logger.error('Failed to send email', {
recipient: email,
error: err.message,
retryCount: 3
});
logger.info('Order processed successfully', {
orderId: order.id,
total: order.total,
processingTime: endTime - startTime
});
💡 Tipp:
Loggen Sie so, dass Sie Probleme auch um 3 Uhr nachts verstehen können. Kontext ist alles!