作成に至る発端
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 件のコメント:
コメントを投稿