Log4j 详解:Java经典日志框架

Log4j 详解:Java经典日志框架

在 Java 开发中,日志是排查问题、监控程序运行状态的核心手段。相比于System.out.println,专业的日志框架能提供更灵活的配置、更优的性能和更丰富的功能。本文将全面讲解 Log4j 的核心概念、配置方式及实战技巧,帮助你快速掌握并落地到项目中。

一、日志框架概述

1.1 什么是日志

日志是程序运行过程中产生的事件记录,典型场景包括:

  • 业务流程节点:如 “用户 ID=123 提交订单,订单号 = 456”;
  • 异常详情:捕获异常时记录完整堆栈信息(替代e.printStackTrace());
  • 关键参数 / 结果:如接口入参、返回值;
  • 系统状态:如 JVM 内存使用、数据库连接池状态。

1.2 为什么要打印日志?

调试器断点仅适用于开发阶段,且可能因断点导致多线程问题 “隐藏”;而日志能持久化记录程序运行轨迹,是线上问题排查、生产环境监控的核心依据。

1.3 为什么需要日志框架?

对比System.out.println,Log4j 的优势一目了然:

对比维度System.out.printlnLog4j(日志框架)
性能同步阻塞,高并发下影响性能支持异步输出,性能更优
目的地只能控制台,无法持久化支持控制台、文件、数据库、消息队列等多目的地
格式定制只有文字,无时间、线程、类名、行号自带时间、线程、类、方法、行号等结构化信息
持久化无法自动持久化,需手动处理自动按文件大小 / 时间分割、归档日志
维护性生产环境需手动删除,易遗漏配置控制开关,无需修改代码
级别控制无级别区分,所有信息强制输出可按级别过滤,生产 / 测试环境灵活切换

1.4 常见 Java 日志框架

  • Log4j:Apache 开源经典框架,应用广泛;
  • Logback:Log4j 升级版,性能更优,原生支持 SLF4J;
  • JUL(java.util.logging):JDK 自带,功能简陋;
  • SLF4J:日志门面(接口),统一 API,可切换底层实现(Log4j/Logback 等)。

1.5 Log4j 的优势

  • 配置灵活:支持 XML/Properties 等配置方式,无需改代码即可调整输出;
  • 功能强大:多输出目的地、日志分级、自定义格式;
  • 轻量级:依赖少,占用资源小;
  • 社区成熟:文档丰富,问题解决方案多。

二、Log4j 核心概念

Log4j 的核心由三大组件协同工作,完成日志的采集、输出和格式化:

2.1 Logger(日志记录器)

  • 作用:负责采集日志信息,是程序中直接使用的接口;
  • 命名规则:通常以当前类的全限定名命名(如com.example.demo.UserService),便于定位日志来源;
  • 层级关系:存在父子关系,根 Logger 为rootLogger(所有 Logger 的父类),子 Logger 继承父类配置;
  • 获取方式:Logger logger = Logger.getLogger(当前类.class);

2.2 Appender(输出目的地)

  • 作用:定义日志输出位置,一个 Logger 可绑定多个 Appender(日志同时输出到多个地方);
  • 常见实现类:
    • ConsoleAppender:输出到控制台;
    • FileAppender:输出到文件;
    • RollingFileAppender:按文件大小分割日志(滚动日志);
    • DailyRollingFileAppender:按时间分割日志;
    • JDBCAppender:输出到数据库。

2.3 Layout(日志格式器)

  • 作用:定义日志输出格式(时间、级别、类名、内容等);
  • 常见实现类:
    • PatternLayout:自定义日志模板(最常用);
    • SimpleLayout:仅包含级别和日志信息;
    • HTMLLayout:HTML 格式,适合浏览器查看。

2.4 日志级别(优先级从高到低)

核心规则:只输出级别≥当前 Logger 设置级别的日志

级别说明
FATAL致命错误,程序无法运行(如数据库连接失败、核心配置缺失)
ERROR错误信息,单个异常(如接口调用失败),不影响整体流程
WARN警告信息,状态异常但不报错(如参数不合法、缓存过期)
INFO普通信息,记录正常运行轨迹(如程序启动、接口调用成功)
DEBUG调试信息,开发阶段定位问题(如变量值、方法执行步骤)
TRACE追踪信息,比 DEBUG 更详细,记录代码每一步执行(较少使用)

示例:Logger 设置为 INFO 级别,仅输出 INFO/WARN/ERROR/FATAL 级别的日志。

