2018-08-14[JavaScript] winston 的使用[不完全说明]

官方文档:
注意别看错版本,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);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容