„Schon wieder ist die Anwendung abgestürzt und niemand weiß warum!“ – Kennt ihr das? Als wir letzte Woche bei einem unserer Enterprise-Kunden einen kritischen Production-Bug fixen mussten, wurde uns wieder einmal bewusst: Ohne vernünftiges Logging ist Debugging wie Stochern im Nebel.
Warum Winston.js die erste Wahl für Node.js-Logging ist
In der Node.js-Welt gibt es viele Logging-Libraries, aber Winston hat sich als De-facto-Standard etabliert. Und das aus gutem Grund! Bei Never Code Alone setzen wir Winston in allen größeren Node.js-Projekten ein – von E-Commerce-Plattformen bis zu hochskalierbaren Microservices.
Die Stärken von Winston auf einen Blick:
- Multiple Transports: Logs gleichzeitig in Dateien, Datenbanken und externe Services schreiben
- Log-Level Management: Von debug bis error – alles sauber strukturiert
- Performance: Auch bei tausenden Requests pro Sekunde keine Einbußen
- Erweiterbarkeit: Custom Formatter und eigene Transports sind kein Problem
Setup: So startet ihr mit Winston durch
Schluss mit console.log()! Hier kommt euer Production-Ready Logging-Setup:
const winston = require('winston');
const { combine, timestamp, json, printf, colorize } = winston.format;
// Custom Format für lokale Entwicklung
const devFormat = printf(({ level, message, timestamp, ...metadata }) => {
let msg = `${timestamp} [${level}] : ${message} `;
if (Object.keys(metadata).length > 0) {
msg += JSON.stringify(metadata);
}
return msg;
});
// Production Logger Konfiguration
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: combine(
timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
}),
process.env.NODE_ENV === 'production' ? json() : devFormat
),
transports: [
// Console Output
new winston.transports.Console({
format: process.env.NODE_ENV !== 'production'
? combine(colorize(), devFormat)
: json()
}),
// File Rotation für Production
new winston.transports.File({
filename: 'logs/error.log',
level: 'error',
maxsize: 5242880, // 5MB
maxFiles: 5
}),
new winston.transports.File({
filename: 'logs/combined.log',
maxsize: 5242880,
maxFiles: 5
})
]
});
// Graceful Shutdown
process.on('unhandledRejection', (ex) => {
logger.error('Unhandled Rejection', ex);
process.exit(1);
});
module.exports = logger;
Best Practices aus der Praxis
Nach vier Jahren intensiver Winston-Nutzung in Enterprise-Projekten haben wir bei Never Code Alone einige goldene Regeln entwickelt:
1. Strukturierte Logs sind Gold wert
Vergesst unstrukturierte String-Logs! Mit strukturierten Daten könnt ihr später in Elasticsearch oder Splunk richtig durchstarten:
// ❌ So nicht!
logger.info(`User ${userId} logged in from ${ip}`);
// ✅ So macht ihr es richtig!
logger.info('User login', {
userId,
ip,
userAgent: req.headers['user-agent'],
timestamp: new Date().toISOString()
});
2. Context ist King
Nutzt Child Logger für Request-spezifische Kontexte:
app.use((req, res, next) => {
req.logger = logger.child({
requestId: req.id,
method: req.method,
url: req.url
});
next();
});
// In euren Routes
app.get('/api/users/:id', (req, res) => {
req.logger.info('Fetching user', { userId: req.params.id });
// Der requestId wird automatisch mitgeloggt!
});
3. Performance Monitoring inklusive
Messt die Performance kritischer Operationen direkt mit:
const profiler = logger.startTimer();
await heavyDatabaseOperation();
profiler.done({ message: 'Database query completed' });
// Loggt automatisch die Ausführungszeit!
Integration mit externen Services
In Production-Umgebungen reichen lokale Log-Dateien nicht aus. Hier unsere bewährte Stack-Kombination:
Elasticsearch + Kibana Setup
const ElasticsearchTransport = require('winston-elasticsearch');
const esTransportOpts = {
level: 'info',
clientOpts: {
node: process.env.ELASTICSEARCH_URL,
auth: {
username: process.env.ELASTIC_USER,
password: process.env.ELASTIC_PASSWORD
}
},
index: 'logs-app',
pipeline: 'timestamp_pipeline'
};
logger.add(new ElasticsearchTransport(esTransportOpts));
Slack-Alerts für kritische Fehler
const SlackHook = require('winston-slack-webhook-transport');
logger.add(new SlackHook({
webhookUrl: process.env.SLACK_WEBHOOK_URL,
level: 'error',
formatter: (info) => ({
text: `🚨 *${info.level.toUpperCase()}* in ${process.env.APP_NAME}`,
attachments: [{
color: 'danger',
fields: [{
title: 'Error Message',
value: info.message,
short: false
}, {
title: 'Stack Trace',
value: ````${info.stack || 'No stack trace'}````,
short: false
}]
}]
})
}));
Häufige Fallstricke und wie ihr sie vermeidet
Memory Leaks durch falsche Transport-Konfiguration
// ❌ Gefährlich: Unbegrenzte In-Memory Queue
const transport = new winston.transports.Console({
stderrLevels: ['error']
});
// ✅ Sicher: Mit Limits arbeiten
const transport = new winston.transports.Console({
stderrLevels: ['error'],
handleExceptions: true,
handleRejections: true
});
Sensible Daten in Logs
Implementiert einen Sanitizer für sensible Daten:
const sanitizer = winston.format((info) => {
// Passwörter entfernen
if (info.password) info.password = '***REDACTED***';
// Kreditkarten maskieren
if (info.creditCard) {
info.creditCard = info.creditCard.replace(/d{12}/, '************');
}
return info;
});
logger.add(sanitizer());
Testing nicht vergessen!
Eure Logs sind Teil der Anwendung – testet sie auch:
describe('Logger Tests', () => {
it('should log errors with correct format', () => {
const mockTransport = new winston.transports.Stream({
stream: new WritableStream()
});
testLogger.add(mockTransport);
testLogger.error('Test error', { code: 'TEST_001' });
expect(mockTransport.stream.lastWrite).toMatchObject({
level: 'error',
message: 'Test error',
code: 'TEST_001'
});
});
});
Fazit: Logging als Investition in die Zukunft
Gutes Logging ist wie eine Versicherung – ihr braucht es erst, wenn es zu spät ist. Mit Winston.js habt ihr ein mächtiges Werkzeug an der Hand, das euch im Ernstfall den Arsch rettet.
Bei Never Code Alone haben wir durch konsequentes Logging die Mean Time To Resolution (MTTR) bei kritischen Bugs um über 60% reduziert. Das Investment in ein vernünftiges Logging-Setup zahlt sich schneller aus, als ihr denkt!
Ihr wollt Winston.js in eurem Projekt einführen?
Unsere Experten helfen euch bei der Implementierung einer Production-Ready Logging-Strategie. Von der Architektur bis zur Integration in eure bestehende Monitoring-Landschaft – wir haben die Erfahrung aus dutzenden Enterprise-Projekten.