前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# log4js入门实例

30 秒速记

  • 比 console.log 多出来的东西:时间、级别、分类、输出位置,都能统一配置
  • 三个核心概念:level 决定打不打,category 标明谁打的,appender 决定打到哪(控制台 / 文件 / 远端)
  • 和 Express 整合用 log4js.connectLogger() 记录每个请求
  • 版本差异大:2.x 之后删掉了 logger.setLevel(),配置统一走 log4js.configure();老文章的写法要按当前文档改
  • 生产日志:结构化、带请求 id、敏感字段脱敏、文件要按天或大小轮转

log4js 解决的是 console.log 管不了的那些事:每条日志带时间和级别、能按模块分类、能按配置决定输出到哪里。 线上排查问题时,一条 console.log(err.message) 你连它几点打的、哪个模块打的都不知道;换成 log4js 后每条日志自带时间、级别和分类,配置里一改就能把 ERROR 单独写到一个文件、把 DEBUG 在生产关掉。要注意它的 API 在 2.x 前后变化很大,网上很多旧示例在新版本里已经跑不通了。

对于线上项目用来说,日志是非常重要的一环。log4js是使用得比较多的一个日志组件,经常跟Express一起配合使用。本文从入门实例开始,讲解log4js的使用,以及如何跟Express进行整合。

面试官追问

追问 1线上接口报错只打了 console.log(error.message),排查时缺什么?
参考回答

缺时间、缺来源模块、缺调用栈、缺请求上下文。至少换成 logger.error(err) 把 stack 带上,再在日志里加请求 id,才能把一次请求的几条日志串起来。

追问 2项目有用户、订单、支付三个模块,日志分类怎么划?
参考回答

按模块拿 logger:log4js.getLogger('order'),日志里就会带 [order],配置里还能让支付模块单独写一个文件。分到函数级别就太细了,配置会膨胀,没人维护。

追问 3服务跑在容器里,日志该写文件还是写 stdout?
参考回答

容器里优先 stdout,由平台的日志采集统一收集,容器删了文件也就没了。非容器部署写文件就得配轮转,用 dateFile 或 file 的 maxLogSize + backups,不然迟早把磁盘写满。

追问 4logger.error(err) 和 logger.error(err.message) 有区别吗?
参考回答

有。传 Error 对象,默认布局会把 stack 一起打出来;只传 message 就丢了调用栈,线上很难知道错误从哪抛出来的。

# 入门例子

30 秒速记

  • 最小三步:require('log4js') → getLogger() → logger.debug('hello world')
  • 输出格式:[时间] [级别] [分类] - 消息,分类不传就是 default
  • 时间、级别、分类都是 log4js 补的,你只传了消息
  • 新版本坑:6.x 起默认级别是 OFF,不配置什么都不输出,要先 logger.level = 'debug'
  • 消息支持 util.format 占位符:logger.info('user %s login', name)

入门例子就是拿一个默认 logger 打一行日志,看到输出里自动带上了时间、级别和分类。 你只传了 'hello world',前面的 [2017-02-28 ...] [DEBUG] [default] 都是 log4js 按布局补上去的,default 是因为 getLogger() 没传分类名。这里有个版本坑要知道:老版本默认会输出,但 log4js 6.x 起默认分类的级别是 OFF,这段代码直接跑什么都看不到,要先写一句 logger.level = 'debug'。

输出日志如下,包括日志打印时间、日志级别、日志分类、日志内容。

// started.js
var log4js = require('log4js');
var logger = log4js.getLogger();
logger.debug('hello world');

// 输出:
// [2017-02-28 21:28:22.853] [DEBUG] [default] - hello world
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1照着教程写了 getLogger() 再 logger.debug('hello'),控制台什么都没有,为什么?
参考回答

新版本里默认级别是 OFF,这是为了让库作者引入 log4js 时不会污染用户的输出。加一句 logger.level = 'debug',或者用 log4js.configure 配一个 default 分类和 stdout 输出。

追问 2输出里的时间、DEBUG、default 是从哪来的?
参考回答

都是 log4js 的布局补上的,默认布局等价于 pattern 布局的 %d %p %c %m:时间、级别、分类、消息。改布局只影响输出格式,不影响你的调用代码。

