美文网首页
2018-08-14[JavaScript] winston 的

2018-08-14[JavaScript] winston 的

作者: V_Jan | 来源:发表于2018-08-15 09:32 被阅读0次

    官方文档:
    注意别看错版本,2.x版和3.x版的是有差别的
    3.x版: https://github.com/winstonjs/winston
    2.x版: https://github.com/winstonjs/winston/tree/2.x
    这里我用的是2.4.1版.
    1.从最简单的开始,引入winston后使用默认的logger
    1.1 利用默认的logger打印出一些log信息

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

    控制台输出:
    注意因为winston写log调用的是回调函数,所以每次运行这段代码log的输出顺序不一定一样。
    info: Hello distributed log files!
    info: Hello again distributed logs
    debug: Now my debug messages are written to console!
    当我运行第四次输出的顺序是:
    info: Hello distributed log files!
    debug: Now my debug messages are written to console!
    info: Hello again distributed logs

    1.2 修改log的输出目的地
    默认情况下,默认的logger只将内容输出到Console。但肯定可以修改的。有两种方式修改log的输出目的地。
    1.2.1 你可以通过winston.add(), winston.remove()来添加和移除log传送的途径。 下面代码将详细的log输出到脚本同级目录下的somefile.log里,而且还会带上timestamp**

    'use strict';
    const winston = require('winston');
    /*
     默认情况下,仅在默认记录器上设置控制台传输。您可以通过add()和remove()方法添加或删除传输:
     */
    winston.add(winston.transports.File, { filename: 'somefile.log' });
    winston.remove(winston.transports.Console); //关闭了控制台输出
    
    /* use default logger
     可以通过winston模块直接访问默认记录器。可以在默认记录器上使用您可以在记录器实例上调用的任何方法:
     */
    winston.log('info', 'Hello distributed log files!');
    winston.info('Hello again distributed logs');
    
    winston.level = 'debug';
    winston.log('debug', 'Now my debug messages are written to console!');
    

    1.2.2 通过configure() 一次性修改配置, 为什么说一次性呢?因为transports是winston的一个属性,是一组定义log的传出方式,第一种方法的add, remove操作的其实就是这个transports列表
    下面这种方式,达到跟1.2.1 的例子一样的效果,而不用winston.remove(winston.transports.Console);

    /*
     或者通过一次调用configure()来完成:
     */
    'use strict';
    const winston = require('winston');
    
    winston.configure({
        transports: [
            new (winston.transports.File)({ filename: 'somefile.log' })
        ]
    });
    
    /* use default logger
     可以通过winston模块直接访问默认记录器。可以在默认记录器上使用您可以在记录器实例上调用的任何方法:
     */
    winston.log('info', 'Hello distributed log files!');
    winston.info('Hello again distributed logs');
    
    winston.level = 'debug';
    winston.log('debug', 'Now my debug messages are written to console!');
    

    log输出到file中是以追加的方式输入,这里我运行了2次就有两次一样的输出

    logger输出

    2. 接下来说下如何自定义和使用logger, 用default logger总会受限。
    2.1 自己实例化并使用logger,一般由3个步骤要走。
    a. 用new (wiston.Logger)创建一个logger对象
    b. 指定transports列表,说明log要输出到哪里,这里你依旧可以用操作default logger那样用add(), remove()来添加删除transports.
    c. 指定输出的log信息的等级,有2种方式, 如下,这两种写法是等同的 .
    这里可以看到你可以用哪些log level :
    https://github.com/winstonjs/winston/tree/2.x#using-logging-levels

    //You can pass a string representing the logging level to the log() method or use the level specified methods defined on every winston Logger.
    //logger is an instance of  'new (wiston.Logger)'
    logger.error("I am an error");
    logger.log('error', "I am an error");
    

    来一段代码:

    'use strict';
    const winston = require('winston');
    const logger = new (winston.Logger)({ //这个圆括号可有可无
        level: 'info',
        transports: [
             //transports用于指定log要输出到哪里,这里输出到Console(大家熟悉的控制台)
             //并且打开了颜色控制开关
            new (winston.transports.Console)({ colorize: true }),//Console可以不要参数:new (winston.transports.Console)(),
            new (winston.transports.File)({ filename: 'somefile.log' }) 
        ]
    });
    logger.level = 'debug';
    logger.info('Hello world');
    logger.debug('Debugging info');
    logger.error("I am an error"); //这行代码和下面那行的效果一模一样
    logger.log('error', "I am an error");
    
    

    这里你依旧可以用操作default logger那样用add(), remove()来添加删除transports.

      logger
        .add(winston.transports.File)
        .remove(winston.transports.Console);
    

    2.2接下来说说exceptionHandlers
    当Exception被抛出时,我们往往希望这个exception可以输出到特定的地方让我们可以troubleshooting.
    你可以这么设置, 通过设置.handleExceptions()或者设置exceptionHandlers的属性

    winston.handleExceptions(new winston.transports.File({ filename: 'path/to/exceptions.log' }));
    
     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' })
        ]
      });
    

    今天先到这里,困了。

    有些人会遇到下面的问题,那是因为版本错了。比如我这里package.json里指定的是2.4.1版,但是winston.createLogger()是3.x版后才有的。


    image.png

    当我下载了3.0.0版,这段代码就正常工作了:


    image.png

    参考:
    https://github.com/winstonjs/winston/tree/2.x
    https://github.com/winstonjs/winston
    http://thisdavej.com/using-winston-a-versatile-logging-library-for-node-js/
    https://github.com/winstonjs/winston/issues/1101

    image.png

    最后附上一份结合KOA框架的logger.js

    const path = require('path'),
        winston = require('winston');
    
    module.exports = (app) => {
        let transports = [];
        transports.push(new (winston.transports.Console)({
            colorize: true,
            level: 'info',
            prettyPrint: _jsonPrettyPrint
        }));
    
        let workerIdSuffix = process.env.workerId ? ("." + process.env.workerId) : "";
        transports.push(new (winston.transports.File)({
            filename: path.join(app.conf.get('log.path'), 'server.log' + workerIdSuffix),
            json: false,
            level: 'info',
            prettyPrint: _jsonPrettyPrint
        }));
    
        app.logger = new (winston.Logger)({
            transports: transports,
            exceptionHandlers: [
                new (winston.transports.File)({
                    filename: path.join(app.conf.get('log.path'), 'error.log' + workerIdSuffix),
                    json: false,
                    prettyPrint: _jsonPrettyPrint
                }),
                new (winston.transports.Console)({
                    colorize: true,
                    prettyPrint: _jsonPrettyPrint
                })
            ]
        });
    
        let accessLogger = new (winston.Logger)({
            transports: [new (winston.transports.File)({
                filename: path.join(app.conf.get('log.path'), 'access.log'),
                json: false,
                level: 'info',
                formatter: (options) => options.message
            })]
    
        });
    
        app.accessLogger = {
            log: function () {
                this.request._endTime = this.request._endTime || new Date;
    
                let request = this.request,
                    response = this.response,
                    elapsed = request._endTime - request._startTime,
                    startTime = moment(request._startTime).format('DD/MMM/YYYY HH:mm:ss ZZ'),
                    instanceId = process.env.workerId ? `instance.${process.env.workerId}` : '';
    
                accessLogger.info(`"${request.ip}" [${startTime}] "${request.method} ${request.url}" "${request.header['user-agent']}" ${response.status} ${elapsed}ms "${instanceId}"`);
            }
        };
    
        app.use(async (ctx, next) => {
            ctx.request._startTime = new Date();
            await next();
            ctx.request._endTime = new Date();
            app.accessLogger.log.call(ctx);
        });
    
        app.use(async (ctx, next) => {
            try {
                await next();
            } catch (err) {
                if (err instanceof BadRequestError) {
                    _handleBadRequestError(ctx, err)
                } else {
                    _handleError(ctx, err);
                }
                ctx.app.emit('error', err, ctx);
            }
        });
    };
    
    function _handleBadRequestError(context, err) {
        context.status = 400;
        context.body = {
            error: err.message
        }
    }
    
    function _handleError(context, err) {
        context.status = err.status || 500;
    
        if (err.response && err.response.body && err.response.body.error) {
            context.body = err.response.body;
        } else {
            let cause = err.response && err.response.error ? err.response.error : err;
            context.body = {
                error: cause.message,
                stack: cause.stack ? cause.stack : cause
            };
        }
    }
    
    function _jsonPrettyPrint(obj) {
        return JSON.stringify(obj);
    }
    

    相关文章

      网友评论

          本文标题:2018-08-14[JavaScript] winston 的

          本文链接:https://www.haomeiwen.com/subject/appvbftx.html