Logs NodeJS là gì ? Và tại sao nên dùng ?

Log là gì ? Tại sao nên dùng Log ? Và nên dùng log như thế nào là đúng cách ? Chúng ta sẽ cùng tìm hiểu những điều đó.


1047

Logs NodeJS là gì ?

console.log ()

Là developer thì không ai xa lạ với console.log (). Nó có hàm tương tự như console.error (), console.info () và console.warn (). Tất cả chỉ là đều dựa trên một chuẩn:

console.log(level, message)

Debug module là gì ?

Với rất nhiều package sử dụng để “debug”. Chắc chắn, chúng ta có thể chạy thử và nhận output cho trên phần console. Vấn đề là, hầu hết chúng ta có thể làm với nó. Chúng ta có thể chuyển hướng để xuất log vào một file hoặc một kiểu khác theo ý muốn.

Bạn có thể bật debug lên để có thêm thông tin về những gì đang diễn ra trong middleware của web như Express và Koa khi back-end của bạn nhận request bất kì từ người dùng. Framework tốt sẽ cung cấp cho bạn một middleware ghi log.

Middleware là gì ?

Middleware là những đoạn mã trung gian nằm giữa các request và response. Nó nhận các request, thi hành các mệnh lệnh tương ứng trên request đó. Sau khi hoàn thành nó response (trả về) hoặc chuyển kết quả ủy thác cho một Middleware khác trong hàng đợi.

Ví dụ: Express là một trong những framework phổ biến nhất. Bạn có thể thiết lập middleware như thế này

Application

const app = express();
const loggingMiddleware = require(‘my-logging-middleware’);
app.use(loggingMiddleware);

Router

const router = express.Router();
const routeLoggingMiddleware = require(‘my-route-logging-middleware’);
router.use(routeLoggingMiddleware);

Error

const app = express();
const errorLoggingMiddleware = require(‘my-error-logging-middleware’);
app.use(errorLoggingMiddleware);

Có một pattern để setup middleware trong Express. Bạn cũng có thể đặt middleware bất kì nơi nào bạn muốn

// Đừng làm như thế này.

