Logger Nodejs là gì? Sử dụng Winston là phải chuyên nghiệp như thế này

Nội dung bài viết

Không nói quá chứ bất kỳ chương trình phần mềm nào cũng cần phải có file quản lý log một cách chuyên nghiệp. Chính vì lẽ đó mỗi ngôn ngữ lập trình đều có những module đi kèm như java thì có Log2j, và trong nodejs thì có rất nhiều chẳng hạn như Winston, log4js, Bunyan. Và trong bài viết này thì tôi chỉ đề cập đến Winston vì ở đó có những tất cả mà một người làm backend như tôi đang tìm kiếm. Và nếu như ai đọc xem bài viết "Nodejs Series: Bắt đầu!" thì có thể nhớ ra rằng, log là luôn cần thiết cho việc quản lý hệ thống.


Logger Nodejs là gì?

Logger Nodejs là một cụm từ trong lập trình có nghĩa là ghi lại bất cứ những thao tác của người dùng, ngoài ra còn có ghi lại những error, info, bugs trong console hoặc truy cập vào cơ sở dữ liệu bị lỗi. Điều đó giúp cho những người quản lý hệ thống theo dõi và phát hiện ngay hoặc vào lúc nào cần thiết. Đó là một việc quan trọng, nó nắm giữ việc hệ thống có chạy trơn tru hay không. 

Trong bài viết này chúng tôi sẽ giới thiệu và tập trung vào việc ghi log có tên là Winston , một thư viện ghi nhật ký cực kỳ linh hoạt và là giải pháp ghi nhật ký phổ biến nhất hiện có cho các ứng dụng Node.js , dựa trên thống kê tải xuống NPM. Ngoài là thì chúng tôi cũng có mọt gợi ý khác về việc ghi log http request với việc sủ dụng morgan ở bài trước đã được nhiều bạn đón nhận. morgan là gì? Thì bạn có thể tìm hiểu ở bài trước.


Winston là gì?

Winston được sử dụng có việc ghi log trong hệ thống nào sử dụng Node. Các tính năng của Winston bao gồm hỗ trợ nhiều tùy chọn lưu trữ và cấp độ nhật ký, truy vấn nhật ký và thậm chí cả một trình biên dịch tích hợp. Hướng dẫn này sẽ chỉ cho bạn cách sử dụng Winston để ghi lại log của ứng dụng Node / Express mà chúng tôi sẽ tạo như một phần của quy trình này. Sau khi hoàn thành hướng dẫn này, bạn sẽ một ứng dụng Node / Express nhỏ. Bạn cũng sẽ được triển khai Winston để ghi các lỗi và thông báo vào một file hoặc vào console của hệ thống. 


Và tôi cũng đã tạo một source code dành cho những bạn nào theo dõi bài viết này có thể pull github


Install Winston với nodejs

AnonyStick$ npm i winston --save

Đương nhiên là các bạn phải biết install express và nodejs


winston sử dụng cơ bản

Log sẽ được in vào console của Node theo mặc định nếu như bạn sử dụng dòng code cơ bản dưới đây.

const winston = require('winston')
winston.log('info', 'Hello Anonystick.com!')
winston.info('Hello Anonystick.com')

Chúng tôi cũng có thể sử dụng phương pháp sau để tạo nhiều phiên bản:

const logger1 = winston.createLogger()
const logger2 = winston.createLogger()
logger1.info('logger1', 'Hello Anonystick.com!')
logger2.info('logger2', 'Hello Anonystick.com!')


Ghi log trong NodeJS vào file sử dụng winston

Nodejs write log to file - Trong hầu hết các trường hợp mà tôi gặp phải, tôi không chỉ muốn ghi log trong console của nodejs mà còn muốn ghi log vào một file mà tôi muốn quản lý thì thực hiện điều này rất đơn giản trong Winston có tên là "combined.log"

// luu vao mot file de de quan lys : combined.log

const logger = winston.createLogger({
    transports: [
       new winston.transports.Console(),
       new winston.transports.File({filename: 'combined.log'})
    ]
})

Thì tất cả những log sẽ được ghi vào đó và chúng ta có thể xem lại bất cứ khi nào chúng ta muốn.


Format winston

Theo mặc định, winston sẽ ghi lod có định dạng JSON. Nội dung của nhật ký nằm trong trường thông báo.Nhưng đối với chúng ta thì chúng ta nhiều trường hợp muốn tổ chức rõ hơn về log thì chúng ta có thể customize việc này một cách dễ dàng, đó cũng là một trong những điều mà tôi thích nó.

const logger = winston.createLogger({
  format: winston.format.combine(
    winston.format.label({ label: 'Demo anonystick:' }),
    winston.format.timestamp(),
    winston.format.prettyPrint(),
  ),
  transports: [new winston.transports.Console()]
})
logger.info('hello anonystick.com')

Xuất ra như thế này:

{
  message: 'hello anonystick.com',
  level: 'info',
  label: 'Demo anonystick:',
  timestamp: '2020-10-09T04:13:45.309Z'
}

Chúng ta hoàn toàn có thể tự mình kiểm soát định dạng của nhật ký, chẳng hạn:

const customFormat = winston.format.printf((info) => {
  return `[Muon gi thi tu di ma dinh dang] ${info.timestamp}:${info.label}:${info.message}`
})

