一篇 log4js 日志分类收集开发实践

1,609 阅读5分钟

Lynne,一个能哭爱笑永远少女心的前端开发工程师。身处互联网浪潮之中,热爱生活与技术。

前言

一年前参加打卡活动将学习中匆忙整理的文章发了出来,大篇幅摘抄形成抄袭,首先向作者致歉,并附参考文章地址:zhuanlan.zhihu.com/p/22110802

原文内容很翔实,看到这儿的小伙伴可以去原文加强学习。

保留本文,一方面警醒自己,日后坚持原创,一方面决定重写本文,顺便复习下我的日志收集分类管理是如何做的。

本文还是从以下三个方面介绍,结合实际工作:

  • 日志分级
  • 日志分类
  • 日志落盘

看完本文介绍的 log4js,你将可以:

  • 了解log4js基本结构
  • 在项目中使用log4js

实践指南

背景

项目采用服务端渲染同构框架,服务端渲染基于node开发,因此要收集node端请求日志,以及项目中的一些log 及错误日志。

对比过网上实践后决定借助 log4js 编写日志收集中间件。

举个栗子

// file: index.js
import config from '../config' // 导入config配置文件的基本配置信息
import log4jsLog from 'log4js'; // 导入依赖包
import log4jsLogConfig from '../log4js.config'; // 导入配置文件内的配置信息

const logConfig = log4jsLogConfig(config) // 生成最终的配置信息
log4jsLog.configure(logConfig); // 出于配置能更丰富更清晰,借助log4js的API .configure()方法配置日志分类

const graylog = log4jsLog.getLogger('grayLog'); // 生成log4js 的 Logger 实例
      graylog.info(`###gtraceStart###${JSON.stringify(traceInfo)}###gtraceEnd### #PRIVATE_JSON_START#${JSON.stringify(statistics)}#PRIVATE_JSON_END#`); // 调用实例上的api方法

其中 Logger 实例上具有9个API方法是对应到下一小结要讲的日志分级。

为什么使用 log4js 之 log4js 基本能力

level - 日志分级

日志分级这一点可以对应到我们日常使用console.log()方法的console,我们都知道可以通过console的不同api方法输出不同格式日志。其实从日志类型级别的角度看,它也是可以分成不同级别的,主要有:log、info、trace、warn、error,而这里要讲的log4js的分级则更加丰富,也是我们为什么使用loag4js的主要原因。

log4js 的日志分为九个等级,各个级别的名字和权重参考log4js源码中设置如下:

Level.addLevels({
    ALL: { value: Number.MIN_VALUE, colour: 'grey' },
    TRACE: { value: 5000, colour: 'blue' },
    DEBUG: { value: 10000, colour: 'cyan' },
    INFO: { value: 20000, colour: 'green' },
    WARN: { value: 30000, colour: 'yellow' },
    ERROR: { value: 40000, colour: 'red' },
    FATAL: { value: 50000, colour: 'magenta' },
    MARK: { value: 9007199254740992, colour: 'grey' }, // 2^53
    OFF: { value: Number.MAX_VALUE, colour: 'grey' }
});

理一下 log4js 通过日志分级展示日志的主要优点:

  • 不同级别的日志可以在控制台中采用不同的颜色,比如 error 采用红色重点强调
  • 在生产可以有选择的落盘日志:比如error日志、warn日志和其他级别日志单独存放,更方便仅对error日志进行报警处理

category - 日志类型

category可以理解为区分日志的另外一个维度。

通过设置一个 Logger 实例的类型,可以合并落盘不同级别的日志,按照自己的需求组合日志,毕竟实际情况下我们并非一定要完全区分九个级别的日志。

Appender -- 日志落盘

Appender 进一步解决日志落盘问题。

这里我们主要通过 .configure()方法配置日志分类,参数中包含对appender的配置,对日志的级别和类别进行过滤。

layout -- 日志格式

