winston寫日志(譯)


1.  使用

有兩種方式使用winston,一是通過默認的logger,二是實例化自己的Logger,前者設計的目的是在應用程序中共享logger比較方便。

1.1 使用默認Logger

使用默認的logger很方便,直接通過winston模塊獲取,logger的任何方法都可以通過默認的logger實例得到。 

var winston = require('winston');
winston.log('info','Hello distributed log files!');
winston.info('Hello distributed log files!');
winston.level = 'debug';
winston.log('debug','Now my debug message are written to console!'); 

默認情況logger僅僅只設置了console。可以通過add()和remove()來增加和清除其他處理方式。
winston.add(winston.transports.File,{filename:'somefile.log'});
winston.remove(winston.transports.Console);

或者使用configure()來配置。

winston.configure({
     transports:[new (winston.transports.File)({filename:'somefile.log'})]
 });

Winston更多處理方式的文檔,可以查看Winston Transports文檔。

1.2 自定義Logger

如果你想管理loggers對象的生存期,可以自定義logger對象。

 var logger =  new (winston.Logger)({
     level:'info',
     transports:[
        new (winston.transports.Console)(),
        new (winston.transports.File)({filename:'somefile.log'})
     ]
 });

它和默認的logger工作方式一樣。

logger.log('info','Hello distributed log files!');
logger.info('Hello distributed log files!');
logger.add(winston.transports.File)
 .remove(winston.transports.Console);

同樣,使用configure方法也可以重新配置winston.Logger。

var logger =  new (winston.Logger)({
    level:'info',
    transports:[
       new (winston.transports.Console)(),
       new (winston.transports.File)({filename:'somefile.log'})
    ]
});
//替換以前整個transports通過一個新的配置
logger.configure({
    level:'verbose',
    transports:[
        new (require('winston-daily-rotate-file'))(opts)
    ]
});

2.元數據處理

除了打印字符串信息,winston也能夠打印JSON元數據,如下:

winston.log('info','Test Log Message',{anything:'This is metadata'});

不同的日志方式可能導致儲存對象會發生變化,有一個比較好的方式去操作元數據:

1.Console:Logger via util.inspect(meta)
2.File:Logger via util.inspect(meta)

3.同種日志類型多種處理方式

通過定義,可以對相同transports的winston.transports.File設置多種不同level處理方式。

var logger = new (winston.Logger)({
    transports:[
        new (winston.transports.File)({
            name : 'info-file',
            filename:'filelog-info.log',
            level:'info'
        }),
        new (winston.transports.File)({
             name:'error-file',
             filename:'filelog-error.log',
             level:'error'
        })
    ]
});

如果你想刪除其中一種處理方式,可以如下:

logger.remove("info-file");

在這個例子中也可以通過刪除Transport本身獲得相同的效果:

var infoFile = logger.transports[0];
logger.remove(infoFile);

4.分析

除了對消息和元數據進行處理之外,winston對任何logger也有一個簡單的分析機制:

//開始分析test,
//使用Date.now()來標記一個異步操作
winston.profile("test");
setTimeout(function(){
    //結束分析test
    winston.profile('test');
},1000)
//info: test durationMs=1001

所有分析信息默認設置為'info',在這個配置中消息和元數據都是可選的,沒有明顯的區別,但是我還是說出這個建議或者問題。

5.字符串插值

log提供和util.format一樣的字符串插值方法,允許這樣打印信息:

logger.log('info','test message %s', 'my string');
//info: test message my string
logger.log('info','test message %d',123);
//info: test message 123
logger.log('info','test message %j',{number:123},{});
//info: test message {"number":123}
logger.log('info','test message %s, %s','first','second',{number:123});
//info: test message first, second number=123
logger.log('info','test message', 'first', 'second', {number:123});
//info: test message first second number=123
logger.log('info','test message %s,%s','first','second',{number:123},function(){});
//info: test message first,second number=123
logger.log('info','test message', 'first','second',{number:123},function(){});
//info: test message first second number=123

6.查詢日志

 winston提供查詢日志接口,和Logger-like類似,具體可以查看Loggly Search API.

var options = {
    from:new Date - 24 * 60 * 60 * 1000,
    util:new Date,
    limit:10,
    start:0,
    order:'desc',
    fields:['./somefile.log']
};
/*
   找出昨天到今天的日志
 */
winston.query(options,function(err,results){
    if(err){
        throw err;
    }
    console.log(results);
});

7.日志流

streaming允許從你選擇的處理方式流水返回日志。

winston.stream({start: -1}).on('log',function(log){
    console.log(log);
});

異常

winston可以在進程中捕獲和記錄uncaughtException事件。

有兩種不同方法能實現這個功能,分別是在默認的logger實例和自定義的實例。

如果你想通過默認的logger來使用這個特征,調用實例的.handleExceptions的方法

//你能增加一個單獨的異常日志給.handleException

winston.handleException(new winston.transports.File({
    filename:'path/to/exception.log'
}));
//也可以設置.handleException為true當你增加一個處理方式給winston
//可以使用.humanReadableUnhandledException選項或者更多可讀的異常

winston.add(winston.transports.File,{
    filename:'path/to/all-logs.log',
    handleException:true,
    humanReadableUnhandledException:true
});

//多個處理方式也能被異常操縱

winston.handleException([transports1,transports2,....]);

 退出和不退出

 默認情況下,winston會退出如果記錄到一個未捕獲異常之后,如果不想退出。設置exitOnError =  false

