• 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 ?
                    '
    	' + JSON.string(options.meta):"");
                }
            });
        ]
    });
    logger.info('Data to log');
  • 相关阅读:
    Spring Boot
    AWS DynamoDB
    VBA读excel写xml
    WebSocket API 学习
    故障排除 Mybatis ORA-01000 和 本地缓存问题
    Java基础
    Java Tutorials Lambda表达式 翻译
    在代理环境中构建maven环境
    Pom
    我的JAVA笔记
  • 原文地址:https://www.cnblogs.com/liuyinlei/p/6128984.html
Copyright © 2020-2023  润新知