Với những chia sẻ như vậy có nhiều bạn sẽ tặc lưỡi, "hứ! Nếu chỉ vậy thì đâu cần winston đâu". Đúng đấy, có nhiều bạn sẽ nói như vậy nếu như đọc đến đây, trên đây là những chức năng cơ bản cho việc quản lý log Nodejs. Nhưng bài viết chưa kết thúc, hãy xem những chức năng còn lại có thể bạn sẽ suy nghĩ khác.


Kích thước của file log quá lớn thì làm sao?

Đây là một trong những câu hỏi được nhiều người làm hệ thống quan tâm nhất. Nếu như file log quá lớn thì việc truy xuất log rất khó quản lý và có thể làm tràn disk. Chính vì vậy, có hai cách để bạn quản lý file log 

  • Quản lý theo kích thước của file (không quá 5M) 
  • Quản lý theo mỗi ngày ghi log (day1.log, day2.log...) 

winston có thể quản lý tốt về những điều trên (bạn đã thấy thích nó chưa?). 


Ví dụ bạn muốn quản lý theo size của file thì có thể sử dụng như sau:

const maxsizeTransport = new winston.transports.File({
  level: 'info',
  format: winston.format.printf(info => info.message),
  filename: ('testMaxsize.log'), //đường đẫn tạo file
  maxsize: 5242880, // 5MB
})

Vậy điều gì sẽ xảy ra nếu như file này quá 5M thì tự động nó sẽ tạo ra những file kế tiếp như testmaxsize1.log, testmaxsize2.log vv... Vậy còn quản lý theo thời gian mỗi ngày xoay tua để ghi log thì sao? 

Cũng đơn giản thôi, winston cung cấp cho bạn một thư viện cho việc xuay tua này đó là winston-daily-rotate-file ví dụ:

new transports.DailyRotateFile({
  filename: path.join(__dirname, '..', 'logs', `%DATE%.log`),
  datePattern: 'YYYY-MM-DD',
  prepend: true,
  json: false
})

File Log sẽ được tạo ra lần lượt 2020-10-01.log, 2020-10-02.log v.v. Nếu đến đây bạn vẫn chưa thoả mãn với những yêu cầu khắc khe or có những câu hỏi khác như "làm sao stream log? Hay làm sao push log này về một hệ thống khác?". Nếu bạn có những câu hỏi như vậy thì tôi biết trình độ bạn quá chuyên nghiệp rồi. Khỏi cần phỏng vấn bạn cũng pass rồi. winston làm được điều đó cho nên tôi đã không thay đổi thư viện khác trong thời gian rất lâu.


Tạo 4 luồng theo dõi log thông qua winston

Nếu như vừa rồi chúng ta đều giới thiệu việc ghi log nodejs thông qua console và file được lưu trong thư mục thì ngay bây giờ chúng ta sẽ đi đến việc lưu log trực tiếp sử dụng stream và truyền qua http. winston cung cấp một chức năng đơn giản cho việc cấu hình.

  • Console: In ra console trong nodejs
  • File: Ghi log vào file
  • http: Push log thông qua http
  • Stream: phát trực tiếp log

Chỉ cần bạn muốn thì có thể sử dụng code sau:

const { Writable } = require('stream')
const stream = new Writable({
    objectMode: false,
    write: raw => console.log('stream msg>>>', raw.toString()) // phat trực tiếp log tại đây
})

const http = require('http')
http
  .createServer((req, res) => {
    const arr = []
    req
      .on('data', chunk => arr.push(chunk))
      .on('end', () => {
        const msg = Buffer.concat(arr).toString()
        console.log('http msg', msg)// push log qua một hệ thông khác http://localhost:8080 
        res.end(msg)
      })
  })
  .listen(8080)

const path = require('path')

const logger = winston.createLogger({
    format: winston.format.combine(
        winston.format.label({ label: 'Demo Anonystick' }),
        winston.format.timestamp(),
        winston.format.prettyPrint(),
        winston.format.printf((info) => {
            return `[Muon gi thi tu di ma dinh dang] ${info.timestamp}:${info.label}:${info.message}`
        })
    ),
    transports: [
        new winston.transports.Console(),
        new winston.transports.File({
            level: 'info',
            format:  winston.format.printf((info) => {
                return `[Muon gi thi tu di ma dinh dang] ${info.timestamp}:${info.label}:${info.message}`
            }),
            filename: 'info.log',
            maxsize: 1
          }),
        new winston.transports.Http({host: 'localhost', port: 8080}),
        new winston.transports.Stream({ stream }) //stream tai đây
    ]
})
logger.info('winston transports')

Cuối cùng, bạn có thể thấy rằng console, file, HTTP và stream có thể ghi đều có thể nhận được thông báo sau: {"message":"winston transports","level":"info"}


Phần kết luận

Trong hướng dẫn này, bạn đã xây dựng một ứng dụng web Node.js đơn giản và tích hợp giải pháp ghi nhật ký Winston sẽ hoạt động như một công cụ hiệu quả để cung cấp thông tin chi tiết về hiệu suất của ứng dụng. Bạn có thể làm nhiều hơn nữa để xây dựng các giải pháp ghi nhật ký mạnh mẽ cho các ứng dụng của mình, đặc biệt khi nhu cầu của bạn ngày càng phức tạp. 

Chúng tôi khuyên bạn nên dành thời gian xem một số thư viện sau: log4js, morgan, Bunyan... Nếu bạn cảm thấy nó đáng được nhân rộng thì vui lòng share bài viết này ra cộng đồng. 

"Kết thúc chương trình truyền hình đến đây là hết..."

Có thể bạn đã bị missing