0

Series PM2 Log Mastery #3: Đẩy Log lên Telegram và Chuẩn hóa JSON cho ELK Stack (Trạm cuối)

1. Chuẩn hóa Log sang định dạng JSON (Bắt buộc cho ELK)

Mặc định, PM2 ghi log dưới dạng Text thuần (Plain Text). Nhưng Logstash hoặc Filebeat của hệ thống Elasticsearch cực kỳ "ghét" Text thuần vì nó rất khó bóc tách (parse) dữ liệu.

Để Elasticsearch hiểu được đâu là thời gian, đâu là tên tiến trình, đâu là nội dung lỗi, chúng ta phải ép PM2 xuất log ra định dạng JSON.

Cách 1: Ép JSON qua Command Line Khi khởi chạy ứng dụng, bạn chỉ cần thêm cờ --log-type json:

pm2 start app.js --name "afc-api-service" --log-type json

Cách 2: Dùng Ecosystem File (Chuẩn Senior) Thay vì gõ lệnh dài dòng, hãy tạo file ecosystem.config.js để quản lý cấu hình:

module.exports = {
  apps: [{
    name: "afc-api-service",
    script: "./app.js",
    log_type: "json", // Bật tính năng JSON Log
    merge_logs: true, // Gộp chung log nếu chạy cluster
  }]
}

Lúc này, thay vì những dòng chữ đơn điệu, file log của bạn sẽ trông chuyên nghiệp như thế này:

{"message":"Kết nối Database thành công","timestamp":"2026-07-15T09:40:00.000Z","type":"out","process_id":0,"app_name":"afc-api-service"}

Khi file log đã mang hình hài JSON, bạn chỉ cần cấu hình Filebeat đọc trực tiếp từ thư mục ~/.pm2/logs/ và đẩy thẳng lên Elasticsearch. Trên Dashboard Kibana, bạn có thể dễ dàng filter lỗi theo trường app_name hoặc process_id cực kỳ mượt mà.

2. Thiết lập "Tai mắt": Bắn lỗi thẳng vào Telegram

Không ai muốn Telegram bị spam bởi hàng ngàn dòng log Info. Chúng ta chỉ muốn nhận tin nhắn khi có Lỗi (Error) xảy ra (ví dụ: mất kết nối Hitachi, lỗi trừ tiền vé).

PM2 cung cấp một API cực mạnh tên là Event Bus. Chúng ta sẽ viết một script nhỏ chạy ngầm bằng Node.js. Script này sẽ đóng vai trò như một "lính gác", liên tục lắng nghe mọi tiến trình do PM2 quản lý, nếu thấy có dòng log nào thuộc loại error, nó sẽ bế dòng log đó quăng lên Telegram.

Bước 1: Khởi tạo script Lính gác Tạo một file tên là telegram-watcher.js:

const pm2 = require('pm2');
const axios = require('axios');

const TELEGRAM_BOT_TOKEN = 'YOUR_BOT_TOKEN';
const CHAT_ID = '-100123456789'; // ID group DevOps của bạn

pm2.connect(function(err) {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  console.log("Vệ sĩ Telegram đang lắng nghe lỗi từ PM2...");

  // Bật kênh lắng nghe sự kiện của PM2
  pm2.launchBus(function(err, bus) {
    
    // Lắng nghe sự kiện log báo lỗi (log:err)
    bus.on('log:err', function(packet) {
      const appName = packet.process.name;
      const errorMsg = packet.data; // Nội dung lỗi

      const message = `🚨 [CẢNH BÁO LỖI] 🚨\n\n📌 Service: ${appName}\n❌ Lỗi: ${errorMsg}`;

      // Gọi API Telegram để bắn tin nhắn
      axios.post(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`, {
        chat_id: CHAT_ID,
        text: message
      }).catch(console.error);
    });
    
  });
});

Bước 2: Giao việc cho PM2 quản lý chính cái "Lính gác" này Bạn phải đảm bảo script gác cổng này cũng chạy 24/7 không bao giờ chết:

pm2 start telegram-watcher.js --name "pm2-telegram-alert"

Xong! Từ giây phút này, bất kỳ tiến trình nào (dù là Laravel Queue hay API Node.js) văng ra một dòng lỗi stderr, điện thoại của anh em DevOps sẽ lập tức rung lên với thông tin đích danh Service đang hấp hối.

Tổng kết Series PM2 Log Mastery

Trải qua 3 bài học ngắn gọn nhưng đậm chất thực chiến, chúng ta đã đưa hệ thống Log từ trạng thái "hoang dã" vào một khuôn khổ vận hành cấp độ Enterprise:

  1. Bài 1: Dùng PM2 làm quản gia bất tử, duy trì sinh mệnh cho các Worker ngầm.
  2. Bài 2: Dùng pm2-logrotate để tự động dọn rác, giải cứu ổ cứng khỏi nguy cơ phình to.
  3. Bài 3: Chuẩn hóa dữ liệu thành JSON để mở cổng cho ElasticSearch, đồng thời tạo lính gác bắt lỗi bắn lên Telegram theo thời gian thực.

Khép lại những vấn đề về hạ tầng vận hành ngầm, hệ thống của chúng ta giờ đã có đôi mắt và tiếng nói riêng.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí