Pino
高性能TypeScript/Node.js向け構造化ロギングフレームワーク(1,150万週間ダウンロード)。JSON出力をデフォルトとし、非同期ログ処理により優れた応答性を実現。Winstonより5倍以上高速で、本番環境での使用に最適化。
GitHub概要
スター15,768
ウォッチ83
フォーク909
作成日:2016年2月16日
言語:JavaScript
ライセンス:MIT License
トピックス
fastjsonloggernodejspino
スター履歴
データ取得日時: 2025/7/17 10:01
pino
Pinoは、Node.jsアプリケーション向けに設計された超高速で低オーバーヘッドなロガーです。構造化されたJSONログを出力し、非同期処理による高パフォーマンスを実現します。大規模なプロダクション環境での使用に最適化されています。
主な特徴
- 超高速パフォーマンス - 他のロガーの5倍以上の速度
- 低オーバーヘッド - 最小限のリソース使用
- 構造化ログ - NDJSON形式の機械可読ログ
- 非同期処理 - トランスポートによる別スレッド処理
- チャイルドロガー - 効率的なコンテキスト管理
インストール
npm install pino
# TypeScript型定義(Pinoに含まれている)
# 追加の型定義は不要
# 開発用のプリティプリント
npm install --save-dev pino-pretty
基本的な使い方
シンプルな例
import pino from 'pino';
// 基本的なロガーの作成
const logger = pino();
// ログ出力
logger.info('アプリケーションが起動しました');
logger.error('エラーが発生しました');
logger.warn('警告メッセージ');
logger.debug('デバッグ情報');
// オブジェクトを含むログ
logger.info({ userId: 123, action: 'login' }, 'ユーザーがログインしました');
設定オプション
import pino from 'pino';
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
timestamp: pino.stdTimeFunctions.isoTime,
formatters: {
level: (label) => {
return { level: label.toUpperCase() };
},
bindings: (bindings) => {
return {
pid: bindings.pid,
host: bindings.hostname,
node_version: process.version
};
}
},
base: {
env: process.env.NODE_ENV,
revision: process.env.GIT_COMMIT
}
});
チャイルドロガー
基本的な使用
import pino from 'pino';
const logger = pino();
// モジュール用のチャイルドロガー
const authLogger = logger.child({ module: 'auth' });
const dbLogger = logger.child({ module: 'database' });
authLogger.info('認証処理開始');
dbLogger.info('データベース接続確立');
// ネストされたチャイルドロガー
const userAuthLogger = authLogger.child({
submodule: 'user-auth',
version: '1.0.0'
});
userAuthLogger.info({ userId: 123 }, 'ユーザー認証成功');
リクエストコンテキスト
import pino from 'pino';
import { randomUUID } from 'crypto';
const logger = pino();
// Express ミドルウェアの例
function requestLogger(req: any, res: any, next: any) {
const requestId = randomUUID();
const childLogger = logger.child({
requestId,
method: req.method,
url: req.url,
ip: req.ip
});
// リクエストオブジェクトにロガーを追加
req.log = childLogger;
childLogger.info('リクエスト受信');
// レスポンス時のログ
res.on('finish', () => {
childLogger.info({
statusCode: res.statusCode,
duration: Date.now() - req.startTime
}, 'リクエスト完了');
});
next();
}
トランスポート
開発環境用の設定
import pino from 'pino';
// 開発環境でのプリティプリント
const transport = pino.transport({
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'SYS:standard',
ignore: 'pid,hostname',
messageFormat: '{levelLabel} - {msg}'
}
});
const logger = pino(transport);
複数のトランスポート
import pino from 'pino';
const transport = pino.transport({
targets: [
{
// ファイルへの出力
target: 'pino/file',
level: 'info',
options: {
destination: './logs/app.log',
mkdir: true
}
},
{
// エラーログ専用ファイル
target: 'pino/file',
level: 'error',
options: {
destination: './logs/error.log',
mkdir: true
}
},
{
// 開発環境でのプリティプリント
target: 'pino-pretty',
level: 'debug',
options: {
colorize: true,
levelFirst: true,
translateTime: 'yyyy-mm-dd HH:MM:ss'
}
}
]
});
const logger = pino(transport);
カスタムトランスポート
// transport.ts
import { Transform } from 'stream';
export default (options: any) => {
return new Transform({
objectMode: true,
transform(chunk: any, encoding: string, callback: Function) {
// カスタム処理
const log = JSON.parse(chunk);
// 例: 特定のレベル以上をSlackに送信
if (log.level >= 50) { // ERROR以上
sendToSlack(log);
}
callback(null, chunk);
}
});
};
// 使用
const transport = pino.transport({
target: './transport.js',
options: { /* カスタムオプション */ }
});
高度な機能
カスタムレベル
import pino from 'pino';
const logger = pino({
customLevels: {
database: 35,
network: 45,
critical: 55
},
useOnlyCustomLevels: false,
level: 'trace'
});
// TypeScript用の型拡張
declare module 'pino' {
interface CustomLevels {
database: 35;
network: 45;
critical: 55;
}
}
// 使用
logger.database('データベースクエリ実行');
logger.network('API呼び出し開始');
logger.critical('重大なエラーが発生');
Mixin(共通データの追加)
import pino from 'pino';
import os from 'os';
const logger = pino({
mixin(_context, level) {
return {
application: 'my-app',
environment: process.env.NODE_ENV,
level_label: logger.levels.labels[level],
memory: process.memoryUsage().heapUsed,
cpuUsage: os.loadavg()[0]
};
}
});
// すべてのログに共通データが含まれる
logger.info('メッセージ');
センシティブデータの除去
import pino from 'pino';
const logger = pino({
redact: {
paths: ['password', 'token', '*.secret', 'creditCard'],
censor: '[REDACTED]'
}
});
// センシティブデータは自動的に除去される
logger.info({
user: 'john',
password: '12345',
token: 'abc123',
data: {
secret: 'sensitive-info'
}
}, 'ユーザー情報');
// password, token, secretは[REDACTED]に置換される
エラーのシリアライズ
import pino from 'pino';
const logger = pino({
serializers: {
err: pino.stdSerializers.err,
// カスタムシリアライザー
user: (user) => ({
id: user.id,
email: user.email,
// パスワードは含めない
})
}
});
try {
throw new Error('何かエラーが発生');
} catch (err) {
logger.error({ err, user: currentUser }, 'エラーが発生しました');
}
パフォーマンス最適化
非同期ロギング
import pino from 'pino';
import { pino as pinoHttp } from 'pino-http';
// sonic-boomを使用した高速書き込み
const dest = pino.destination({
dest: './app.log',
sync: false // 非同期書き込み
});
const logger = pino(dest);
// HTTPロギング(Express)
const httpLogger = pinoHttp({
logger,
autoLogging: {
ignore: (req) => req.url === '/health'
},
customLogLevel: (req, res, err) => {
if (res.statusCode >= 400 && res.statusCode < 500) {
return 'warn';
} else if (res.statusCode >= 500 || err) {
return 'error';
}
return 'info';
}
});
条件付きロギング
import pino from 'pino';
const logger = pino();
// ログレベルチェック
if (logger.isLevelEnabled('debug')) {
const expensiveData = calculateExpensiveOperation();
logger.debug({ data: expensiveData }, '詳細データ');
}
// より簡潔な方法
logger.debug(() => ({
data: calculateExpensiveOperation()
}), '詳細データ');
ベストプラクティス
1. 構造化されたコンテキスト
class ServiceLogger {
private logger: pino.Logger;
constructor(serviceName: string) {
this.logger = pino().child({ service: serviceName });
}
async processRequest(requestId: string, userId: string) {
const requestLogger = this.logger.child({ requestId, userId });
requestLogger.info('処理開始');
try {
// 処理
requestLogger.info({ duration: 100 }, '処理完了');
} catch (error) {
requestLogger.error({ err: error }, '処理エラー');
throw error;
}
}
}
2. 環境別設定
import pino from 'pino';
function createLogger() {
const isDevelopment = process.env.NODE_ENV === 'development';
if (isDevelopment) {
return pino({
level: 'debug',
transport: {
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'HH:MM:ss',
ignore: 'pid,hostname'
}
}
});
}
// 本番環境
return pino({
level: process.env.LOG_LEVEL || 'info',
formatters: {
level: (label) => ({ severity: label })
}
});
}
export const logger = createLogger();
3. エラーハンドリング
import pino from 'pino';
const logger = pino();
// グローバルエラーハンドラー
process.on('uncaughtException', (error) => {
logger.fatal({ err: error }, '未処理の例外');
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
logger.fatal({
err: reason,
promise: promise.toString()
}, '未処理のPromise拒否');
});
// シャットダウン処理
async function gracefulShutdown(signal: string) {
logger.info({ signal }, 'シャットダウン開始');
// クリーンアップ処理
await cleanup();
logger.info('シャットダウン完了');
process.exit(0);
}
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
まとめ
Pinoは、パフォーマンスを最優先に設計された強力なロギングライブラリです。構造化ログ、チャイルドロガー、トランスポートシステムなどの機能により、大規模なプロダクション環境でも効率的なログ管理が可能です。非同期処理と最小限のオーバーヘッドにより、アプリケーションのパフォーマンスへの影響を最小限に抑えながら、包括的なログ情報を収集できます。