作成に至る発端
Log4js もあるが、ほとんどデバッグ目的のログ出力なので、console.assert や console.dir、可変長引数の console.log で出力する事が多い。文字列のみを出力する Log4js はオブジェクトや、XMLの出力において、console での出力に圧倒的に劣る。
また、Log4js自体のファイルサイズも大きい。
しかし、console は、ログ出力レベルを指定して出力をコントロールするといった機能が無い。
そんな事を考えていると、以下の記事が目に入り、ライブラリを作るかという事になった。
console.log は長くてつらい #JavaScript - Qiita
http://qiita.com/items/6f2ae599207fa9af323a
挫折
難しくないだろうと、こんなコードを書いた。
var LoggerLevel={ ALL:-99, DEBUG:-1, INFO:0, WARN:1, ERROR:2, OFF:99 }, self=null; var Logger=function(level){ self=this; self.level=isNaN(level) ? LoggerLevel.INFO : level; }; for(var key in console){ var level=LoggerLevel[key.toUpperCase()]; if(!level){level=99}; ( function(k,l){ Logger.prototype[k]=function(){ self=this; if(self.level<=l){ return console[k].apply(console, arguments); } } } )(key, level); };こんな感じで実行する。
var logger=new Logger(LoggerLevel.INFO); logger.debug("debugメッセージ"); logger.info("infoメッセージ"); logger.warn("warnメッセージ"); logger.error("errorメッセージ"); logger.dir([1,2,3,4,5]);ブラウザのコンソールを確認すると、うまく出力されているようだ。
ん・・・コンソールに表示される、どこでログ出力が呼ばれたかという行番号が、logger.js の console[k].apply の行番号になっている。
本当は、logger.info等を実行している行番号が出てほしいんだけど・・・。
これじゃデバッグが不便になるな。
うむ~まいった。
なやんでいると、こんな記事を見つけた。
console.logのエイリアス - hokaccha.hamalog v2
http://d.hatena.ne.jp/hokaccha/20111216/1324026093
bindね。これを使うと、bindされたファンクションを、コンストラクタとして扱えるようになるという事。
bind | Mozilla Developer Network
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
そして完成
bindを使い、以下のように書き直した。
var LoggerLevel={ ALL:-99, DEBUG:-1, INFO:0, WARN:1, ERROR:2, OFF:99 }, self=null; var Logger=function(level){ self=this; self.level=isNaN(level) ? LoggerLevel.INFO : level; }; for(var key in console){ var level=LoggerLevel[key.toUpperCase()]; if(!level){level=99}; Logger.prototype[key]=( function(k,l){ self=this; if(self.level<=l){ if(Function.bind){ return console[k].bind(console); }else{ return console[k].apply(console, arguments); } } } )(key, level); };先ほどと同じように実行してみる。
今度は、ちゃんと呼び出し元のファイル名、行番号でコンソールに出力された。
めでたしめでたし。
ちょっと修正
上のコードでも問題ないんだけど、ちょっと見直し。ログ出力の度いちいちFunction.bindを判定するのもなぁ・・・と思ったので以下のようにした。
var LoggerLevel={ ALL:-99, DEBUG:-1, INFO:0, WARN:1, ERROR:2, OFF:99 }, self=null; var Logger=function(level){ self=this; self.level=isNaN(level) ? LoggerLevel.INFO : level; }; for(var key in console){ var level=LoggerLevel[key.toUpperCase()]; if(!level){level=LoggerLevel.OFF}; if(Function.bind){ Logger.prototype[key]=( function(k,l){ self=this; if(self.level<=l){ return console[k].bind(console); } } )(key, level); }else{ Logger.prototype[key]=( function(k,l){ self=this; if(self.level<=l){ return console[k].apply(console, arguments); } } )(key, level); } };Loggerのprototypeを作る際にあらかじめ判定するようにしてみた。
console.timeとか使った際に、判定が入ることによる誤差を無くすための処置。
更に修正
var LoggerLevel={ ALL:-99, DEBUG:-1, INFO:0, WARN:1, ERROR:2, OFF:99 }; var Logger=function(level){ var self=this; self.level=isNaN(level) ? LoggerLevel.INFO : level; self.make(); }; Logger.prototype.make=function(){ var self=this; for(var key in console){ var l=LoggerLevel[key.toUpperCase()]; if(!l){l=LoggerLevel.OFF}; if(self.level<=l){ if(Function.bind){ Logger.prototype[key]=( function(k){ return console[k].bind(console); } )(key); }else{ Logger.prototype[key]=( function(k){ return console[k].apply(console, arguments); } )(key); } }else{ Logger.prototype[key]=function(){}; } } };さらに無駄な処理を省いた
一応最終版。
ダウンロード
- 非圧縮版(915B)
- https://sites.google.com/site/logroid/files/logger.js
- 圧縮版(661B)
- https://sites.google.com/site/logroid/files/logger.min.js
JavaScript
0 件のコメント:
コメントを投稿