三、Log4j 环境搭建

3.1 依赖引入(Maven)

Log4j 1.x 核心依赖:

xml

<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> 

3.2 默认日志输出

若未添加配置文件(log4j.properties/log4j.xml),Log4j 启用默认配置:

  • 级别:仅输出 ERROR/FATAL;
  • 目的地:仅控制台;
  • 格式:简单格式(级别 + 日志内容)。

示例代码:

java

import org.apache.log4j.Logger; public class Log4jDefaultDemo { private static final Logger logger = Logger.getLogger(Log4jDefaultDemo.class); public static void main(String[] args) { logger.debug("调试信息:无配置文件时不输出"); logger.info("普通信息:无配置文件时不输出"); logger.error("错误信息:无配置文件时会输出"); logger.fatal("致命信息:无配置文件时会输出"); } } 

运行结果:

ERROR - 错误信息:无配置文件时会输出 FATAL - 致命信息:无配置文件时会输出 

3.3 手动控制日志格式(无配置文件)

若需临时自定义格式,可通过代码构建 Layout 和 Appender:

java

import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; public class Log4jNoConfigTest { private static final Logger logger = Logger.getLogger(Log4jNoConfigTest.class); public static void main(String[] args) { // 自定义格式:时间 [级别] 类名 - 日志内容 PatternLayout layout = new PatternLayout("%d{yyyy-MM-dd HH:mm:ss} [%5p] %c{1} - %m%n"); ConsoleAppender consoleAppender = new ConsoleAppender(layout); logger.addAppender(consoleAppender); logger.setLevel(Level.WARN); // 输出WARN及以上 logger.warn("警告信息:自定义格式输出"); logger.error("错误信息:自定义格式输出"); } } 

四、Log4j 配置详解

配置文件是 Log4j 的核心,支持 Properties 和 XML 格式,启动时优先加载classpath下的log4j.xml,其次是log4j.properties

4.1 Properties 格式配置(入门首选)

4.1.1 配置根 Logger

格式:log4j.rootLogger=日志级别, Appender1, Appender2,...示例:

properties

# 根Logger级别为DEBUG,绑定控制台+文件输出 log4j.rootLogger=DEBUG, CONSOLE, FILE 
4.1.2 配置 ConsoleAppender(控制台输出)

properties

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout # 自定义格式:时间 [级别] 类名 - 内容 log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %c{1} - %m%n 
4.1.3 配置 RollingFileAppender(按大小分割日志)

properties

log4j.appender.FILE=org.apache.log4j.RollingFileAppender log4j.appender.FILE.File=logs/demo.log # 日志路径 log4j.appender.FILE.MaxFileSize=10MB # 单文件最大大小 log4j.appender.FILE.MaxBackupIndex=10 # 最大备份数 log4j.appender.FILE.layout=org.apache.log4j.PatternLayout log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %l - %m%n 
4.1.4 配置 DailyRollingFileAppender(按时间分割)

properties

log4j.appender.DAILY_FILE=org.apache.log4j.DailyRollingFileAppender log4j.appender.DAILY_FILE.File=logs/daily_demo.log log4j.appender.DAILY_FILE.DatePattern='.'yyyy-MM-dd # 按天分割 log4j.appender.DAILY_FILE.layout=org.apache.log4j.PatternLayout log4j.appender.DAILY_FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %c - %m%n 
4.1.5 常用 PatternLayout 转换符
转换符说明
%d日志时间(自定义格式)
%p日志级别
%cLogger 名称(类全限定名)
%c{1}仅显示类名(省略包名)
%l日志位置(类 + 方法 + 行号)
%m日志内容
%n换行符
%t当前线程名称
4.1.6 自定义 Logger(按包 / 类配置)

对指定包 / 类单独配置日志级别,避免全局配置冲突:

properties

# com.example.demo包下日志级别为INFO,仅输出到文件 log4j.logger.com.example.demo=INFO, FILE # 禁止继承根Logger的Appender(避免重复输出) log4j.additivity.com.example.demo=false 

4.2 XML 格式配置(复杂场景)

结构清晰,支持高级功能,示例如下:

xml

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration> <!-- 控制台Appender --> <appender name="CONSOLE"> <layout> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%p] %c{1} - %m%n"/> </layout> </appender> <!-- 滚动文件Appender --> <appender name="FILE"> <param name="File" value="D:/logs/demo.log"/> <param name="MaxFileSize" value="5MB"/> <param name="MaxBackupIndex" value="5"/> <layout> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%p] %l - %m%n"/> </layout> </appender> <!-- 自定义Logger --> <logger name="com.example.demo" additivity="false"> <level value="INFO"/> <appender-ref ref="FILE"/> </logger> <!-- 根Logger --> <root> <level value="DEBUG"/> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </root> </log4j:configuration> 

4.3 Properties vs XML 对比

对比维度Properties 格式XML 格式
语法复杂度简单(键值对)较复杂(标签)
可读性简单配置清晰复杂配置清晰
功能支持基础功能高级功能(条件判断等)
适用场景小型项目 / 入门中大型项目

五、SLF4J + Log4j 整合(注解版)

SLF4J 是日志门面,统一 API,配合 Lombok 的@Slf4j可简化 Logger 创建。

5.1 引入依赖

xml

<!-- SLF4J桥接Log4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.36</version> </dependency> <!-- Lombok(简化Logger创建) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> <scope>provided</scope> </dependency> 

5.2 使用示例

java

import lombok.extern.slf4j.Slf4j; @Slf4j // 自动生成log实例,无需手动创建 public class Slf4jTest { public static void main(String[] args) { // 占位符输出(避免字符串拼接) String username = "zhangsan"; log.info("用户{}登录成功", username); // 记录异常 try { int result = 20 / 0; } catch (Exception e) { log.error("算术异常", e); // 自动打印堆栈 } } } 

5.3 优势

  • 简化代码:无需手动写Logger.getLogger(类.class)
  • API 统一:切换底层框架(如 Logback)无需改业务代码;
  • 性能优化:占位符避免无效字符串拼接。

六、常见问题与注意事项

6.1 问题 1:警告 “Could not find log4j.properties or log4j.xml”

原因:配置文件未放在classpath下(Maven 项目需放在src/main/resources)。

6.2 问题 2:日志无法输出到文件

  • 路径错误:检查File配置的绝对 / 相对路径;
  • 权限不足:目标目录无写入权限;
  • 级别过高:如 Logger 级别为 INFO,DEBUG 日志不会输出。

6.3 问题 3:日志重复输出

原因:自定义 Logger 的additivity为 true(默认),日志同时输出到自定义和根 Logger 的 Appender;解决方案:log4j.additivity.包名=false

6.4 注意事项

  • 生产环境禁用 DEBUG/TRACE:减少日志量,提升性能;
  • 避免字符串拼接:使用占位符(%s/%d);
  • 敏感信息不记录:日志中屏蔽密码、手机号等;
  • 定期清理日志:使用滚动日志避免文件过大。

七、实战案例

7.1 基础案例(控制台 + 文件输出)

步骤 1:配置 log4j.properties

properties

log4j.rootLogger=DEBUG, CONSOLE, FILE # 控制台配置 log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %c{1} - %m%n # 文件配置 log4j.appender.FILE=org.apache.log4j.RollingFileAppender log4j.appender.FILE.File=D:/logs/demo.log log4j.appender.FILE.MaxFileSize=5MB log4j.appender.FILE.MaxBackupIndex=5 log4j.appender.FILE.layout=org.apache.log4j.PatternLayout log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %l - %m%n 
步骤 2:编写业务代码

java

import org.apache.log4j.Logger; public class Log4jDemo { private static final Logger logger = Logger.getLogger(Log4jDemo.class); public static void main(String[] args) { logger.info("程序启动完成"); logger.debug("用户ID=123,查询订单"); try { int result = 10 / 0; } catch (Exception e) { logger.error("计算异常", e); } } } 

7.2 进阶案例(按包配置级别)

需求:com.example.demo.service包下仅输出 INFO 及以上级别:

properties

log4j.rootLogger=DEBUG, CONSOLE log4j.logger.com.example.demo.service=INFO # 单独配置级别 

测试代码:

java

package com.example.demo.service; import org.apache.log4j.Logger; public class UserService { private static final Logger logger = Logger.getLogger(UserService.class); public void login(String username) { logger.debug("验证用户名密码"); // 被过滤 logger.info("用户{}尝试登录", username); // 输出 } } 

Read more

Flutter 三方库 index_generator — 赋能鸿蒙大型项目自动化生成 Export 导出索引,消除繁琐 Import 片段工程化利器(适配鸿蒙 HarmonyOS Next ohos

Flutter 三方库 index_generator — 赋能鸿蒙大型项目自动化生成 Export 导出索引,消除繁琐 Import 片段工程化利器(适配鸿蒙 HarmonyOS Next ohos

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net。 Flutter 三方库 index_generator — 赋能鸿蒙大型项目自动化生成 Export 导出索引,消除繁琐 Import 片段的工程化利器(适配鸿蒙 HarmonyOS Next ohos) 前言 在华为鸿蒙(OpenHarmony)生态的深度开发中,随着业务组件和模型类的爆发式增长,开发者经常会陷入“Import 迷宫”。当你需要引用某个页面时,发现上方堆叠了数十行细碎的文件引用,这不仅影响代码的可读性,更让后续的重构工作(如移动目录)变得极其痛苦。 index_generator 是一款极其高效的命令行工具。它能根据你定义的配置文件,自动扫描指定目录并生成一个统一的“索引文件(Barrel File,通常为 index.dart)”,将目录下的所有组件一键导出。在构建鸿蒙平台的复杂多模块(Multi-module)工程、管理庞大的 UI

By Ne0inhk
【Linux系统编程】(三十五)揭秘 Linux 信号产生:从终端到内核全解析

【Linux系统编程】(三十五)揭秘 Linux 信号产生:从终端到内核全解析

前言         在 Linux 系统中,信号是进程间异步通信的 “信使”,而 “信号产生” 则是这个通信过程的起点。无论是我们熟悉的Ctrl+C终止进程,还是程序运行中出现的段错误、定时器超时,本质上都是信号被触发产生的过程。很多开发者只知道 “信号能终止进程”,却不清楚信号到底是怎么来的 —— 是用户操作触发的?还是系统自动产生的?不同场景下信号的产生机制有何不同?         本文将基于 Linux 内核原理,结合 5 种核心信号产生场景(终端按键、系统命令、函数调用、软件条件、硬件异常),用通俗的语言,带你全方位揭秘信号产生的底层逻辑,让你不仅 “知其然”,更 “知其所以然”。下面就让我们正式开始吧! 一、信号产生的核心本质:谁在 “发送” 信号?         在深入具体场景之前,我们先明确一个核心问题:信号是由谁产生并发送的?答案是操作系统(OS)。         无论信号的触发源头是用户按键、函数调用还是硬件异常,

By Ne0inhk
Flutter 三方库 swagger_parser 自动化打通鸿蒙 API 通信(一键将 Swagger 转化为 Dart 模型)

Flutter 三方库 swagger_parser 自动化打通鸿蒙 API 通信(一键将 Swagger 转化为 Dart 模型)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在进行 OpenHarmony 项目开发时,最枯燥的工作莫过于根据后端提供的 Swagger (OpenAPI) 文档手动编写一个个的 Request 类、Response 类和 API Client。这不仅低效,而且极易因文档更新没对齐而导致 Bug。 swagger_parser 是一个强大的命令行工具,它能直接读取本地或网络上的 Swagger JSON/YAML 文件,自动为你生成完整的 Dart 数据类和 Dio/Chopper API 控制器。 一、核心工作流 Swagger JSON / YAML Swagger Parser Dart 数据模型 (JSON Serialized) Dio / Chopper

By Ne0inhk
DiT(Diffusion Transformer)详解——AIGC时代的新宠儿

DiT(Diffusion Transformer)详解——AIGC时代的新宠儿

扩散模型 相关知识点参考:小白也能读懂的AIGC扩散(Diffusion)模型系列讲解 文章目录论文定义架构与传统(U-Net)扩散模型区别架构噪声调度策略与传统扩散的相同输入图像的Patch化(Patchify)和位置编码Patch化位置编码DiT Block模块详细信息上下文条件化交叉注意力模块adaLN-Zero 模块Layer Normalization(LN)Adaptive Layer Normalization(AdaLN)AdaLN的核心步骤adaLN-ZeroadaLN-Zero的核心步骤说明DiT中具体的初始化U-ViT(U-Net Vision Transformer)DiT 和 U-ViT 的对比 推荐阅读: 1. 一文带你搞懂DiT(Diffusion Transformer) 2. Sora 基础作品之 DiT:Scalable Diffusion Models with Transformer 3. 此文DiT部分:视频生成Sora的全面解析:从AI绘画、ViT到ViViT、TECO、DiT、VDT、NaViT等 部分摘录

By Ne0inhk