• בלוג
  • כתיבת קובץ לוג משרת Express באמצעות Winston

כתיבת קובץ לוג משרת Express באמצעות Winston

וינסטון היא ספריית לוגים ל Node.JS שיודעת לעשות שני דברים מאוד טוב: היא יודעת לשלוח את הלוגים שלכם להרבה סוגים של יעדים, והיא יודעת לפרמט את הלוגים שלכם בכל צורה שתבחרו. החיבור בין שני הדברים הוא קסום כי עם וינסטון אני יכול בקלות לכתוב את הלוגים לקונסול במצב פיתוח ולקובץ במצב ייצור, או גם לקובץ וגם לקונסול, או לשרת לוגים מרוחק בענן, וכל זה באמצעות שינוי קטן בקונפיגורציה. בואו נראה איך להתקין ולהשתמש בספריה.

1. כמה דוגמאות לשמירת לוג עם Winston

אני מתחיל בפרויקט Node.JS רגיל (ללא אקספרס) ומתקין את וינסטון עם:

$ npm install --save winston

עכשיו אפשר לכתוב קובץ demo1.js עם התוכן הבא:

const winston = require('winston');

const logger = winston.createLogger({
  level: 'debug',
  format: winston.format.simple(),
  transports: [
    new winston.transports.File({ filename: 'logs/dev.log' }),
    new winston.transports.Console(),
  ],
});

logger.info("Program Starts");

for (let i=0; i < 10; i++) {
  logger.debug(`Counting ... ${i}`);
}

logger.info("Program Ends");

זה היה פשוט נכון? אנחנו יוצרים לוגר שיקח את כל ההודעות החל מרמת debug (שזה כמעט כולן... היחידה שלא תישמר תהיה logger.silly) ויכתוב אותן גם לקובץ וגם לקונסול. התוכנית עצמה פשוט משתמשת בלוגר שיצרנו, ובעולם האמיתי נשמור את קוד יצירת הלוגר בקובץ משלו וכל מי שיצטרך את הלוגר יוכל להפעיל require לאותו קובץ.

הפעלת התוכנית מדפיסה את הפלט הבא, וגם כותבת אותו לקובץ logs/dev.log:

info: Program Starts
debug: Counting ... 0
debug: Counting ... 1
debug: Counting ... 2
debug: Counting ... 3
debug: Counting ... 4
debug: Counting ... 5
debug: Counting ... 6
debug: Counting ... 7
debug: Counting ... 8
debug: Counting ... 9
info: Program Ends

אבל בינינו זה לא הלוג הכי אינפורמטיבי בעולם. בואו נוסיף Timestamp כדי לדעת מתי נכתבה כל הודעה:

const winston = require('winston');

const logger = winston.createLogger({
  level: 'debug',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.printf(({ level, message, timestamp }) => (
      `${timestamp} ${level}: ${message}`
    )),
  ),
  transports: [
    new winston.transports.File({ filename: 'logs/dev.log' }),
    new winston.transports.Console(),
  ],
});

logger.info("Program Starts");

for (let i=0; i < 10; i++) {
  logger.debug(`Counting ... ${i}`);
}

logger.info("Program Ends");

והפלט עכשיו:

2021-07-09T17:11:43.730Z info: Program Starts
2021-07-09T17:11:43.731Z debug: Counting ... 0
2021-07-09T17:11:43.732Z debug: Counting ... 1
2021-07-09T17:11:43.732Z debug: Counting ... 2
2021-07-09T17:11:43.732Z debug: Counting ... 3
2021-07-09T17:11:43.732Z debug: Counting ... 4
2021-07-09T17:11:43.733Z debug: Counting ... 5
2021-07-09T17:11:43.733Z debug: Counting ... 6
2021-07-09T17:11:43.733Z debug: Counting ... 7
2021-07-09T17:11:43.733Z debug: Counting ... 8
2021-07-09T17:11:43.733Z debug: Counting ... 9
2021-07-09T17:11:43.733Z info: Program Ends

פוקנציות הפורמט מגיעות מספריית logform ואפשר למצוא כאן רשימה של כל הפורמטים בספריה: https://github.com/winstonjs/logform

2. חיבור וינסטון לאקספרס

בפרויקט אקספרס כבר יש לנו מידלוור אחד שכותב לוגים - זהו מורגן. תשמחו לדעת שאין בעיה לחבר בין השניים, רק צריך לדעת לכתוב את שורת הקוד הנכונה. ניצור פרויקט אקספרס חדש ובתוכו אני יוצר קובץ בשם logger.js עם התוכן הבא:

const winston = require('winston');

const logger = winston.createLogger({
  level: 'debug',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.printf(({ level, message, timestamp }) => (
      `${timestamp} ${level}: ${message}`
    )),
  ),
  transports: [
    new winston.transports.File({ filename: 'logs/dev.log' }),
    new winston.transports.Console(),
  ],
});

logger.stream = {
  write(message) {
    logger.info(message);
  }
};

module.exports = logger;

ב app.js של פרויקט express חדש שנוצר על ידי express-generator השורות הבאות אחראיות על יצירת הלוגר מורגן:

var logger = require('morgan');

app.use(logger('dev'));

אני מחליף אותן לקוד הבא:

var morgan = require('morgan');
var logger = require('./logger');
app.use(morgan(':method :url :status :res[content-length] - :response-time ms', { stream: logger.stream }));

ועכשיו בהפעלת השרת וגלישה מדפדפן אני מקבל גם לקונסול וגם לקובץ את התוכן הבא:

2021-07-09T17:26:31.663Z info: GET / 200 170 - 104.904 ms
2021-07-09T17:26:31.705Z info: GET /stylesheets/style.css 304 - - 1.058 ms

3. עוד כמה יעדי לוג

בעמוד הבא תוכלו למצוא רשימה די גדולה של יעדים ש Winston יודע לכתוב אליהם את ההודעות שלכם: https://github.com/winstonjs/winston/blob/master/docs/transports.md

בין היעדים שאני אהבתי יש את MongoDB, Syslog, Amazon Cloudwatch, Elasticsearch, Papertrail וכמובן Slack.