追问 3想在日志里拼变量,logger.info('user ' + name) 和 logger.info('user %s', name) 选哪个?
参考回答

选后者。占位符写法用的是 util.format,传对象时也能正确展开;级别被过滤掉时也省了一次字符串拼接。

追问 4监控同学想从这种文本日志里解析接口耗时,靠谱吗?
参考回答

不靠谱,自由文本一改格式解析就崩。要统计就输出结构化日志,比如自定义一个 JSON 布局,把接口名、耗时、状态码作为独立字段,让日志平台直接按字段聚合。

# 日志级别

30 秒速记

  • 级别从低到高:TRACE < DEBUG < INFO < WARN < ERROR < FATAL,设了某一级,低于它的都不打
  • 示例设 INFO:debug() 被吞掉,info() 和 error() 正常输出
  • 过滤发生在 logger 内部,低级别日志根本不会被格式化和写出
  • 写法分版本:老版本 logger.setLevel('INFO'),2.x 以后改成 logger.level = 'info' 或在 configure 的 categories 里配 level
  • 一般开发用 DEBUG,生产用 INFO,排障时临时下调

设置日志级别就是设一个门槛,只有大于等于这个级别的日志才会输出。 示例里门槛是 INFO,所以 debug() 那条直接被丢掉,info() 和 error() 能打出来。这个过滤是在 logger 内部做的,低于门槛的调用连格式化都不会走,所以生产环境放心留着 debug() 调用,开发时调低门槛就能看到。写法要注意版本,setLevel 是老 API,log4js 2.x 以后要写成 logger.level = 'info',或者在 configure 里按分类配。

logger.setLevel('INFO'); 表示想要打印的最低级别的日志是INFO,也就是说,调用类似logger.debug()等级别低于INFO的接口,日志是不会打印出来的。

var log4js = require('log4js');
var logger = log4js.getLogger();
logger.setLevel('INFO');

logger.debug('level: debug');
logger.info('level: info');
logger.error('level: error');

// 输出如下:
// [2017-02-28 21:50:45.372] [INFO] [default] - level: info
// [2017-02-28 21:50:45.376] [ERROR] [default] - level: error
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1级别设成 INFO 后,debug() 的日志是被打出来再被日志平台过滤掉的吗?
参考回答

不是,在 logger 这一层就被拦下了,根本不会写到任何 appender。如果后面还有日志平台的过滤规则,那是另一层,和这里无关。

追问 2升级 log4js 后启动报 logger.setLevel is not a function,怎么改?
参考回答

2.x 起删掉了这个方法。直接改成 logger.level = 'info';更推荐在 log4js.configure 的 categories 里写 default: { appenders: ['out'], level: 'info' },所有级别集中在配置里管。

追问 3线上出问题想临时看 DEBUG 日志,又不想重新发版,怎么做?
参考回答

级别从环境变量读:logger.level = process.env.LOG_LEVEL || 'info',改环境变量重启就生效。要注意 DEBUG 日志量可能翻几倍,看完记得调回去,也要确认里面没打敏感信息。

追问 4构造日志参数本身很耗时,级别被关掉了还会执行吗?
参考回答

会。logger.debug(JSON.stringify(bigObj)) 里的 JSON.stringify 在调用前就执行了。热点路径可以先判断:if (logger.isDebugEnabled()) logger.debug(...)。

追问 5有人要求生产只开 ERROR 级别省磁盘,你怎么看?
参考回答

基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
      • 入门例子
      • 日志级别
      • 日志类别
      • appenders
      • express应用
      • 相关链接
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

log4js入门实例|Nodejs专题系列

# log4js入门实例

30 秒速记

  • 比 console.log 多出来的东西:时间、级别、分类、输出位置,都能统一配置
  • 三个核心概念:level 决定打不打,category 标明谁打的,appender 决定打到哪(控制台 / 文件 / 远端)
  • 和 Express 整合用 log4js.connectLogger() 记录每个请求
  • 版本差异大:2.x 之后删掉了 logger.setLevel(),配置统一走 log4js.configure();老文章的写法要按当前文档改
  • 生产日志:结构化、带请求 id、敏感字段脱敏、文件要按天或大小轮转

