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調(diào)用的是回調(diào)函數(shù),所以每次運行這段代碼log的輸出順序不一定一樣。
info: Hello distributed log files!
info: Hello again distributed logs
debug: Now my debug messages are written to console!
當(dāng)我運行第四次輸出的順序是:
info: Hello distributed log files!
debug: Now my debug messages are written to console!
info: Hello again distributed logs

1.2 修改log的輸出目的地
默認情況下,默認的logger只將內(nèi)容輸出到Console。但肯定可以修改的。有兩種方式修改log的輸出目的地。
1.2.1 你可以通過winston.add(), winston.remove()來添加和移除log傳送的途徑。 下面代碼將詳細的log輸出到腳本同級目錄下的somefile.log里,而且還會帶上timestamp**

'use strict';
const winston = require('winston');
/*
 默認情況下,僅在默認記錄器上設(shè)置控制臺傳輸。您可以通過add()和remove()方法添加或刪除傳輸:
 */
winston.add(winston.transports.File, { filename: 'somefile.log' });
winston.remove(winston.transports.Console); //關(guān)閉了控制臺輸出

/* use default logger
 可以通過winston模塊直接訪問默認記錄器??梢栽谀J記錄器上使用您可以在記錄器實例上調(diào)用的任何方法:
 */
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);

/*
 或者通過一次調(diào)用configure()來完成:
 */
'use strict';
const winston = require('winston');

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

/* use default logger
 可以通過winston模塊直接訪問默認記錄器??梢栽谀J記錄器上使用您可以在記錄器實例上調(diào)用的任何方法:
 */
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)創(chuàng)建一個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(大家熟悉的控制臺)
         //并且打開了顏色控制開關(guān)
        new (winston.transports.Console)({ colorize: true }),//Console可以不要參數(shù):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
當(dāng)Exception被拋出時,我們往往希望這個exception可以輸出到特定的地方讓我們可以troubleshooting.
你可以這么設(shè)置, 通過設(shè)置.handleExceptions()或者設(shè)置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

當(dāng)我下載了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

最后附上一份結(jié)合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);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,544評論 19 139
  • 前言 最先接觸編程的知識是在大學(xué)里面,大學(xué)里面學(xué)了一些基礎(chǔ)的知識,c語言,java語言,單片機的匯編語言等;大學(xué)畢...
    oceanfive閱讀 3,377評論 0 7
  • afinalAfinal是一個android的ioc,orm框架 https://github.com/yangf...
    wgl0419閱讀 6,576評論 1 9
  • 今天我跟爸爸一起去看媽媽咪呀,把我嚇得肚子哈哈大笑。晚上我餓了,媽媽給我定了一份披薩,人家贈了飲料,我吃完飯,飽...
    碩仔媽媽成長記閱讀 295評論 0 0
  • Skipfish是由谷歌開發(fā)的一款掃描工具,具有速度快、啟發(fā)式內(nèi)容識別、誤報率低、可生成報告等優(yōu)點。 1.掃描 s...
    FateKey閱讀 3,356評論 0 1

友情鏈接更多精彩內(nèi)容