log4js基础上手

1,179 阅读7分钟

log4js简介

log4js是nodejs中的一个日志模块,通过设置其优先级别,可以打印出不同级别的日志,便于后续的系统分析。node其他的日志还有bunyanwinston等。

开箱即用,它支持以下功能:

  1. 彩色控制台记录到标准输出或标准输出
  2. 文件追加器,具有基于文件大小或日期的可配置日志滚动
  3. 用于连接/快速服务器的记录器
  4. 可配置的日志消息布局/模式
  5. 不同日志类别的不同日志级别(将应用日志的某些部分设为 DEBUG,其他部分仅设为错误等)

站在巨人的肩膀上,只会看的更远,感谢官方文档和民间使用文档
更多信息看官方文档:log4js-node.github.io/log4js-node… 其他的参考文档:juejin.cn/post/684490…(有点老了)

log4js安装

npm install log4js  (俺的版本是^6.7.1)

基本使用

var log4js = require("log4js");
var logger = log4js.getLogger();
logger.level = "debug";
logger.debug("Some debug messages");

调用.getLogger() 可以获得 log4js 的 Logger 实例,这个实例的用法与 console 是一致的,可以调用.debug(也有.info.error 等方法)来输出日志。将logger对象的level设置为debug(默认为OFF不会输出任何日志)。

运行node test.js,终端输出如下:

由 - 分割开来的说明符区与内容区

说明符:[2023-01-05T10:23:02.337] [DEBUG] default

内容:Some debug messages

等级Level(也叫分级)

Level其实就是日志的分级,log4js 才能更好地为我们展示日志(不同级别的日志在控制台中采用不同的颜色,比如 error 通常是红色的)

log4js 的日志分为九个等级,各个级别的名字和权重如下:

{
  ALL: new Level(Number.MIN_VALUE, "ALL"),
  TRACE: new Level(5000, "TRACE"),
  DEBUG: new Level(10000, "DEBUG"),
  INFO: new Level(20000, "INFO"),
  WARN: new Level(30000, "WARN"),
  ERROR: new Level(40000, "ERROR"),
  FATAL: new Level(50000, "FATAL"),
  MARK: new Level(9007199254740992, "MARK"), // 2^53
  OFF: new Level(Number.MAX_VALUE, "OFF")
}

log4js 的输出级别: trace,debug,info,warn,error,fatal,设置为info后,则只会打印info及其后面类型的日志。

类别(也叫分类)

log4js 还有一个概念就是 category(类别),你可以设置一个 Logger 实例的类型,按照另外一个维度来区分日志:

const log4js = require("log4js");

let loggerOne = log4js.getLogger();
let loggerTwo = log4js.getLogger('main.js');//!!!

loggerOne.level = "debug";
loggerTwo.level = "debug";

loggerOne.debug("Some debug messages");
loggerTwo.debug("Some debug messages");

说明符的default变成了main.js

类别为日志了提供了第二个区分的维度,可以针对不同的 node package 使用不同的category,这样可以区分日志来源于哪个模块(人话就是方便看来自哪个js文件的日志)。

log4js中的配置

先上基础完整代码在逐各分析

const log4js = require("log4js");
// log4js的配置
log4js.configure({
    // 追加器
    appenders: {
        out: {
            type: "stdout",
            layout: {
                type: 'colored'
            }
        },
        app: {
            type: "file",
            filename: "application.log"
        },
    },
  	//类别 
    categories: {
        default: {
            appenders: ["out", "app"],
            level: "debug"
        },
        cheese:{
            appenders: ["out"],
            level: "debug"
        }
    },
});

const loggerOne = log4js.getLogger() //使用默认类别(default)
const loggerTwo = log4js.getLogger('cheese') //使用cheese类别
loggerOne.debug("loggerOne")
loggerOne.info("loggerOne")
loggerOne.warn("loggerOne")
loggerOne.error("loggerOne")
loggerOne.fatal("loggerOne")
loggerOne.mark("loggerOne")
loggerTwo.info('loggerTwo')

一些注意点:

  1. 没有对 log4js 进行任何配置的时候,默认是将日志都输出到了控制台。
  2. log4js 2.0 版本以上 stdout 作为默认 appender, 推荐使用 stdout 而不是 console 打印控制台日志 appender-console 在大量日志输出时会占用 v8 大量内存,拖慢系统性能,不推荐使用 !

appenders(追加器)

关于日志的保存问题(即日志输出到哪里)是由 Appender 来解决。

appenders: {
        out: {
            type: "stdout",//输出在终端中
            layout: {
                type: 'colored'
            }
        },
        app: {
            type: "file",
            //存在当前文件的目录下的 application.log文件中
            filename: "application.log"
        },
    },

outapp是两个不同类型的追加器(人话就是你想怎么输出,咋样输出),每个追加器可以对应单个或多个类别,比如app对应了categories中的default(默认类别)和cheese

type输出样式(列举几个常用其余可以看官方文档)

  1. stdout:日志事件写入标准输出流。它是 log4js 的默认追加器(人话输出在终端看得见)。
  2. file:日志事件写入到文件中。完整的扩展配置后面say。
  3. dateFile:日志事件写入到根据当天日期创建文件中。完整扩展后面say
  4. 其他见官方文档

Layout(列举一些常用的,具体用到见官方文档)