log4js 解决的是 console.log 管不了的那些事:每条日志带时间和级别、能按模块分类、能按配置决定输出到哪里。 线上排查问题时,一条 console.log(err.message) 你连它几点打的、哪个模块打的都不知道;换成 log4js 后每条日志自带时间、级别和分类,配置里一改就能把 ERROR 单独写到一个文件、把 DEBUG 在生产关掉。要注意它的 API 在 2.x 前后变化很大,网上很多旧示例在新版本里已经跑不通了。

对于线上项目用来说,日志是非常重要的一环。log4js是使用得比较多的一个日志组件,经常跟Express一起配合使用。本文从入门实例开始,讲解log4js的使用,以及如何跟Express进行整合。

面试官追问

追问 1线上接口报错只打了 console.log(error.message),排查时缺什么?
参考回答

缺时间、缺来源模块、缺调用栈、缺请求上下文。至少换成 logger.error(err) 把 stack 带上,再在日志里加请求 id,才能把一次请求的几条日志串起来。

追问 2项目有用户、订单、支付三个模块,日志分类怎么划?
参考回答

按模块拿 logger:log4js.getLogger('order'),日志里就会带 [order],配置里还能让支付模块单独写一个文件。分到函数级别就太细了,配置会膨胀,没人维护。

追问 3服务跑在容器里,日志该写文件还是写 stdout?
参考回答

容器里优先 stdout,由平台的日志采集统一收集,容器删了文件也就没了。非容器部署写文件就得配轮转,用 dateFile 或 file 的 maxLogSize + backups,不然迟早把磁盘写满。

追问 4logger.error(err) 和 logger.error(err.message) 有区别吗?
参考回答

有。传 Error 对象,默认布局会把 stack 一起打出来;只传 message 就丢了调用栈,线上很难知道错误从哪抛出来的。

# 入门例子

30 秒速记

  • 最小三步:require('log4js') → getLogger() → logger.debug('hello world')
  • 输出格式:[时间] [级别] [分类] - 消息,分类不传就是 default
  • 时间、级别、分类都是 log4js 补的,你只传了消息
  • 新版本坑:6.x 起默认级别是 OFF,不配置什么都不输出,要先 logger.level = 'debug'
  • 消息支持 util.format 占位符:logger.info('user %s login', name)

入门例子就是拿一个默认 logger 打一行日志,看到输出里自动带上了时间、级别和分类。 你只传了 'hello world',前面的 [2017-02-28 ...] [DEBUG] [default] 都是 log4js 按布局补上去的,default 是因为 getLogger() 没传分类名。这里有个版本坑要知道:老版本默认会输出,但 log4js 6.x 起默认分类的级别是 OFF,这段代码直接跑什么都看不到,要先写一句 logger.level = 'debug'。

输出日志如下,包括日志打印时间、日志级别、日志分类、日志内容。

// started.js
var log4js = require('log4js');
var logger = log4js.getLogger();
logger.debug('hello world');

// 输出:
// [2017-02-28 21:28:22.853] [DEBUG] [default] - hello world
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1照着教程写了 getLogger() 再 logger.debug('hello'),控制台什么都没有,为什么?
参考回答

新版本里默认级别是 OFF,这是为了让库作者引入 log4js 时不会污染用户的输出。加一句 logger.level = 'debug',或者用 log4js.configure 配一个 default 分类和 stdout 输出。

追问 2输出里的时间、DEBUG、default 是从哪来的?
参考回答

都是 log4js 的布局补上的,默认布局等价于 pattern 布局的 %d %p %c %m:时间、级别、分类、消息。改布局只影响输出格式,不影响你的调用代码。

追问 3想在日志里拼变量,logger.info('user ' + name) 和 logger.info('user %s', name) 选哪个?
参考回答

选后者。占位符写法用的是 util.format,传对象时也能正确展开;级别被过滤掉时也省了一次字符串拼接。

追问 4监控同学想从这种文本日志里解析接口耗时,靠谱吗?
参考回答

不靠谱,自由文本一改格式解析就崩。要统计就输出结构化日志,比如自定义一个 JSON 布局,把接口名、耗时、状态码作为独立字段,让日志平台直接按字段聚合。

# 日志级别