var logger = new (winston.Logger)({
    exitOnError:false
});
//或者這樣
logger.exitOnError = false;

當自定義logger實例,你可以給一個處理方式傳遞exceptionHandlers屬性或者在任何處理方式設置handlerExceptions。

例子1

var logger = new (winston.Logger)({
    transports:[
        new winston.transports.File({
            filename:'path/to/all-logs.log'
        })
    ],
    exceptionHandlers:[
        new winston.transports.File({
            filename:'path/to/exceptions.log'
        })
    ]
});

例子2:

var logger = new (winston.Logger)({
    transports:[
        new winston.transports.Console({
            json:true,
            handleException:true
        })
    ],
    exitOnError:false
});

exitOnError選項也可以是一個函數,能防止某些錯誤的類型二退出。

function ignoreEpipe(err){
    return err.code !== 'EPIPE';
}
var logger = new (winston.Logger)({
    exitOnError:ignoreEpipe
});
//或者像這樣:
logger.exitOnError = ignoreEpipe; 

日志等級

這個很簡單了

進一步閱讀

winston的事件和回調

每一個winston.Logger實例也都是一個EventEmitter實例,一個log事件被觸發當寫日志成功。

logger.on('logging',function(transport,level,msg,meta){
    //msg和meta已經用level記錄在[transport]
});
logger.info('CHILL WINSTON',{seriously:true});

值得一提的是,logger還能觸發一個“錯誤”事件,如果你不想操作異常,你可以用來處理或者忽略它

logger.on("error",function(err){
    /* do something */
});
//或者忽略它
logger.emitErrs = false;

每個logging方法在最后一個字段也有一個可選的回調函數,它觸發當所有的transports已經特殊信息完畢

logger.info('CHILL WINSTON',{seriously:true},function(err.level.msg,meta)){
    //msg和meta已經用level記錄在[transport]
}

多個winston類目的日志

常常在一個大的,比較復雜的應用中是非常必要使用多個日志實例。每個日志對應不同的特性或者類型,winston有兩種方式來處理:

通過winston.loggers或者winston.Container的實例。事實上,winston.loggers也是winston.Container預先定義的實例。

winston.loggers.add('category1',{
    console:{
        level:'silly',
        colorize:true,
        label:'category one'
    },
    file:{
        filename:'/path/to/some/file'
    }
});

winston.loggers.add('category2',{
    couchdb:{
        host:'127.0.0.1',
        port:5984
    }
});

注意:在應用中,你要訪問你預配置的logger,你需要require("winston")在你的文件中。

var winston = require("winston");

var category1 = winston.loggers.get('category1');
category1.info('logging from you Ioc Contains-based logger'); 

如果你喜歡Container你可以實例化

var winston = require("winston"),
    container = new winston.container();

container.add('category1',{
    console:{
        level:"silly",
        colorize:true
    },
    file:{
        filename:'path/to/some/file'
    }
})

過濾和重寫

過濾允許修正日志消息的內容,重寫允許修改日志元數據,即掩蓋日志中不出現的數據。

過濾和重寫都是一個函數數組,它被創建一個winston.Logger對象時被提供。

var logger = new winston.Logger({
    rewriters:[function(level,msg,meta){}],
    filters:[function(level,msg,meta){}]
});

就像其他數組一樣,修改日志能運行在winston內部,也沒有什么副作用。

var logger = new winston.Logger({
    rewriters:[function(level,msg,meta){}],
    filters:[function(level,msg,meta){}]
});
logger.filters.push(function(level,msg,meta){
    return meta.production ? maskCardNumbers(msg) :msg;
});
logger.info('transaction with card number 1234567890123456 successful');

這個輸出的結果可能是:

info:transaction with card number 123456****2345 successful

而重寫,你想把creditCard元數據重新實例化:

logger.rewriters.push(function(level,msg,meta){
    if(meta.creditCard){
        meta.creditCard = maskCardNumbers(meta.creditCard);
    }
    return meta;
});

logger.info('transaction ok',{creditCard:123456789012345});

輸出結果可能是:

info:transaction ok creditCard=123456****2345

增加自定義日志處理方式

增加一個自定義處理方式非常簡單,所有需要做的是接受一些選項,設置名字,執行log()方法,和winston暴露的一些transports(處理方式)

var util = require('util'),
    winston = require('winston');

var CustomLogger = winston.transports.CustomLogger = function(options){
    //logger的名字
    this.name = 'customLogger';
    //選項設置一個等級
    this.level = options.level || "info";
    //配置你想要的處理方式
}
//  繼承winston.Transports,你能利用基本函數和.handlerExceptions()
util.inherit(CustomLogger,winston.Transports);
CustomLogger.prototype.log = function(level,msg,meta,callback){
    callback(null,true);
}

自定義日志格式

指定自定義格式應該為transport設置格式化函數,目前支持格式化的transports是:Console, File和Memory。可選對象作為參數傳遞給格式化對象。

一般屬性有:時間戳、等級、消息、和元數據,取決於transports類型可能會有額外的屬性。

var logger =  new (winston.Logger)({
    transports:[
        new (winston.transports.Console)({
            timestamp:function(){
                return Date.now();
            }
            formatter:function(options){
                //返回字符串給logger
                return options.timestamp() + ' ' +options.level.toUpperCase() + ''
                (options.message ? options.message: "") + (options.meta && Object.keys(options.meta).length ?
                '\n\t' + JSON.string(options.meta):"");
            }
        });
    ]
});
logger.info('Data to log');

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM