تسجيل الدخول في تطبيقات JavaScript: أفضل الممارسات عملياً
تسجيل الدخول ليس مجرد كتابة رسائل في وحدة التحكم. في بيئة الإنتاج، يصبح تسجيل الدخول المُعد بشكل صحيح الأداة الرئيسية للمراقبة وتصحيح الأخطاء والتدقيق. بدونه، أنت تعمل بشكل أعمى. في هذه المقالة، سنستعرض أفضل ممارسات تسجيل الدخول لتطبيقات JavaScript على Node.js، من اختيار المكتبة إلى إعداد تدوير الملفات. جميع أمثلة الكود جاهزة للاستخدام.
1. لماذا console.log سيء؟
في مرحلة التطوير، نستخدم جميعاً console.log. إنه سريع ومريح. لكن في الإنتاج، هذا النهج خطير:
- لا توجد مستويات تسجيل. لن تتمكن من تصفية الأخطاء من الرسائل المعلوماتية.
- حظر متزامن. يمكن لـ
console.logالقياسي إبطاء التطبيق عند تدفق كبير من الطلبات. - غياب الهيكلة. لا يمكن تحليل سجلات JSON دون أدوات إضافية.
- لا يوجد تدوير. سينمو ملف السجل إلى ما لا نهاية حتى يملأ القرص.
بدلاً من ذلك، استخدم المكتبات الاحترافية. الأكثر شيوعاً في Node.js هما Winston و Pino.
2. اختيار المكتبة: Winston مقابل Pino
كلا المكتبتين تحلان نفس المشكلة، لكن لهما أولويات مختلفة.
Winston - شامل ومرن
Winston هو "سكين الجيش السويسري" لتسجيل الدخول. يدعم العديد من وسائل النقل (ملفات، وحدة تحكم، HTTP، قواعد بيانات) ويسهل تخصيصه.
const winston = require('winston');
const logger = winston.createLogger({ level: 'info', format: winston.format.json(), transports: [ new winston.transports.File({ filename: 'error.log', level: 'error' }), new winston.transports.File({ filename: 'combined.log' }), ],});
// في التطوير نضيف الإخراج إلى وحدة التحكمif (process.env.NODE_ENV !== 'production') { logger.add(new winston.transports.Console({ format: winston.format.simple(), }));}
logger.info('الخادم يعمل على المنفذ 3000');logger.error('خطأ في الاتصال بقاعدة البيانات', { db: 'postgres' });Pino - السرعة أولاً
Pino يُقدم نفسه كأسرع مسجل لـ Node.js. إنه أسرع بـ 5-6 مرات من Winston بفضل استخدام sonic-boom (الكتابة غير المتزامنة). مثالي للمشاريع عالية التحميل.
const pino = require('pino');
const logger = pino({ level: process.env.LOG_LEVEL || 'info', transport: { target: 'pino/file', options: { destination: './app.log' }, },});
logger.info({ user: 'admin' }, 'المستخدم قام بتسجيل الدخول');logger.error({ err: new Error('Timeout') }, 'الطلب تجاوز الحد المسموح');نصيحة: للخدمات المصغرة وواجهات API ذات التحميل العالي، اختر Pino. للتكوينات المعقدة مع وسائل نقل متعددة، اختر Winston.
3. مستويات التسجيل: لا تكتب كل شيء في info
استخدم مقياس المستويات القياسي (حسب الأهمية المتزايدة):
trace/debug— فقط للتطوير. تصحيح أخطاء تفصيلي.info— التشغيل العادي للتطبيق: بدء التشغيل، الطلبات الناجحة، أحداث الأعمال.warn— مشاكل محتملة: طلبات بطيئة، نقص في الذاكرة، طرق قديمة.error— استثناءات، أعطال، انهيارات. يجب أن تكون دائماً في ملف منفصل أو نظام مراقبة.fatal— أخطاء حرجة، لا يمكن للتطبيق بعدها مواصلة العمل.
قم بتعيين متغير البيئة LOG_LEVEL لتغيير مستوى التصفية دون إعادة تشغيل الكود:
// مثال مع Winstonconst logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', // ...});
// في