30 秒速记

  • 级别从低到高:TRACE < DEBUG < INFO < WARN < ERROR < FATAL,设了某一级,低于它的都不打
  • 示例设 INFO:debug() 被吞掉,info() 和 error() 正常输出
  • 过滤发生在 logger 内部,低级别日志根本不会被格式化和写出
  • 写法分版本:老版本 logger.setLevel('INFO'),2.x 以后改成 logger.level = 'info' 或在 configure 的 categories 里配 level
  • 一般开发用 DEBUG,生产用 INFO,排障时临时下调

设置日志级别就是设一个门槛,只有大于等于这个级别的日志才会输出。 示例里门槛是 INFO,所以 debug() 那条直接被丢掉,info() 和 error() 能打出来。这个过滤是在 logger 内部做的,低于门槛的调用连格式化都不会走,所以生产环境放心留着 debug() 调用,开发时调低门槛就能看到。写法要注意版本,setLevel 是老 API,log4js 2.x 以后要写成 logger.level = 'info',或者在 configure 里按分类配。

logger.setLevel('INFO'); 表示想要打印的最低级别的日志是INFO,也就是说,调用类似logger.debug()等级别低于INFO的接口,日志是不会打印出来的。

var log4js = require('log4js');
var logger = log4js.getLogger();
logger.setLevel('INFO');

logger.debug('level: debug');
logger.info('level: info');
logger.error('level: error');

// 输出如下:
// [2017-02-28 21:50:45.372] [INFO] [default] - level: info
// [2017-02-28 21:50:45.376] [ERROR] [default] - level: error
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1级别设成 INFO 后,debug() 的日志是被打出来再被日志平台过滤掉的吗?
参考回答

不是,在 logger 这一层就被拦下了,根本不会写到任何 appender。如果后面还有日志平台的过滤规则,那是另一层,和这里无关。

追问 2升级 log4js 后启动报 logger.setLevel is not a function,怎么改?
参考回答

2.x 起删掉了这个方法。直接改成 logger.level = 'info';更推荐在 log4js.configure 的 categories 里写 default: { appenders: ['out'], level: 'info' },所有级别集中在配置里管。

追问 3线上出问题想临时看 DEBUG 日志,又不想重新发版,怎么做?
参考回答

级别从环境变量读:logger.level = process.env.LOG_LEVEL || 'info',改环境变量重启就生效。要注意 DEBUG 日志量可能翻几倍,看完记得调回去,也要确认里面没打敏感信息。

追问 4构造日志参数本身很耗时,级别被关掉了还会执行吗?
参考回答

会。logger.debug(JSON.stringify(bigObj)) 里的 JSON.stringify 在调用前就执行了。热点路径可以先判断:if (logger.isDebugEnabled()) logger.debug(...)。

追问 5有人要求生产只开 ERROR 级别省磁盘,你怎么看?
参考回答

出了问题只有一行报错,前面请求进来、走了哪个分支全没有,很难还原现场。我一般保留 INFO,控制好 INFO 的打印量,同时配好文件轮转。

# 日志类别

30 秒速记

  • category = 日志归属,回答「这条日志是哪个模块打的」;级别回答「有多严重」,两个维度别混
  • 写法:log4js.getLogger('order'),输出里会带上类别名 [INFO] order - hello
  • 类别名要稳定、按模块或业务边界起,别把用户 ID、请求号塞进去,类别会无限膨胀
  • 新版(v2+)类别还决定走哪些 appender、用什么级别,没配置的类别回落到 default

category 就是给日志贴一个来源标签,同样一句 hello,你能一眼看出是订单模块还是支付模块打的。 用法很简单,getLogger('order') 拿到的 logger 打出来的每一行都带着 order。我一般按模块起名,比如 http、db、order,团队统一一份清单。它和级别是两回事:级别管过滤,类别管归属和路由,新版 log4js 里还可以按类别配不同的输出位置和门槛,比如 db 类别单独写一个文件。

除级别外,还可以对日志进行分类,log4js.getLogger(category),如下所示

var log4js = require('log4js');
var alogger = log4js.getLogger('category-a');
var blogger = log4js.getLogger('category-b');

alogger.info('hello');
blogger.info('hello');

// 输出如下:
// [2017-02-28 22:36:57.570] [INFO] category-a - hello
// [2017-02-28 22:36:57.574] [INFO] category-b - hello
@前端进阶之旅: 代码已经复制到剪贴板

← httpsnode8_napi →

fe