app.use(function(req, res, next) {
  console.log(req.url)
  next()
}

Chọn package nào để ghi logs

Hướng dẫn lần này sẽ chọn Winston để hướng dẫn cho các bạn . Điều tốt nó có thể đưa ra output nhiều kiểu

Node.js thì không như vậy, bạn vẫn không thể đưa output của debug ra các loại transport khác. Nếu không, thì không cần package rồi ^^

Setup Winston trong Express như sau

‘use strict’
const winston = require(‘winston’)
const remoteLog = new winston.transports.Http({
   host: “127.0.0.1”,
   port: 3000,
   path: “/errors”
})
const consoleLog = new winston.transports.Console()
module.exports = {
   requestLogger: createRequestLogger([consoleLog]),
   errorLogger: createErrorLogger([remoteLog, consoleLog])
}
function createRequestLogger(transports) {
   const requestLogger = winston.createLogger({
       format: getRequestLogFormatter(),
       transports: transports
   })
   return function logRequest(req, res, next) {
       requestLogger.info({req, res})
       next()
   }
}
function createErrorLogger(transports) {
   const errLogger = winston.createLogger({
       level: ‘error’,
       transports: transports
   })
   return function logError(err, req, res, next) {
       errLogger.error({err, req, res})
       next()
   }
}
function getRequestLogFormatter() {
   const {combine, timestamp, printf} = winston.format;
   return combine(
       timestamp(),
       printf(info => {
           const {req, res} = info.message;
           return ${info.timestamp} ${info.level}: ${req.hostname}${req.port || ”}${req.originalUrl};
       })
   );
}

Ưu điểm tốt nhất trong Winston là dễ cấu hình. Với tính năng lọc, bạn có thể thiết lập nhiều transport khác nhau , chọn nhiều kiểu xuất ra và chỉnh sửa mọi thứ theo ý của bạn . Trong đoạn code trên, tôi chỉ viết một log cơ bản.

Bạn có thể chọn host, port, và cả phần path để nhận logs ghi vào

‘use strict’
const winston = require(‘winston’)
const remoteLog = new winston.transports.Http({
   host: “127.0.0.1”,
   port: 3000,
   path: “/errors”
})
const consoleLog = new winston.transports.Console()
module.exports = {
   requestLogger: createRequestLogger([consoleLog]),
   errorLogger: createErrorLogger([remoteLog, consoleLog])
}
function createRequestLogger(transports) {
   const requestLogger = winston.createLogger({
       format: getRequestLogFormatter(),
       transports: transports
   })
   return function logRequest(req, res, next) {
       requestLogger.info({req, res})
       next()
   }
}
function createErrorLogger(transports) {
   const errLogger = winston.createLogger({
       level: ‘error’,
       transports: transports
   })
   return function logError(err, req, res, next) {
       errLogger.error({err, req, res})
       next()
   }
}
function getRequestLogFormatter() {
   const {combine, timestamp, printf} = winston.format;
   return combine(
       timestamp(),
       printf(info => {
           const {req, res} = info.message;
           return ${info.timestamp} ${info.level}: ${req.hostname}${req.port || ”}${req.originalUrl};
       })
   );
}

Thiết lập này sẽ tạo ra middleware của log bằng Winston. Các middleware sẽ được viết trong phần input của express. Nhưng hãy ghi nhớ phần này nhé

Middleware có thể tái sử dụng nhiều lần. Bạn chỉ cần nhớ pattern của framework bạn muốn sử dụng vì mỗi framework đều có pattern riêng. Mỗi lần sử dụng lại , bạn chỉ cần include file middleware đó

Nếu bạn đang sử dụng Retrace, package này bạn phải gắn đúng vào từng model thông qua Stackify transport. Và với Express, bạn có thể sử dụng Stackify . Rất đơn giản, chỉ cần làm theo những bước sau

var stackify = require(‘stackify-logger’)

// tất cả các log sẽ ghi vào Retrace

stackify.start({apiKey: ‘***’, env: ‘dev’})

// chỉ những đoạn log trong route Express mới được ghi vào Retrace

app.use(stackify.expressExceptionHandler)

// hoặc thêm phần lưu trữ log Stackify

require(‘winston-stackify’).Stackify
winstonLogger.add(winston.transports.Stackify, {storage: stackify})
require(‘winston-stackify’).Stackify
const stackifyTransport = new winston.transports.Stackify({storage: stackify})

Logs trên server

Bất kể bạn đang sử dụng môi trường lưu trữ nào, bạn cần để mắt đến điều này. Nên gửi tất cả các logs đến một hướng nhất định

Log trên server, log từ database, và log từ app. Tất cả các log nên được ghi lại một cách rõ ràng để dễ kiểm tra

Với hiện tai, tình trạng mạng ngàn cân treo sợ tóc, bạn nên ghi log offline và khi kết nối được mạng nên up lên ngay.

Nên ghi lại những log nào ?

Chúng ta phải xác định và chọn ghi lại log với những mục đích khác nhau. Và đây là những log với những mục đích của từng loại

  • Error
  • Warn
  • Info
  • Verbose
  • Debug

Kết luận

Chúng ta nên ghi log lại vì những điều sau:

Hiệu suất (Performance): Người lập trình lẫn người dùng đều quan tâm đến điều này, nên hãy ghi lại những log có ảnh hưởng trực tiếp hiệu suất.

Đặc biệt khi debug: Bạn luôn xem log trước khi xuất ra màn hình để xem phần data có đúng không. Và khi như vậy bạn sẽ biết lỗi xảy ra tại đâu, sẽ dễ dàng fix bug hơn

Bạn có thể xem thêm bài Từng bước tạo RESTful API với Node.js , Express, MySQL sử dụng ngay logs 😀


Like it? Share with your friends!

1047