Chuyển đến nội dung chính
LogBrew là nền tảng observability (khả năng quan sát) cho lập trình viên và agent lập trình, có gói miễn phí rộng rãi và không cần thẻ thanh toán. Hướng dẫn này cấu hình logging trong Node.js với Winston và Pino, thêm logger cho Express, rồi gửi mỗi log đến LogBrew cùng trace của yêu cầu. Mọi ví dụ đã chạy trên Node.js 22 với Winston 3.19, Pino 10.4, Express 5.3, @logbrew/sdk 0.1.40, @logbrew/node 0.1.24 và @logbrew/express 0.1.10. Mỗi khối kết quả là kết quả thật.

Chọn Winston hay Pino

Cả hai thư viện đều ghi log JSON có cấu trúc. Giữ thư viện mà ứng dụng đang dùng. Cách thiết lập LogBrew khác nhau cho mỗi thư viện.

Chuẩn bị dự án LogBrew

1

Tạo khóa dự án

Đăng nhập bằng CLI. Tạo một dự án và lưu khóa gửi dữ liệu của dự án vào một tệp mà chỉ chủ sở hữu đọc được.
CLI không in khóa ra. Trong production, dùng trình quản lý secret của nền tảng bạn dùng.
2

Cài đặt các gói

Các gói cần Node.js 18.19 trở lên. Cài Winston, Pino hoặc cả hai.
3

Đặt khóa và danh tính triển khai

createLogBrewNodeClient() đọc khóa từ LOGBREW_SERVER_API_KEY. Tên dịch vụ là name trong package.json. Để dùng tên khác, đặt LOGBREW_SERVICE_NAME. Các ví dụ dùng ES module, nên đặt "type": "module" trong package.json.

Các mức log trong Node.js

Mỗi thư viện có tên và số mức riêng. LogBrew lưu 4 mức và giữ mức gốc trong metadata. Trong Winston, số càng nhỏ thì càng nghiêm trọng. Trong Pino, số càng lớn thì càng nghiêm trọng. Đặt info trong production. Chỉ dùng debug khi chẩn đoán trong thời gian ngắn.

Logger Winston

Lưu tệp này thành winston-app.js. Format đầu tiên loại các bản ghi thấp hơn mức của logger trước khi bất kỳ transport nào nhận được. Transport LogBrew nhận mọi bản ghi mà logger ghi, nên cần bộ lọc này.
Chạy node winston-app.js. Console nhận 1 dòng JSON cho mỗi bản ghi từ mức info trở lên. Dấu vết ngăn xếp (stack trace) ở đây đã được rút gọn.
LogBrew nhận cùng 3 bản ghi đó. Các trường trở thành metadata context.*. Transport gửi tên và thông điệp lỗi, nhưng không gửi dấu vết ngăn xếp. Để gửi dấu vết ngăn xếp, đặt includeErrorStack: true trong createLogBrewWinstonTransport(). Mỗi thông điệp cũng trở thành một breadcrumb của vấn đề tiếp theo. Đặt breadcrumbs: false để tắt việc này.

Logger Pino

Lưu tệp này thành pino-app.js. Gọi installLogBrewPinoInstrumentation() một lần, trước log đầu tiên. Hàm này đọc từng bản ghi Pino đã hoàn tất. Pino vẫn ghi vào đích riêng của nó.
Chạy node pino-app.js. Tên máy chủ và dấu vết ngăn xếp ở đây đã được rút gọn.
LogBrew nhận 3 bản ghi. Pino loại bản ghi debug trước khi LogBrew thấy nó. Trường token không có trong LogBrew. LogBrew loại các trường thông tin xác thực, cookie, body, query, URL và dấu vết ngăn xếp. Các đường dẫn redact của Pino vẫn có hiệu lực như lớp kiểm soát thứ hai. pid, hostname và time là giá trị mặc định của Pino, nên LogBrew không sao chép chúng. Tính năng tự động ghi nhận cần Pino 9.11 trở lên trong nhánh 9.x, hoặc Pino 10.1 trở lên. Với các phiên bản Pino cũ hơn, dùng createLogBrewPinoDestination() từ @logbrew/sdk làm đích của Pino. Để đọc kết quả của Pino khi phát triển, chuyển nó qua pino-pretty.

Logger cho Express

logbrewMiddleware() tạo 1 span yêu cầu cho mỗi yêu cầu. logbrewErrorHandler() báo lỗi thành vấn đề. Log Pino bên trong một yêu cầu nhận trace ID và span ID của yêu cầu đó. Lưu tệp này thành express-app.js.
Khởi động ứng dụng. Sau đó gửi 2 yêu cầu từ một terminal thứ hai.
LogBrew nhận các sự kiện sau. Log và span của mỗi yêu cầu có cùng trace ID. Tên span dùng mẫu route, không dùng đường dẫn cụ thể. Log listening on 3000 không có trace, vì log này nằm ngoài yêu cầu. Để middleware tự tạo client cho từng yêu cầu. Đừng truyền client dùng chung cho cả tiến trình vào logbrewMiddleware() hay logbrewErrorHandler(). Middleware tắt client của yêu cầu sau mỗi phản hồi.

Thêm trace vào log Winston

Với Winston, truyền trace đang hoạt động cho transport.
Thêm logbrewTransport vào danh sách transports của logger. Khi đó, log Winston bên trong một yêu cầu Express có trace ID và span ID của yêu cầu đó.

Đọc lại log

Lệnh cuối cùng đọc mọi log của 1 yêu cầu. Sao chép <trace_id> từ một trace hoặc một vấn đề. Để đọc từ CI hoặc agent lập trình, dùng khóa đọc dữ liệu của dự án. Xem Kiểm tra thiết lập.

Tắt mà không mất log

Client gửi các sự kiện trong hàng đợi 1 giây sau sự kiện đầu tiên hoặc khi đủ 50 sự kiện. Khi event loop trống, client gửi các sự kiện còn lại trong tối đa 2 giây. process.exit() và signal của hệ điều hành bỏ qua bước đó. Gọi await client.shutdown() trước khi thoát, như handler SIGTERM trong ví dụ Express.

Khắc phục sự cố

Để chọn các trường log, xem Structured logging. Với các framework khác, xem Tích hợp SDK.