大家好,很高興又見面了,我是"高級前端進階",由我帶著大家一起關注前端前沿、深入前端底層技術,大家一起進步,也歡迎大家關注、點讚、收藏、轉發!
今天給大家帶來的主題是 Node.js 生態的日誌記錄框架,即 Pino。話不多說,直接開始!
1.什麼是 Pino
Pino 是一個強大的 Node.js 日誌記錄框架,擁有非常快的速度和非常全面的功能,同時因為性能優勢它已經集成到了開源 Fastify Web 伺服器中。 Pino 的多功能性還擴展到它易於與其他 Node.js Web 框架集成,使其成為可靠、靈活日誌方案的首選。
Pino 包括日誌框架中預期的所有標準功能,例如:可自定義的日誌級別、格式化選項和多個日誌傳輸選項。 它的靈活性是其突出的特點之一,因為它可以輕鬆擴展以滿足特定要求,從而使其成為廣泛應用的首選。
2.為什麼選擇 Pino
當選擇具體的日誌方案時,Node.js 生態有很多不錯的可選項。Pino 是一個歷史悠久且非常流行的日誌記錄工具,在 Github 上擁有超過 11.5K star,NPM 周平均下載量達到了驚人的 3601k。
Pino 提供了幾個關鍵特性,使其非常適合在 Node.js 應用程式中使用:
- 快速 :Pino 的設計目標是快速和輕便,並專注於性能。 它對日誌消息使用二進位格式,這使其能夠快速高效地生成日誌輸出。字符串列印速度上:Pino 平均是 114.801ms,Bunyan 為377.434ms,Winston 為270.249ms,Bole 為172.690ms,Debug 為220.527ms,LogLevel 為222.802ms,其中 Pino 最快,這個結論也同樣適用於普通對象和深度嵌套對象(benchmark參考文末資料)。
- 結構化日誌:Pino 以 JSON 格式記錄消息,這樣可以輕鬆解析、過濾和分析日誌數據,使得搜索、可視化和分析日誌數據以及將日誌數據集成到其他系統變得更加容易。
- 易於擴展:Pino 被設計成高度可擴展的,並包含許多可用於添加附加功能的內置插件,例如:將日誌數據寫入文件或將日誌數據發送到遠程伺服器。
- 低開銷:Pino 是一個高效的 Node.js 日誌庫,因為它的資源利用率最低。 Pino 的日誌記錄過程逐漸積累消息,導致應用程式節流和每秒請求數減少。 節流是一種技術,其中觸發連接到事件的函數在指定時間範圍內僅運行一次,即使事件被觸發多次也是如此。
- 傳輸 : Pino 提供了多種發送日誌的選項,包括寫入文件、在控制台中顯示以及利用 Sentry、Azure Application Insights 和 CouchDB 等平台。
要使用 Pino 也是非常簡單,只需要首先安裝相應的包,然後通過下面示例代碼集成:
const logger = require('pino')();
logger.info('hello world');
const child = logger.child({ a: 'property' });
child.info('hello child!');
此時輸出的日誌格式如下:
{"level":30,"time":1531171074631,"msg":"hello world","pid":657,"hostname":"Davids-MBP-3.fritz.box"}
{"level":30,"time":1531171082399,"msg":"hello child!","pid":657,"hostname":"Davids-MBP-3.fritz.box","a":"property"}
3.Pino 與其他框架集成
由於 HTTP 日誌記錄是 Pino 的主要用例,因此 Pino 對 Node.js Web 框架生態系統具有一流的支持,比如:Fastify、Express、Hapi、Restify、Koa 等等
Pino 與 Fastify
Fastify 是一個高度專注於以最少的開銷和強大的插件架構提供最佳開發體驗的 Web 框架。 它的靈感來自 Hapi 和 Express,據目前所知,它是目前 Node.js 生態中最快的 Web 框架之一。
Fastify web 框架默認集成了 Pino ,只需將 Fastify 的 logger 選項設置為 true 並使用 request.log 或 reply.log 來記錄與每個請求對應的日誌消息:
const fastify = require('fastify')({
logger: true,
});
// logger選項也可以設置為一個對象,該對象將作為 pino 選項對象直接傳遞。
fastify.get('/', async (request, reply) => {
request.log.info('something');
return { hello: 'world' };
});
fastify.listen({ port: 3000 }, (err) => {
if (err) {
fastify.log.error(err);
process.exit(1);
}
});
Pino 與 Express
Express 是用於 Node.js 的快速、極簡主義的 Web 框架,目前在 NPM 周平均下載量達到了驚人的 27545k。Express 的典型特徵包括:
- 強大的路由
- 專注於高性能
- 超高測試覆蓋率
- 大量 HTTP 工具函數(重定向、緩存等)
- 查看系統支持 14+ 模板引擎
- 內容協商(Content negotiation)
- 可執行以快速生成應用程式
Pino 與 Express 的集成也非常簡單,比如下面的示例:
const app = require('express')();
const pino = require('pino-http')();
app.use(pino);
app.get('/', function (req, res) {
req.log.info('something');
res.send('hello world');
});
app.listen(3000);
Pino 和 Hapi 集成
Hapi 是開發人員信任的簡單、安全的框架 以最小的開銷和完整的開箱即用功能構建功能強大、可擴展的應用程式,在 NPM 上周平均下載量達到了 512k。
Pino 與 Hapi 的集成也非常簡單,比如下面的示例:
'use strict';
require('make-promises-safe');
const Hapi = require('@hapi/hapi');
const Pino = require('hapi-pino');
async function start() {
// 創建一個有host和port的伺服器
const server = Hapi.server({
host: 'localhost',
port: 3000,
});
// 添加路由
server.route({
method: 'GET',
path: '/',
handler: async function (request, h) {
//request.log 是 HAPI 的標準日誌記錄方式
request.log(['a', 'b'], 'Request into hello world');
//也可以使用 pino 實例,這樣會更快
request.logger.info('In handler %s', request.path);
return 'hello world';
},
});
await server.register(Pino);
//也作為修飾的 API
server.logger.info('another way for accessing it');
//並通過 Hapi 標準日誌系統
server.log(['subsystem'], 'third way for accessing it');
await server.start();
return server;
}
start().catch((err) => {
console.log(err);
process.exit(1);
});
Pino 與 Restify
restify 是一個框架,利用 connect 風格的中間件來構建 REST API。Pino 與 Restify 的集成也非常簡單,比如下面的示例:
const server = require('restify').createServer({ name: 'server' });
const pino = require('restify-pino-logger')();
server.use(pino);
server.get('/', function (req, res) {
req.log.info('something');
res.send('hello world');
});
server.listen(3000);
Pino 與 Koa
Koa 是用於 node.js 的富有表現力的 HTTP 中間件框架,使 Web 應用程式和 API 編寫起來更輕鬆。 Koa 的中間件以類似堆棧的方式流動,允許開發者在下游執行操作然後在上游過濾和操作響應。Koa 沒有打包任何中間件。
Pino 與 Koa 的集成也非常簡單,比如下面的示例:
const Koa = require('koa');
const app = new Koa();
const pino = require('koa-pino-logger')();
app.use(pino);
app.use((ctx) => {
ctx.log.info('something else');
ctx.body = 'hello world';
});
app.listen(3000);
Pino 與 http
Pino 與 http 的集成也非常簡單,比如下面的示例:
const http = require('http');
const server = http.createServer(handle);
const logger = require('pino-http')();
function handle(req, res) {
logger(req, res);
req.log.info('something else');
res.end('hello world');
}
Pino 與 Nest
Nest 是一個用於構建高效、可擴展的 Node.js 伺服器端應用程式的框架。 它基於現代 JavaScript,使用 TypeScript 構建(保留與純 JavaScript 的兼容性)並結合了 OOP(面向對象編程)、FP(函數式編程)和 FRP(函數式響應式編程)的元素。
本質上,Nest 是基於 Express,但也提供了與廣泛的其他庫的兼容性,例如 Fastify,允許輕鬆使用無數可用的第三方插件。Pino 與 Nest 的集成也非常簡單,比如下面的示例:
import { NestFactory } from '@nestjs/core'
import { Controller, Get, Module } from '@nestjs/common'
import { LoggerModule, Logger } from 'nestjs-pino'
@Controller()
export class AppController {
constructor(private readonly logger: Logger) {}
@Get()
getHello() {
this.logger.log('something')
return `Hello world`
}
}
@Module({
controllers: [AppController],
imports: [LoggerModule.forRoot()]
})
class MyModule {}
async function bootstrap() {
const app = await NestFactory.create(MyModule)
await app.listen(3000)
}
bootstrap()
Pino 與 H3
H3 是為高性能和可移植性構建的最小 http 框架,NPM 上周平均下載量達到了 267K,具有以下典型特性:
- ✔️ 可移植:在 Serverless、Workers 和 Node.js 中完美運行
- ✔️ Minimal:小巧且支持 tree-shakable
- ✔️ 現代:原生 Promise 支持
- ✔️ 可擴展:附帶一組可組合的實用程序,但可以擴展
- ✔️ 路由支持:使用 unjs/radix3 進行超快速路由匹配
- ✔️ 兼容:具有與 node/connect/express 兼容層
Pino 與 H3 的集成也非常簡單,比如下面的示例:
import { createServer } from 'http';
import { createApp } from 'h3';
import pino from 'pino-http';
const app = createApp();
app.use(pino());
app.use('/', (req) => {
req.log.info('something');
return 'hello world';
});
createServer(app).listen(process.env.PORT || 3000);
4.本文總結
本文主要和大家介紹下 Node.js 生態的日誌記錄框架,即 Pino。相信通過本文的閱讀,大家對 Pino 都會有一個初步的了解。
因為篇幅有限,文章並沒有過多展開,如果有興趣,可以在我的主頁繼續閱讀,同時文末的參考資料提供了大量優秀文檔以供學習。最後,歡迎大家點讚、評論、轉發、收藏!
參考資料
https://www.npmjs.com/package/h3
https://github.com/pinojs/pino
https://github.com/nestjs/nest
https://www.npmjs.com/package/fastify
https://www.npmjs.com/package/express
https://www.npmjs.com/package/@hapi/hapi
https://github.com/restify/node-restify
https://blog.logrocket.com/comparing-node-js-logging-tools/
https://www.npmjs.com/package/pino
https://github.com/pinojs/pino/blob/master/docs/benchmarks.md
封面圖來自:https://css-tricks.com/how-to-implement-logging-in-a-node-js-application-with-pino-logger/