繁体   English   中英

使用winston,morgan和winston-daily-rotate-file实现记录器

[英]logger implementation using winston , morgan and winston-daily-rotate-file

我正在尝试在节点js中实现一个记录器,它将在日志的自定义格式上每天创建一个新的日志文件

为此,我使用了三个包

  1. 温斯顿
  2. 摩根
  3. 温斯顿-每天-转-文件

所以每天应该在日志文件夹中创建一个新的日志文件的最终输出,它应该将所有http(摩根日志)和键入的日志(winston日志)记录到以下格式的单个文件中

日期|| 文件名|| statusCode || logMessage || uuid(用于追踪)

例如: Fri Jan 18 2019 13:48:18 GMT + 0530(IST)|| [index.js] || 200 || 调用新路径|| 287dccb0-1afa-11e9-88a0-dfb1c665be9d

所以为此,我写了三个文件index.js(nodejs的根文件)logger.js(logger实现和配置)和logger.test.js(使用jest的logger测试用例)

额外的包

  1. CORS
  2. UUID
  3. HTTP上下文
  4. 应用根路径
  5. 表达-HTTP上下文
  6. 笑话

我遇到的问题

  1. 如果我把一个logger.error在上之前app.listen到CONSOLE.LOG的index.js)({消息:{的StatusCode::200,logMsg “服务器将开始在端口3000”}})(UUID是空值
  2. 我写的测试用例是错误的,我是开玩笑的新手,我只想知道如何检查所有这些情况。
  3. 为什么当我测试套装uuid为null时,我怎么能通过uuid测试用例呢
  4. 我如何检查是否将创建新文件夹,如果已经登录文件夹,那么新文件就会被创建一种测试用例。
  5. 如何根据环境添加其他级别,信息,debuge,警告。 如何改进此代码以实现记录器功能

 // index.js const app = require('express')(); const cors = require('cors') const morgan = require('morgan') // HTTP request logger middleware const logger = require('./config/logger')(module) //Logger const uuid = require('uuid') const httpContext = require('express-http-context') // Use any third party middleware that does not need access to the context here // app.use(some3rdParty.middleware); app.use(httpContext.middleware); // all code from here on has access to the same context for each request // Run the context for each request. // Assigning a unique identifier to each request app.use((req, res, next) => { httpContext.set('reqId', uuid.v1()); next() }) // using morgan with winston(logger) app.use(morgan('combined', { stream: { write: (message) => logger.error(message) } })) app.use(cors()); app.use("/new", (req, res) => { logger.error({ message: { statusCode: 400, logMsg: "hitting new route" } }) nextLayer(res) }) const nextLayer = (res) => { logger.error({ message: { statusCode: 400, logMsg: "hitting in nextLayer function" } }) res.send("OK") } app.listen(4000, () => { console.log('Server running on port 4000'); }) // Logger.js const appRoot = require('app-root-path') const { createLogger, format, transports } = require('winston') const { combine, timestamp, label, printf } = format const path = require('path') require('winston-daily-rotate-file'); const httpContext = require('express-http-context') /** * @method checkMessageProp * @param {message} can be object if developer defined, else it will be string * if its a network request * @returns a fixed format how the status code and message should show */ const checkMessageProp = (message) => { switch (typeof message) { case "object": const { statusCode, logMsg } = message return `${statusCode ? statusCode : "Not Defined"} || ${logMsg ? logMsg : "Not Defined"}`; case "string": let messageSplit = message.split(`"`) var message = messageSplit ? `${messageSplit[2].trim().split(" ")[0]} || ${messageSplit[1]}` : null return message default: return message } } /** * @method customFormat * @param {log} the log passed by the developer or based on network requests * @returns a customFormat how it should be logged to the log files */ const customFormat = printf(log => { const now = new Date(); const reqId = httpContext.get('reqId'); return `${log.timestamp ? new Date(log.timestamp) : now} || [${log.label}] || ${checkMessageProp(log.message)} || ${reqId ? reqId : null}` }); /** * @method getFileName * @param {moduleObj} the module realted object passed from the require of logger file * @returns the file name where the logger was invoked */ const getFileName = moduleObj => { if (Object.keys(moduleObj).length > 0) { let parts = moduleObj.filename.split(path.sep) return parts.pop() } else { return "Module not passed while requiring the logger" } } // Custom settings for each transport const options = moduleObj => { return { dailyRotateFile: { filename: `${appRoot}/logs/TPS-UI-%DATE%.log`, datePattern: 'YYYY-MM-DD', prepend: true, level: "error", timestamp: new Date(), localTime: true } } } // Instantiate a Winston Logger with the settings let logger = moduleObj => { return createLogger({ format: combine( label({ label: getFileName(moduleObj) }), customFormat ), transports: [ new transports.DailyRotateFile(options(moduleObj).dailyRotateFile) ], exitOnError: false // do not exit on handled exceptions }) } module.exports = logger // logger.test.js const logger = require('./logger') beforeEach(() => { mockLoggerMessageObject = { message: { statusCode: 400, logMsg: "Calling in test suite" } } mockLoggerMessageString = `::ffff:127.0.0.1 - - [18/Jan/2019:04:50:57 +0000] "GET /new HTTP/1.1" 200 2 "http://localhost/" "Mozilla/5.0 (linux) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/11.12.0"` mockLoggerMessageNumberFormat = 123 mockLoggerMessageArrayFormat = ["data", "test", 123] }) describe(`Logger test cases`, () => { test('should invoke the logger function with the mock Logger message object', () => { expect(logger(module).error(mockLoggerMessageObject)).toBeDefined() }) test(`should invoke the logger function with empty object`, () => { expect(logger(module).error({})).toBeDefined() }) test(`should invoke the logger function without any module object`, () => { expect(logger({}).error(mockLoggerMessageObject)).toBeDefined() }) test(`should invoke the logger function without any module and message object`, () => { expect(logger({}).error({})).toBeDefined() }) test(`should invoke the logger function with the http request`, () => { expect(logger(module).error(mockLoggerMessageString)).toBeDefined() }) test(`should invoke the logger function with the number format`, () => { expect(logger(module).error(mockLoggerMessageNumberFormat)).toBeDefined() }) test(`should invoke the logger function with the array format`, () => { expect(logger(module).error(mockLoggerMessageArrayFormat)).toBeDefined() }) }) 

对于winston我正在使用timestamp(),这样它会自动将timestamp()属性添加到对象

const {transports, createLogger, format} = require('winston');
const logger = createLogger({
        format: format.combine(
            format.timestamp(),
            format.json()
        ),

另外要检查它是否创建文件你可以模拟日期,比如2019-01-01并检查是否创建文件2019-01-01.log而不是将日期移动到2019-01-02并记录其他内容。 Winston将创建新的文件夹和gzip存档,您可以检查文件是否存在,并且可以解压缩并包含信息

尝试阅读winston的文档。 基本上我会说你可能需要使用

format.timestamp()
format.json()
colorize()

dailyRotate with zippedArchive:true

如果摩根不适合您的需求,您可以尝试直接登录

app.use((req, res, next) => { 
    logger.silly({ message:'start', req,res}); 

    return next().then(r=>logger.silly({ message:'end', req,res}; return r;);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM