debug
軽量なデバッグ専用ロギングライブラリ。環境変数DEBUGを使用した柔軟なログ表示制御が特徴。開発時のデバッグ情報表示に特化し、本番環境では自動的に無効化。多くのNode.jsライブラリの内部デバッグ機能として採用されている。
GitHub概要
debug-js/debug
A tiny JavaScript debugging utility modelled after Node.js core's debugging technique. Works in Node.js and web browsers
トピックス
スター履歴
ライブラリ
debug
概要
debugは「JavaScript/Node.js向けの軽量なデバッグ専用ロギングライブラリ」として開発された、環境変数による柔軟なログ制御が特徴のツールです。「Node.jsコアのデバッグ技術をモデルにした軽量JavaScriptデバッグユーティリティ」をコンセプトに、開発時のデバッグ情報表示に特化し、本番環境では自動的に無効化される設計。多くのNode.jsライブラリの内部デバッグ機能として採用され、DEBUG環境変数を使用した詳細なログ表示制御により開発体験を大幅に向上させます。
詳細
debug 2025年版は軽量性と簡潔性を重視したデバッグ特化ライブラリとして確固たる地位を維持しています。Node.jsとWebブラウザ両対応の汎用性により、フルスタック開発でのデバッグ体験を統一化。ネームスペース機能による階層的なデバッグカテゴリ管理、ワイルドカード対応のDEBUG環境変数制御、カラー出力によるログ視認性向上など、開発効率を最大化する機能を提供します。Express、Socket.IO、Request等の主要Node.jsライブラリで内部ログシステムとして標準採用されており、エコシステム全体での一貫したデバッグ体験を実現しています。
主な特徴
- 環境変数制御: DEBUG環境変数による柔軟なログ表示制御
- ネームスペース対応: 階層的なログカテゴリ管理とワイルドカード指定
- 軽量設計: 最小限のオーバーヘッドで高速動作
- カラー出力: TTY環境での自動色分け表示
- ブラウザ対応: Node.jsとWebブラウザ両環境で動作
- タイミング情報: ログ間の経過時間自動表示
メリット・デメリット
メリット
- 環境変数による直感的で柔軟なログ制御システム
- 軽量設計により本番環境への影響を最小化
- ネームスペース機能による大規模プロジェクトでの詳細ログ管理
- Node.jsエコシステムでの広範な採用と標準化
- ブラウザとサーバーサイドでの統一されたデバッグ体験
- ライブラリ開発時の内部ログ機能として最適
デメリット
- デバッグ専用でプロダクションログ機能は提供せず
- ログレベル概念がなく、on/off制御のみ
- ファイル出力、ローテーション等の高度なログ管理機能なし
- 構造化ログやJSON形式への対応が限定的
- エラーハンドリングや例外処理機能の不足
- 大規模アプリケーションでは他の包括的ロギングライブラリが必要
参考ページ
書き方の例
インストールと基本セットアップ
# debugライブラリのインストール
npm install debug
# プロジェクトでの使用確認
node -e "console.log(require('debug'))"
# バージョン確認
npm list debug
# グローバルインストール(開発用)
npm install -g debug
基本的なデバッグログ出力
// 基本的なdebugインスタンス作成
const debug = require('debug')('myapp');
// シンプルなログ出力
debug('アプリケーション開始');
debug('設定ファイル読み込み完了');
// 値の出力
const config = { port: 3000, env: 'development' };
debug('設定内容: %O', config);
// 文字列フォーマット
const userId = 123;
const userName = '田中太郎';
debug('ユーザー処理: ID=%d, 名前=%s', userId, userName);
// エラー情報のデバッグ
try {
throw new Error('テストエラー');
} catch (error) {
debug('エラーキャッチ: %O', error);
}
// 実行時間の測定
debug('処理開始');
setTimeout(() => {
debug('処理完了'); // +5ms のような時間差表示
}, 5);
環境変数によるログ制御
# 特定のネームスペースのみ表示
DEBUG=myapp node app.js
# 複数ネームスペース指定
DEBUG=myapp,database node app.js
# ワイルドカード使用
DEBUG=myapp:* node app.js
# 除外指定
DEBUG=*,-myapp:verbose node app.js
# 全てのデバッグログ表示
DEBUG=* node app.js
# ログ無効化
DEBUG= node app.js
# または
node app.js
# 部分的なワイルドカード
DEBUG=myapp:*,database:connection node app.js
ネームスペース階層とモジュール分割
// メインアプリケーション (app.js)
const debug = require('debug')('myapp:main');
const dbDebug = require('debug')('myapp:database');
const authDebug = require('debug')('myapp:auth');
debug('アプリケーション初期化');
// データベースモジュール (db.js)
const debug = require('debug')('myapp:database:connection');
const queryDebug = require('debug')('myapp:database:query');
function connectDB() {
debug('データベース接続開始');
// 接続処理
debug('接続完了: host=%s, port=%d', 'localhost', 5432);
}
function executeQuery(sql) {
queryDebug('SQL実行: %s', sql);
// クエリ実行
queryDebug('結果: %d行取得', 42);
}
// 認証モジュール (auth.js)
const debug = require('debug')('myapp:auth:login');
const sessionDebug = require('debug')('myapp:auth:session');
function login(credentials) {
debug('ログイン試行: user=%s', credentials.username);
if (validateCredentials(credentials)) {
sessionDebug('セッション作成: sessionId=%s', generateSessionId());
debug('ログイン成功');
} else {
debug('ログイン失敗: 認証情報が無効');
}
}
// HTTPリクエスト詳細ログ
const requestDebug = require('debug')('myapp:http:request');
const responseDebug = require('debug')('myapp:http:response');
app.use((req, res, next) => {
requestDebug('%s %s - %s', req.method, req.url, req.get('User-Agent'));
res.on('finish', () => {
responseDebug('%s %s - %d', req.method, req.url, res.statusCode);
});
next();
});
条件付きデバッグとパフォーマンス最適化
const debug = require('debug')('myapp:performance');
// デバッグ有効性チェック
if (debug.enabled) {
// 重い処理はデバッグが有効な時のみ実行
const memoryUsage = process.memoryUsage();
debug('メモリ使用量: %O', memoryUsage);
}
// 高精度タイマーによる性能測定
function measurePerformance(operationName, fn) {
if (!debug.enabled) {
return fn(); // デバッグ無効時は測定をスキップ
}
debug('%s 開始', operationName);
const startTime = process.hrtime.bigint();
const result = fn();
const endTime = process.hrtime.bigint();
const duration = Number(endTime - startTime) / 1000000; // ナノ秒をミリ秒に変換
debug('%s 完了: %.2fms', operationName, duration);
return result;
}
// 使用例
const result = measurePerformance('データベースクエリ', () => {
// 重い処理
return fetchDataFromDB();
});
// 動的デバッグ制御
function setDebugLevel(namespace, enabled) {
const debug = require('debug');
if (enabled) {
// 現在の設定に追加
const current = process.env.DEBUG || '';
const newDebug = current ? `${current},${namespace}` : namespace;
debug.enabled = function(name) {
return new RegExp(newDebug.replace('*', '.*')).test(name);
};
} else {
// 特定のネームスペースを無効化
debug.enabled = function(name) {
return !new RegExp(namespace.replace('*', '.*')).test(name);
};
}
}
// 実行時のデバッグ制御例
setDebugLevel('myapp:verbose', false); // verbose ログを無効化
setDebugLevel('myapp:error', true); // error ログを有効化
フォーマッタとカスタム出力
const debug = require('debug')('myapp');
// printf スタイルフォーマット
debug('整数: %d, 文字列: %s, JSON: %O', 42, 'テスト', { key: 'value' });
// オブジェクトの詳細表示
const complexObject = {
user: { id: 1, name: '田中太郎' },
metadata: { created: new Date(), tags: ['important', 'user'] },
config: { theme: 'dark', language: 'ja' }
};
debug('複雑なオブジェクト: %O', complexObject);
// エラーオブジェクトの詳細
try {
JSON.parse('invalid json');
} catch (error) {
debug('JSON解析エラー: %O', {
message: error.message,
stack: error.stack,
name: error.name
});
}
// カスタムフォーマッタ関数
function formatUser(user) {
return `${user.name}(ID:${user.id})`;
}
const user = { id: 123, name: '佐藤花子' };
debug('ユーザー処理: %s', formatUser(user));
// 配列の詳細表示
const items = [
{ id: 1, name: 'アイテム1', price: 1000 },
{ id: 2, name: 'アイテム2', price: 2000 }
];
items.forEach((item, index) => {
debug('アイテム[%d]: %s - %d円', index, item.name, item.price);
});
// バイナリデータやBufferのデバッグ
const buffer = Buffer.from('Hello, デバッグ', 'utf8');
debug('バッファデータ: %O', {
length: buffer.length,
content: buffer.toString('utf8'),
hex: buffer.toString('hex')
});
Express.jsアプリケーションでの実践的活用
const express = require('express');
const debug = require('debug')('myapp:server');
const routeDebug = require('debug')('myapp:routes');
const dbDebug = require('debug')('myapp:database');
const app = express();
// サーバー開始ログ
debug('Express サーバー初期化中...');
// ミドルウェアレベルのデバッグ
app.use((req, res, next) => {
routeDebug('受信: %s %s', req.method, req.url);
// レスポンス完了時のログ
res.on('finish', () => {
routeDebug('応答: %s %s - %d (%dms)',
req.method, req.url, res.statusCode, Date.now() - req.startTime);
});
req.startTime = Date.now();
next();
});
// ルート固有のデバッグ
app.get('/users/:id', async (req, res) => {
const userDebug = require('debug')('myapp:routes:users');
userDebug('ユーザー取得リクエスト: ID=%s', req.params.id);
try {
dbDebug('ユーザーデータベースクエリ実行');
const user = await getUserById(req.params.id);
if (user) {
userDebug('ユーザー見つかりました: %s', user.name);
res.json(user);
} else {
userDebug('ユーザーが見つかりません: ID=%s', req.params.id);
res.status(404).json({ error: 'User not found' });
}
} catch (error) {
userDebug('ユーザー取得エラー: %O', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// エラーハンドリングミドルウェア
app.use((error, req, res, next) => {
const errorDebug = require('debug')('myapp:error');
errorDebug('未処理エラー: %O', {
message: error.message,
stack: error.stack,
url: req.url,
method: req.method
});
res.status(500).json({ error: 'Something went wrong!' });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
debug('サーバー起動: http://localhost:%d', PORT);
debug('環境: %s', process.env.NODE_ENV || 'development');
});
// Graceful shutdown
process.on('SIGTERM', () => {
debug('SIGTERM受信 - サーバーシャットダウン開始');
server.close(() => {
debug('サーバーシャットダウン完了');
process.exit(0);
});
});
本番環境対応とセキュリティ考慮
// 本番環境での debug 無効化確認
const debug = require('debug')('myapp');
// NODE_ENV による自動制御
if (process.env.NODE_ENV === 'production') {
// 本番環境では DEBUG 環境変数を明示的にクリア
delete process.env.DEBUG;
// または最低限のエラーログのみ有効化
process.env.DEBUG = 'myapp:error,myapp:critical';
}
// 機密情報の保護
function safeDebug(namespace) {
const debug = require('debug')(namespace);
return function(message, ...args) {
// 機密情報を含む可能性のあるデータをフィルタリング
const filteredArgs = args.map(arg => {
if (typeof arg === 'object' && arg !== null) {
const filtered = { ...arg };
// パスワードやトークンを除去
['password', 'token', 'secret', 'apiKey', 'privateKey'].forEach(key => {
if (filtered[key]) {
filtered[key] = '***REDACTED***';
}
});
return filtered;
}
return arg;
});
debug(message, ...filteredArgs);
};
}
// 安全なデバッグログ使用例
const safeLog = safeDebug('myapp:auth');
const loginData = {
username: '[email protected]',
password: 'secretpassword',
rememberMe: true
};
safeLog('ログイン試行: %O', loginData); // password は ***REDACTED*** と表示
// ログレベル風の制御実装
const logLevels = {
error: require('debug')('myapp:error'),
warn: require('debug')('myapp:warn'),
info: require('debug')('myapp:info'),
debug: require('debug')('myapp:debug')
};
function log(level, message, ...args) {
if (logLevels[level]) {
logLevels[level](message, ...args);
}
}
// 使用例
log('error', 'データベース接続失敗: %s', error.message);
log('info', 'ユーザー登録完了: %s', user.email);
log('debug', '内部状態: %O', internalState);