node.js を使い始めて javascript かわいいなーと思い始めたこのごろ
まだ javascript の扱い方から勉強してるんだけど
そんなわけなのでソースを読んで勉強しようかなと winston を選んでみた
winston は nodejitsu 社が作ってる Flatiron ってオープンソースフレームワークのモジュールの一つとして開発されてるす
いくつか便利機能があるんすが query とか、例外ハンドリングとか、profiler とか
そのへんは今回は触らずにロギング周りを見ていくす
この記事は 東京Node学園祭2012 アドベントカレンダー の 26 日目の記事です。
ファイル
lib の中身はシンプル
├── winston │ ├── common.js │ ├── config │ │ ├── cli-config.js │ │ ├── npm-config.js │ │ └── syslog-config.js │ ├── config.js │ ├── container.js │ ├── exception.js │ ├── logger.js │ ├── transports │ │ ├── console.js │ │ ├── file.js │ │ ├── http.js │ │ ├── transport.js │ │ └── webhook.js │ └── transports.js └── winston.js
winston.js だけを require すれば使えるように作られてる
てことで winston.js を見てみよう
winston.js
大きくわけて 2 つの役割を持ってます
- 1) ロガーを作ったりするのに便利なコンストラクタ的な関数やユーティリティ
- 2) winston 自体がロガーとして動作するようになってる
(1) から見ていくす
1) ロガーを作ったりするのに便利なコンストラクタ的な関数やユーティリティ
expose されてるのを図にするとこんな感じ
オレンジはコンストラクタ的な関数で緑はプロパティ的なの
winston.transports.Console winston.transports.File winston.Container winston.Logger winston.config.cli winston.config.npm
とかが呼べる感じ
transports
transports は出力先ですね
こんな風にして作れます
new (winston.transports.Console)(), new (winston.transports.File)({ filename: 'somefile.log' })
ちなみに継承みたいな構造はこんな感じ
Container
Container は複数のロガーをひとまとめにして持っとくための箱です
それぞれのロガーにはIDをつけておいて、それで取り出すことができます
以下の例では指定したオプションでロガーを生成して、それを category1 という名前で container に保持してるっつーわけすね
var winston = require('winston'), container = new winston.Container(); container.add('category1', { console: { level: 'silly', colorize: 'true' }, file: { filename: '/path/to/some/file' } });
Logger
Logger はログを出力するためのものです
Transport を複数持つことができて log 関数でそこに出力する
javascript っぽくて面白いなーと思ったのが
setLevel 関数でそのレベルごとの関数を作ってるところ
実際は common.js#L23 に実装してある
大雑把に書くとこんな感じ
targetLogger[level] = function (msg) { return targetLogger.log(level, msg, meta, callback); }
config
config はレベルと、レベルごとの色を保持している設定ファイルです
例えば syslog config は
var syslogConfig = exports; syslogConfig.levels = { debug: 0, info: 1, notice: 2, warning: 3, error: 4, crit: 5, alert: 6, emerg: 7 }; syslogConfig.colors = { debug: 'blue', info: 'green', notice: 'yellow', warning: 'red', error: 'red', crit: 'red', alert: 'yellow', emerg: 'red' };
まとめ
ということで。ここまでで。
- Transport を作ることができて
- それを指定して Logger を作ることができて
- config でレベルや色が変えられて
- 複数の Logger をひとまとめで管理する Container を作ることができる
んでも。もっと気軽に使いたいよね。ということで winston はそれ自身がログを出力できるようになってます。
2) winston 自体がロガーとして動作するようになってる
winston 自身が Logger を defaultLogger という名前で持っていて
そこに処理を委譲しているような印象す
var methods = [ 'log', 'query', 'stream', 'add', 'remove', 'clear', 'profile', 'startTimer', 'extend', 'cli', 'handleExceptions', 'unhandleExceptions' ]; common.setLevels(winston, null, defaultLogger.levels); methods.forEach(function (method) { winston[method] = function () { return defaultLogger[method].apply(defaultLogger, arguments); }; });
なので winston 自体に Transports を設定したり setLevels したりして
そのまま winston.log('info', 'msg'); などが可能です。
winston の使い方
ここまで読んで、ドキュメントの意味がわかったす
https://github.com/flatiron/winston#logging
Using the Default Logger
var winston = require('winston'); // winston から直接ログ出力できるよー winston.log('info', 'Hello distributed log files!'); winston.info('Hello again distributed logs'); // こんなこともできるよー winston.add(winston.transports.File, { filename: 'somefile.log' }); winston.remove(winston.transports.Console);
winston が内部に持ってる defaultLogger に対しての処理になるすね。
Instantiating your own Logger
こっちは作ってるってことね。
var logger = new (winston.Logger)({ transports: [ new (winston.transports.Console)(), new (winston.transports.File)({ filename: 'somefile.log' }) ] }); logger.log('info', 'Hello distributed log files!'); logger.info('Hello again distributed logs'); logger.add(winston.transports.File) .remove(winston.transports.Console);
面白かったー。