大多数追加器配置将采用一个名为布局的字段,这是一个对象 - 通常具有单个字段类型,该字段类型是下面定义的布局的名称。(人话就是每个追加器都可能有一个layout对象并且只有一个type的属性

type可能有的值:

  1. colored:时间戳、级别和类别将根据日志事件的级别着色(也是log4js默认就选择的)

1. TRACE - ‘blue’
2. DEBUG - ‘cyan’
3.  INFO - ‘green’
4.  WARN - ‘yellow’
5.  ERROR - ‘red’
6.  FATAL - ‘magenta’
  1. basic:基本布局将输出时间戳、级别、类别,后跟格式化的日志事件数据。colored就是在此基础上上色了而已。

  1. messagePassThrough:此布局仅只输出日志事件数据的格式,不输出时间戳、级别或类别。

categories(类别)的配置

categories: {
        default: {
            appenders: ["out", "app"],
            level: "debug"
        },
        cheese:{
            appenders: ["out"],
            level: "debug"
        }
    },

defaultcheese两个不同的类别,两个设置的level都为debug级别,使用的追加器(输出方式)不同(default默认多一个日志事件保存文件)

  1. appenders:选择appenders中设置好的追加器(可以有多个,也就是输出的方式可以有多个,即可输出在终端的同时又输出到log文件中)
  2. level:设置等级(设置能输出日志的等级)

具体使用

file文件类型输出使用

const log4js = require('log4js');
log4js.configure({
    appenders: {
        everything: {
            type: "file",
            filename: "all-the-logs.log",
          	//当大小达到 10Mb 时,它将被重命名并压缩为 all-the-logs.log.1(2,3依次递增)并打开一个名为 all-the-logs.log 的新文件。
            //如果未指定 maxLogSize 或 0,则不会发生日志滚动。后缀K、M、G(dddd)
            maxLogSize: "10M",
            //日志滚动期间要保留的旧日志文件数(不包括热文件all-the-logs.log)(结合下图看更明白)
            backups: 6, 
          	// 是否压缩,会压缩成在all-the-logs.log.1基础上压缩成all-the-logs.log.1.gz文件
            compress: true,
        },
    },
    categories: {
        default: { appenders: ["everything"], level: "debug" },
    },
});
const logger = log4js.getLogger();
// 自行for循环试试看
logger.debug("loggerOne")
logger.info("loggerOne")
logger.warn("loggerOne")

dateFile文件类型使用

const log4js = require('log4js');
log4js.configure({
  appenders: {
    cheese: {
      type: 'dateFile',
      filename: 'logs/cheese.log',
      pattern: "yyyy-MM-dd",
      compress: true,
    	numBackups: 5,
    }
  },
  categories: { 
    default: { 
      appenders: ['cheese'], 
      level: 'info' 
    } 
  }
});

const logger = log4js.getLogger();
logger.debug("loggerOne")
logger.info("loggerOne")
logger.warn("loggerOne")

这个我就逐个分析:

{
  // 只有这两个属性的时候,默认就是一天滚动一次日志
  // 初始文件将是 cheese.log,每日备份是 cheese.log.2023-01-6 等
	type: 'dateFile',
  // 指定输出地址(当前文件下的)
	filename: 'logs/cheese.log',
}
  1. pattern属性:用于确定何时滚动日志的模式。例如:"yyyy-MM-dd-hh",则是每小时滚动一次日志。(不写默认是隔天滚动)
  2. numBackups:日志滚动期间保留旧日志文件数(不包括热文件cheese.log)
  3. compress:开启压缩
  4. 开压缩的情况下就不需要alwaysIncludePattern:true至于为什么大家可以拿我代码去试试看。(压缩和不压缩都是一种选择把,不压缩的话就开启alwaysIncludePattern这样文件命名信息就比较清楚些)

log4js在Node中的应用

我实践的代码(写的可能不是很规范)

官方参考:log4js-node.github.io/log4js-node…

const log4js = require("log4js");
const express = require("express");

log4js.configure({
    appenders: {
        console: { type: "console" },
        file: { type: "file", filename: "cheese.log" },
    },
    categories: {
        cheese: { appenders: ["file"], level: "info" },
        default: { appenders: ["console"], level: "info" },
    },
});

const logger = log4js.getLogger("cheese");
const app = express();

app.use(express.json())
app.use(log4js.connectLogger(logger, {
    level: log4js.levels.INFO,
    // format: ":method :url",
    // 这种方法可以拿请求的数据放进日志中比如id等
    /* format: (req, res, format) =>
        format(
            `:remote-addr - ${req.id} - ":method :url HTTP/:http-version" :status :content-length ":referrer" ":user-agent"`
        ), */
    // 这个则是将post请求的携带的json文件保存进日志中
    format: (req, res, format) =>
        format(`:remote-addr :method :url :status ${JSON.stringify(req.body)}`),
    statusRules: [
        { codes: [303, 304], level: "info" },
        { codes: [404], level: "warn" },
    ],
    // nolog: (req, res) => res.statusCode < 400,
    
}));


app.get("/", function (req, res) {
    res.send("hello world");
});
app.listen(5002);
  1. log4js.connectLogger中间件用来收集访问的信息(自己试试就明白了)。

  2. log4js.connectLogger配置:

    1. level:值可以是"debug"、"info"字符串log4js.levels[.DEBUG]、[.INFO],设置日志等级。
    2. format:设置格式。
      1. :method 请求方式
      2. :url请求地址
      3. HTTP/:http-version htpp版本号
      4. :status 状态码
      5. :content-length 内容长度
      6. :user-agent 用户代理

    1. statusRules:状态规则。{ codes: [404], level: "warn" }如果状态码为404,则等级为warn。

    2. nolog:哪些信息不用输出在log文件上。例子:nolog: (req, res) => res.statusCode < 400状态码小于400的访问信息则不会出现在log文件中。也支持字符串、正则表达式、数组省略日志消息,比如: nolog: "\.gif|\.jpg$",访问example.com/hoge.gif 则会省略日志消息。

  1. express、koa、egg用法大差不差都是中间件使用。log4js.configure中的配置可以放置在json文件中读取使用,log4js.connectLogger中间件方法也可以分离出来,测试就不写那么正式了。