【问题标题】:I want to display the file Name in the log statement我想在日志语句中显示文件名
【发布时间】:2012-11-04 20:00:53
【问题描述】:

对于任何级别的每个logger语句,我都需要显示执行日志语句的文件名,下面是我在下面给出的说明:

示例: 下面是从 JobWork.js

执行的行
logger.info("getInCompleteJobs in job works");

实际:

2012-11-05T06:07:19.158Z - info: getInCompleteJobs in job works

必填:

2012-11-05T06:07:19.158Z - info JobWork.js : getInCompleteJobs in job works

如果不将文件名作为参数从日志语句中传递,它应该给出文件名。

【问题讨论】:

    标签: node.js logging winston


    【解决方案1】:

    假设每个文件都是一个单独的节点进程,你可以使用类似process.argv[1].match(/[\w-]+\.js/gi)[0]

    如果您正在寻找可以在模块中使用的东西,这可能会起作用:

    process.mainModule.filename.match(/[\w-]+\.js/gi)[0]
    

    【讨论】:

    • 感谢您的评论,它仅用于每次提供相同的文件名,即开始执行的文件名
    • 在这种情况下process.mainModule.filename.match(/[\w-]+\.js/gi)[0] 应该适合你! (它适用于每个根目录)您可以将其用作logger.info(process.mainModule.filename.match(/[\w-]+\.js/gi)[0] + "getInCompleteJobs in job works"); 或看中并将其直接写入记录器。
    【解决方案2】:

    您可以使用附加到 v8 的 Error 对象的堆栈跟踪信息来找出调用您的代码的文件/行。这种方法效果很好,但效果不佳;所以如果你在开发过程中使用它,你会希望在生产时禁用它。

    所以你可以这样做:

      var logger_info_old = logger.info;
      logger.info = function(msg) {
        var fileAndLine = traceCaller(1);
        return logger_info_old.call(this, fileAndLine + ":" + msg);
      }
    
      /**
      * examines the call stack and returns a string indicating 
      * the file and line number of the n'th previous ancestor call.
      * this works in chrome, and should work in nodejs as well.  
      *
      * @param n : int (default: n=1) - the number of calls to trace up the
      *   stack from the current call.  `n=0` gives you your current file/line.
      *  `n=1` gives the file/line that called you.
      */
      function traceCaller(n) {
        if( isNaN(n) || n<0) n=1;
        n+=1;
        var s = (new Error()).stack
          , a=s.indexOf('\n',5);
        while(n--) {
          a=s.indexOf('\n',a+1);
          if( a<0 ) { a=s.lastIndexOf('\n',s.length); break;}
        }
        b=s.indexOf('\n',a+1); if( b<0 ) b=s.length;
        a=Math.max(s.lastIndexOf(' ',b), s.lastIndexOf('/',b));
        b=s.lastIndexOf(':',b);
        s=s.substring(a+1,b);
        return s;
      }
    

    【讨论】:

    • 感谢您的评论,请您看一下这个问题github.com/flatiron/winston/issues/197
    • 好的,具体来说,你想让我对那个 github 问题做什么? mmalecki@github 是正确的:这是一个巨大的性能打击。这对于开发来说可能没问题,但对于生产来说就不行了。当然不能包含在温斯顿本身中。如果你想在你的程序中使用这个功能,你可以覆盖 log 函数(如我上面所示),或者你可以获取自己的 winston 副本,并制作一个具有必要修改的仅开发版本。
    • 为什么b是全球性的?
    【解决方案3】:

    看起来您在这里使用的是 Winston - 我通常将 module 传递到我的记录器模块,然后将 Winston 的 label 属性设置为 module.filename 的解析版本。比如:

    logger.js:

    const path = require('path');
    
    // Return the last folder name in the path and the calling
    // module's filename.
    const getLabel = function(callingModule) {
      const parts = callingModule.filename.split(path.sep);
      return path.join(parts[parts.length - 2], parts.pop());
    };
    
    module.exports = function (callingModule) {
      return new winston.Logger({
        transports: [new winston.transports.Console({
          label: getLabel(callingModule)
        })]
      });
    };
    

    用法(假设模块为controllers/users.js):

    const logger = require('./logger')(module);
    logger.info('foo');
    

    结果:

    2014-11-25T15:31:12.186Z - info: [controllers/users.js] foo
    

    【讨论】:

    • 干得好!注意:我无法让winston 将label 视为函数而不是字符串,因此我最终确定了return new winston.Logger... 之前的标签。反正效率更高。
    • 谢谢,我从项目中提取的代码不正确。现已修复。
    • 哇,使用“模块”作为参数太简单了。谢谢 :-)
    • 这是我试过的所有其他方法中最酷的,但是你如何获得行号?
    • 与@UalterJr 的评论相关。 - 您可以使用 Node 的 path.sep 进行可移植代码:const path = require('path'); ... var parts = callingModule.filename.split(path.sep)
    【解决方案4】:

    使用此代码,它将为您提供带有文件名和行号的日志。将此代码粘贴到新文件winston.js 中,这需要此文件才能使用。

    var winston = require('winston')
    var path = require('path')
    var PROJECT_ROOT = path.join(__dirname, '..')
    var appRoot = require('app-root-path');
    
    
    const options = {
      file: {
        level: 'info',
        filename: `${appRoot}/logs/app.log`,
        handleExceptions: true,
        json: true,
        maxsize: 5242880, // 5MB
        maxFiles: 5,
        colorize: false,
        timestamp: true
      },
      console: {
        level: 'debug',
        handleExceptions: true,
        json: true,
        colorize: true,
        timestamp: true
      }
    };
    
    var logger = new winston.Logger({
      transports: [
        new winston.transports.File(options.file),
        new winston.transports.Console(options.console)
      ],
      exitOnError: false // do not exit on handled exceptions
    });
    
    logger.stream = {
      write: function (message) {
        logger.info(message)
      }
    }
    
    // A custom logger interface that wraps winston, making it easy to instrument
    // code and still possible to replace winston in the future.
    
    module.exports.debug = module.exports.log = function () {
      logger.debug.apply(logger, formatLogArguments(arguments))
    }
    
    module.exports.info = function () {
      logger.info.apply(logger, formatLogArguments(arguments))
    }
    
    module.exports.warn = function () {
      logger.warn.apply(logger, formatLogArguments(arguments))
    }
    
    module.exports.error = function () {
      logger.error.apply(logger, formatLogArguments(arguments))
    }
    
    module.exports.stream = logger.stream
    
    /**
     * Attempts to add file and line number info to the given log arguments.
     */
    function formatLogArguments (args) {
      args = Array.prototype.slice.call(args)
    
      var stackInfo = getStackInfo(1)
    
      if (stackInfo) {
        // get file path relative to project root
        var calleeStr = '(' + stackInfo.relativePath + ':' + stackInfo.line + ')'
    
        if (typeof (args[0]) === 'string') {
          args[0] = calleeStr + ' ' + args[0]
        } else {
          args.unshift(calleeStr)
        }
      }
    
      return args
    }
    
    /**
     * Parses and returns info about the call stack at the given index.
     */
    function getStackInfo (stackIndex) {
      // get call stack, and analyze it
      // get all file, method, and line numbers
      var stacklist = (new Error()).stack.split('\n').slice(3)
    
      // stack trace format:
      // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
      // do not remove the regex expresses to outside of this method (due to a BUG in node.js)
      var stackReg = /at\s+(.*)\s+\((.*):(\d*):(\d*)\)/gi
      var stackReg2 = /at\s+()(.*):(\d*):(\d*)/gi
    
      var s = stacklist[stackIndex] || stacklist[0]
      var sp = stackReg.exec(s) || stackReg2.exec(s)
    
      if (sp && sp.length === 5) {
        return {
          method: sp[1],
          relativePath: path.relative(PROJECT_ROOT, sp[2]),
          line: sp[3],
          pos: sp[4],
          file: path.basename(sp[2]),
          stack: stacklist.join('\n')
        }
      }
    }
    

    【讨论】:

    • else if (args[0].constructor === Object) { args[0] = calleeStr + ' ' + JSON.stringify(args[0], null, 4);这个额外的 else 块也适用于记录对象。
    【解决方案5】:

    带有“consola”包的解决方案(仅限 ES 模块):

    import { createLogger } from '@nitra/consola'
    consola = createLogger(import.meta.url)
    
    consola.debug('TEST')
    

    输出:

    [my-file.js] › TEST
    

    【讨论】:

      猜你喜欢
      • 2017-11-19
      • 2015-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多