通过 layout 可以自定义输出日志的格式。log4js 内置了物五种类型的格式:

  1. basic:在日志的内容前面会加上时间、日志的级别和类别,通常日志的默认 layout;

  2. colored/coloured:在 basic 的基础上给日志加上颜色,官方提供参考:

  • TRACE - ‘blue’
  • DEBUG - ‘cyan’
  • INFO - ‘green’
  • WARN - ‘yellow’
  • ERROR - ‘red’
  • FATAL - ‘magenta’
  1. Message Pass-Through:只格式化日志事件数据,而不输出时间戳、级别或类别。通常用于使用特定格式序列化事件的追加器;

  2. pattern:这是一种特殊类型,可以通过它来定义任何你想要的格式,这是最灵活也是我采用的一种;

  3. Dummy:此布局只输出日志事件数据中的第一个值。它是为logstashUDP appender添加的。

配置实战

上面提到的知识点都体现在这个配置文件中了

// file: log4js.config.js
log4jsLog.configure(logConfig); // 借助log4js的API .configure()方法配置日志分类
export default function(logConfig: LogConfig) { // 入参即为上面import config from '../config'导入的基本配置信息
  const logDir: string = logConfig.logDir || './logs/';
  const logFilePrefix: string = logConfig.logFilePrefix || 'app';
  const pattern: string =
    logConfig.pattern || '%d{yyyy-MM-dd hh:mm:ss} %p %c %m%n'; // pattern配置日志输出格式
  const pm2: boolean = logConfig.pm2;
  return {
    pm2,
    pm2InstanceVar: 'INSTANCE_ID',
    appenders: {
      infoLog: createLog( // 业务应用 log 日志: - default: info-error
        `${logFilePrefix}-out.log`,
        true,
        logDir,
        pattern,
        isProd
      ),
      warnLog: createLog( // 业务应用 warn 日志 - default: warn
        `${logFilePrefix}-warn.log`,
        true,
        logDir,
        pattern,
        isProd
      ),
      errorLog: createLog( // 业务应用 error 日志 - default: error
        `${logFilePrefix}-error.log`,
        true,
        logDir,
        pattern,
        isProd
      ),
      grayLog: createLog( // 中间件请求日志:info-warn - graylog: info-warn
        `${logFilePrefix}-ctx-access.log`,
        true,
        logDir,
        pattern,
        isProd
      ),
      grayError: createLog( // 中间件请求日志:error-fatal - graylog: info-error
        `${logFilePrefix}-ctx-error.log`,
        true,
        logDir,
        pattern,
        isProd
      ),
      filterInfo: {
        type: 'logLevelFilter',
        appender: 'infoLog',
        level: 'info',
        maxLevel: 'error',
      },
      filterWarn: {
        type: 'logLevelFilter',
        appender: 'warnLog',
        level: 'warn',
        maxLevel: 'warn',
      },
      filterError: {
        type: 'logLevelFilter',
        appender: 'errorLog',
        level: 'error',
        maxLevel: 'error',
      },
      filterGrayLog: {
        type: 'logLevelFilter',
        appender: 'grayLog',
        level: 'info',
        maxLevel: 'warn',
      },
      filterGrayError: {
        type: 'logLevelFilter',
        appender: 'grayError',
        level: 'error',
        maxLevel: 'fatal',
      }
    },
    categories: {
      grayLog: {
        appenders: ['filterGrayLog', 'filterGrayError'],
        level: 'info',
      },
      default: {
        appenders: isProd ? ['filterWarn', 'filterError'] : ['filterInfo'],
        level: isProd ? 'warn' : 'info',
      }
    }
  }
}

总结

上述近介绍了我对log4js的基本配置使用,一般我们是借助实例的api方法进行日志收集与落盘,借助log4js对日志的分级,我还做了一些诸如重写console的log、info、warn和error方法,在中间件上下文ctx添加log方法,实现业务与中间件中的日志落盘。更多地大家就可以自由发挥了。

最后为自己之前的抄袭行为反省致歉,发表到社区的文章不同于笔记,尊重作者。

参考文章