Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!
[NODE JS] Express'te Logger Middleware Oluşturma
Bir web uygulamasında loglama hayati önem taşır. Sunucunuza gelen istekleri, hata durumlarını, response sürelerini ve kullanıcı aktivitelerini kayıt altına almak hem geliştirme hem de production aşamasında olmazsa olmazdır. Bir sorun oluştuğunda loglar olmadan neyin yanlış gittiğini bulmak neredeyse imkansızdır.
Express'te loglama için en yaygın kullanılan paket morgan'dır. Morgan önceden tanımlanmış formatlarla HTTP isteklerini loglar. Ama bazen morgan'ın sunduğu formatlar yetmez ya da özel bilgiler loglamak istersiniz. İşte o zaman kendi logger middleware'inizi yazmanız gerekir.
Ben production'daki bir projede sadece console.log ile loglama yapıyordum. Sonra sunucu restart olduğunda tüm loglar uçtu. O günden sonra logları dosyaya yazmayı ve log rotation yapmayı öğrendim. Winston veya Pino gibi log kütüphaneleri bu işi çok kolaylaştırıyor ama temelde ne yaptıklarını bilmek için kendi logger'ınızı yazmak çok faydalı.
Logger middleware'inin temel görevi her isteğin detaylarını kaydetmektir: HTTP metodu, URL, status code, response süresi, istemci IP adresi ve user agent. Bunları bir araya getirip formatlanmış bir şekilde konsola veya dosyaya yazmak. Renkli konsol çıktısı geliştirme ortamında çok kullanışlı, production'da ise yapılandırılmış JSON logları tercih edilir.
Log seviyeleri de önemli bir kavram. DEBUG, INFO, WARN, ERROR gibi seviyeler kullanarak loglarınızı kategorize edebilirsiniz. Production'da sadece WARN ve ERROR loglarını tutmak disk alanından tasarruf sağlar. Geliştirme ortamında ise tüm seviyeleri açık tutarsınız.
Hassas verileri loglamaktan kaçının. Şifreler, kredi kartı numaraları, kişisel bilgiler gibi veriler loglara yazılmamalıdır. Bu hem KVKK hem de GDPR gibi düzenlemelere aykırıdır. Request body'yi loglarken hassas alanları maskelemeniz gerekir.
Log dosyalarının boyutu hızla büyüyebilir. Günlük olarak rotate etmek ve eski logları sıkıştırmak ya da silmek önemlidir. rotating-file-stream veya winston-daily-rotate-file paketleri bu işi otomatik yapar. Ben günlük 50GB trafik alan bir projede log rotation yapmayı unutmuştum ve disk dolduğunda sunucu çökmüştü. O deneyimden sonra log rotation'ı ilk günden ayarlıyorum.
Structured logging yani yapılandırılmış loglama modern uygulamalarda çok önemli. JSON formatında log tutmak logları filtrelemeyi, aramayı ve analiz etmeyi çok kolaylaştırır. ELK Stack (Elasticsearch, Logstash, Kibana) veya Grafana Loki gibi araçlarla bu logları görselleştirebilirsiniz.
Request ID ile logları ilişkilendirmek de çok faydalı bir pratik. Her isteğe benzersiz bir ID atayıp o istek boyunca tüm loglarda bu ID'yi kullanırsanız bir sorun oluştuğunda o isteğin tüm adımlarını kolayca takip edebilirsiniz. Buna distributed tracing'in temeli diyebiliriz.
JavaScript:
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
app.use(express.json());
// ===== RENKLI KONSOL LOGGER =====
const renkler = {{
reset: '\x1b[0m',
bright: '\x1b[1m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m',
}};
function statusRengi(code) {{
if (code >= 500) return renkler.red;
if (code >= 400) return renkler.yellow;
if (code >= 300) return renkler.cyan;
if (code >= 200) return renkler.green;
return renkler.white;
}}
function metodRengi(method) {{
const map = {{
GET: renkler.green,
POST: renkler.blue,
PUT: renkler.yellow,
DELETE: renkler.red,
PATCH: renkler.magenta,
}};
return map[method] || renkler.white;
}}
// Ana logger middleware
function loggerMiddleware(options = {{}}) {{
const {{
format = 'dev', // 'dev' veya 'json'
logToFile = false,
logDir = path.join(__dirname, 'logs'),
}} = options;
// Log dizinini olustur
if (logToFile && !fs.existsSync(logDir)) {{
fs.mkdirSync(logDir, {{ recursive: true }});
}}
return (req, res, next) => {{
const baslangic = Date.now();
const requestId = generateRequestId();
req.requestId = requestId;
// Response tamamlandiginda logla
res.on('finish', () => {{
const sure = Date.now() - baslangic;
const logVerisi = {{
requestId,
timestamp: new Date().toISOString(),
method: req.method,
url: req.originalUrl || req.url,
status: res.statusCode,
responseTime: `${{sure}}ms`,
contentLength: res.get('Content-Length') || '-',
ip: req.ip || req.connection.remoteAddress,
userAgent: req.get('User-Agent') || '-',
}};
if (format === 'json') {{
const jsonLog = JSON.stringify(logVerisi);
console.log(jsonLog);
if (logToFile) writeToFile(logDir, jsonLog);
}} else {{
// Renkli dev formati
const mRenk = metodRengi(req.method);
const sRenk = statusRengi(res.statusCode);
const reset = renkler.reset;
const line = `${{renkler.bright}}[${{logVerisi.timestamp.split('T')[1].split('.')[0]}}]${{reset}} `
+ `${{mRenk}}${{req.method.padEnd(7)}}${{reset}} `
+ `${{req.originalUrl}} `
+ `${{sRenk}}${{res.statusCode}}${{reset}} `
+ `${{sure}}ms `
+ `${{renkler.cyan}}${{logVerisi.contentLength}}${{reset}}`;
console.log(line);
if (logToFile) writeToFile(logDir, `[${{logVerisi.timestamp}}] ${{req.method}} ${{req.originalUrl}} ${{res.statusCode}} ${{sure}}ms`);
}}
}});
next();
}};
}}
function generateRequestId() {{
return Date.now().toString(36) + '-' + Math.random().toString(36).substr(2, 8);
}}
function writeToFile(logDir, content) {{
const tarih = new Date().toISOString().split('T')[0]; // 2024-01-15
const dosya = path.join(logDir, `access-${{tarih}}.log`);
fs.appendFileSync(dosya, content + '\n');
}}
// ===== HATA LOGGER =====
function errorLogger(logDir) {{
if (!fs.existsSync(logDir)) {{
fs.mkdirSync(logDir, {{ recursive: true }});
}}
return (err, req, res, next) => {{
const hataLog = {{
timestamp: new Date().toISOString(),
requestId: req.requestId,
method: req.method,
url: req.originalUrl,
error: {{
message: err.message,
stack: err.stack,
status: err.status || 500,
}},
ip: req.ip,
}};
console.error(`${{renkler.red}}[HATA]${{renkler.reset}} ${{err.message}}`);
const tarih = new Date().toISOString().split('T')[0];
const dosya = path.join(logDir, `error-${{tarih}}.log`);
fs.appendFileSync(dosya, JSON.stringify(hataLog) + '\n');
next(err);
}};
}}
// Middleware'leri ekle
app.use(loggerMiddleware({{
format: process.env.NODE_ENV === 'production' ? 'json' : 'dev',
logToFile: true,
logDir: path.join(__dirname, 'logs'),
}}));
// Ornek route'lar
app.get('/api/urunler', (req, res) => {{
res.json([{{ id: 1, ad: 'Laptop' }}, {{ id: 2, ad: 'Telefon' }}]);
}});
app.post('/api/urunler', (req, res) => {{
res.status(201).json({{ id: 3, ...req.body }});
}});
app.get('/api/hata', (req, res, next) => {{
next(new Error('Test hatasi - bu bilerek olusturuldu'));
}});
// Hata logger ve handler
app.use(errorLogger(path.join(__dirname, 'logs')));
app.use((err, req, res, next) => {{
res.status(err.status || 500).json({{
hata: err.message,
requestId: req.requestId,
}});
}});
app.listen(3000, () => {{
console.log('Logger middleware sunucusu port 3000\'de');
}});
Logger middleware'inizi bir kere düzgün yazıp tüm projelerinizde kullanabilirsiniz. Modüler tutun, opsiyonlarla yapılandırılabilir olsun ve farklı ortamlar için farklı formatları desteklesin. Zamanla kendi kütüphaneniz haline gelir ve bu sizi çok hızlandırır.
Emeğiniz ve katkınız için teşekkür ederiz!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)
Benzer konular
Altın Konu
Next.js'de API Oluşturma Ve Kullanma
- Cevaplar
- 12
- Görüntüleme
- 1K
