当前位置: 首页 > news >正文

java_spring boot 中使用 log4j2 及 自定义layout设置示例

1.  log4j2对比 原始Logback 优势

对于 Spring Boot 3.x,Logback 是默认日志框架,但在高并发、异步日志场景下,Log4j2 通常表现更优。当业务百万级用户、微服务、日志量大时:


1. Logback(默认 Spring Boot 集成)

优势:

  • Spring Boot 原生支持:无需额外配置即可使用。

  • 生态成熟:有 logstash-logback-encoder,方便输出 JSON 日志。

  • 简单易用:配置相对直观,官方支持全面。

  • 性能稳定:同步写日志表现很好。

劣势:

  • 异步性能略弱于 Log4j2:需要借助 AsyncAppender,但整体吞吐比 Log4j2 略低。

  • 无内建 LMAX Disruptor:在极端高并发下性能不如 Log4j2。


2. Log4j2

优势:

  • 异步日志性能极强:基于 LMAX Disruptor,比 Logback AsyncAppender 快 10 倍以上。

  • 支持异步安全:IO 密集型日志收集(比如发送到 Kafka)更高效。

  • 灵活的 JSON Layout:自带 JsonTemplateLayout,不依赖第三方包。

  • 热加载配置文件:支持修改日志级别而不重启服务。

劣势:

  • 非默认框架:需要额外依赖,Spring Boot starter 需要 spring-boot-starter-log4j2 替换。

  • 生态稍弱于 Logback:但主流场景完全足够。

2. 使用版本信息

  • spring boot 3.3.2
  • log4j2: 跟随 spring boot版本,不必特意指定 (spring boot 3.3.2 默认对应log4j2 版本 是 2.24.0
  • jackson: 2.17.2 (参考官网 https://github.com/apache/logging-log4j2/blob/rel/2.24.0/src/changelog/2.24.0/update_com_fasterxml_jackson_jackson_bom.xml)
  • win11下

父pom配置

    <!-- https://github.com/spring-projects/spring-boot/releases?page=4 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.2</version> <!--对应 mybatis-plus.version 3.5.8--><relativePath/></parent><properties><log4j2.version>2.24.0</log4j2.version> <!--spring boot 3.3.2 默认对应log4j2--><!--https://github.com/apache/logging-log4j2/blob/rel/2.24.0/src/changelog/2.24.0/update_com_fasterxml_jackson_jackson_bom.xml--><jackson.version>2.17.2</jackson.version><dependencyManagement><dependencies><!-- 核心 Spring Boot Starter,但排除默认日志框架 Logback --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><!-- 强制所有 commons-logging 排除 --><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version> <!-- 任意真实存在的版本 --><!--标记 scope 为 provided,这样 Maven 会认为依赖存在,但不会打包--><scope>provided</scope></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>${jackson.version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>${jackson.version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>${jackson.version}</version></dependency></dependencies></dependencyManagement>

子使用模块 service-user 配置

pom配置:
 

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency><!-- 可选:Log4j2 JSON Layout --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-layout-template-json</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId></dependency>

resources 中的 log4j2-spring.xml 配置

log4j2-spring.xml 必须放到 resources 目录下, 不能再加一层目录。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="TRACE" monitorInterval="30" messageFactory="org.apache.logging.log4j.message.ParameterizedMessageFactory"><Properties><Property name="LOG_PATH">C:/Data/logs</Property><Property name="LOG_FILE_NAME">log_${spring:spring.application.name:-unknown}</Property><Property name="service.name">${spring:spring.application.name:-unknown}</Property></Properties><Appenders><!-- 控制台输出(原始格式) --><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="jjj %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console><!-- JSON 文件输出 --><RollingFile name="JsonFile" fileName="${LOG_PATH}/${LOG_FILE_NAME}.json"filePattern="${LOG_PATH}/${LOG_FILE_NAME}-%d{yyyy-MM-dd}-%i.json"><!-- <PatternLayout pattern="%d %p %C{1.} [%t] %m%n"/>--><JsonTemplateLayout eventTemplateUri="classpath:johnlogging/Log4j2JsonLayoutV4.json"/><Policies><TimeBasedTriggeringPolicy interval="1" modulate="true"/><SizeBasedTriggeringPolicy size="10MB"/></Policies><DefaultRolloverStrategy max="10"/></RollingFile></Appenders><Loggers><!--additivity 属性为“false”,表示在这个日志记录器中,日志不会被发送到它的父级日志记录器中--><Logger name="com.johnsport" level="info" additivity="false"><AppenderRef ref="Console" /><AppenderRef ref="JsonFile" /></Logger><Root level="INFO"><AppenderRef ref="Console"/><AppenderRef ref="JsonFile"/></Root></Loggers>
</Configuration>
Log4j2JsonLayout 自定义

resources 中的 johnlogging目录下 Log4j2JsonLayoutV4.json 配置

{"timestamp": {"$resolver": "timestamp","pattern": {"format": "yyyy-MM-dd HH:mm:ss.SSS","timeZone": "Asia/Shanghai"}},"host": "${hostName:-unknown}","service": "${sys:service.name:-unknown}","level": {"$resolver": "level","field": "name"},"logger": {"$resolver": "logger","field": "name"},"source": {"$resolver": "source","field": "methodName"},"thread": {"$resolver": "thread","field": "name"},"message": {"$resolver": "message","stringified": true},"exception": {"$resolver": "exception","field": "stackTrace","stackTrace": {"stringified": {"truncation": {"suffix": "... [truncated]","pointMatcherStrings": ["servlet.http.HttpServlet"]}}}}
}

子使用模块service-user的 application.yml 相关定义:

spring:application:name: service-user# ...logging:config:- classpath:log4j2-spring.xmllevel:root: info

3. 输出样例

在 指定的目录生成了log文件, 名称为 log_service-user.json

示例内容(手动格式化了下)如下:

{"timestamp": "2025-08-17 19:29:43.094","host": "johnwang","service": "service-user","level": "INFO","logger": "com.yourcompanyname.projname.ServiceUserApplication","thread": "main","message": "Starting ServiceUserApplication v1.0-SNAPSHOT using Java 17.0.15 with PID 41056 (E:\\Data\\code_dir\\v0\\projname_back\\service\\service-user\\target\\service-user-1.0-SNAPSHOT.jar started by jopc in E:\\Data\\code_dir\\v0\\projname_back)"
}
{"timestamp": "2025-08-17 19:29:43.103","host": "johnwang","service": "service-user","level": "DEBUG","logger": "com.yourcompanyname.projname.ServiceUserApplication","thread": "main","message": "Running with Spring Boot v3.3.2, Spring v6.1.11"
}
{"timestamp": "2025-08-17 19:29:43.105","host": "johnwang","service": "service-user","level": "INFO","logger": "com.yourcompanyname.projname.ServiceUserApplication","thread": "main","message": "The following 1 profile is active: \"dev\""
}
{"timestamp": "2025-08-17 19:29:43.184","host": "johnwang","service": "service-user","level": "WARN","logger": "com.alibaba.cloud.nacos.configdata.NacosConfigDataLoader","thread": "main","message": "[Nacos Config] config[dataId=service-user.yaml, group=DEFAULT_GROUP] is empty"
}
{"timestamp": "2025-08-17 19:29:46.083","host": "johnwang","service": "service-user","level": "INFO","logger": "org.springframework.data.repository.config.RepositoryConfigurationDelegate","thread": "main","message": "Multiple Spring Data modules found, entering strict repository configuration mode"
}
{"timestamp": "2025-08-17 19:29:46.087","host": "johnwang","service": "service-user","level": "INFO","logger": "org.springframework.data.repository.config.RepositoryConfigurationDelegate","thread": "main","message": "Bootstrapping Spring Data Redis repositories in DEFAULT mode."
}
{"timestamp": "2025-08-17 19:29:46.128","host": "johnwang","service": "service-user","level": "INFO","logger": "org.springframework.data.repository.config.RepositoryConfigurationDelegate","thread": "main","message": "Finished Spring Data repository scanning in 19 ms. Found 0 Redis repository interfaces."
}
{"timestamp": "2025-08-17 19:29:46.538","host": "johnwang","service": "service-user","level": "INFO","logger": "org.springframework.cloud.context.scope.GenericScope","thread": "main","message": "BeanFactory id=5e73db5d-3847-3fef-bba4-62fff8906613"
}
{"timestamp": "2025-08-17 19:29:48.414","host": "johnwang","service": "service-user","level": "INFO","logger": "org.springframework.boot.web.embedded.tomcat.TomcatWebServer","thread": "main","message": "Tomcat initialized with port 7203 (http)"
}
{"timestamp": "2025-08-17 19:29:48.451","host": "johnwang","service": "service-user","level": "INFO","logger": "org.apache.coyote.http11.Http11NioProtocol","thread": "main","message": "Initializing ProtocolHandler [\"http-nio-7203\"]"
}
{"timestamp": "2025-08-17 19:29:48.457","host": "johnwang","service": "service-user","level": "INFO","logger": "org.apache.catalina.core.StandardService","thread": "main","message": "Starting service [Tomcat]"
}
{"timestamp": "2025-08-17 19:29:48.458","host": "johnwang","service": "service-user","level": "INFO","logger": "org.apache.catalina.core.StandardEngine","thread": "main","message": "Starting Servlet engine: [Apache Tomcat/10.1.26]"
}
{"timestamp": "2025-08-17 19:29:48.560","host": "johnwang","service": "service-user","level": "INFO","logger": "org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]","thread": "main","message": "Initializing Spring embedded WebApplicationContext"
}
{"timestamp": "2025-08-17 19:29:48.563","host": "johnwang","service": "service-user","level": "INFO","logger": "org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext","thread": "main","message": "Root WebApplicationContext: initialization completed in 5369 ms"
}
{"timestamp": "2025-08-17 19:29:49.451","host": "johnwang","service": "service-user","level": "DEBUG","logger": "com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean","thread": "main","message": "Registered plugin: 'MybatisPlusInterceptor{interceptors=[PaginationInnerInterceptor(logger=org.apache.ibatis.logging.slf4j.Slf4jImpl@2adce412, overflow=false, maxLimit=null, dbType=MYSQL, dialect=null, optimizeJoin=true), com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor@629cf53c]}'"
}
{"timestamp": "2025-08-17 19:29:49.456","host": "johnwang","service": "service-user","level": "DEBUG","logger": "com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean","thread": "main","message": "Property 'mapperLocations' was not specified."
}
{"timestamp": "2025-08-17 19:29:51.897","host": "johnwang","service": "service-user","level": "INFO","logger": "com.alibaba.cloud.sentinel.SentinelWebMvcConfigurer","thread": "main","message": "[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: [/**]."
}
{"timestamp": "2025-08-17 19:29:56.239","host": "johnwang","service": "service-user","level": "INFO","logger": "org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver","thread": "main","message": "Exposing 1 endpoint beneath base path '/actuator'"
}
{"timestamp": "2025-08-17 19:29:56.414","host": "johnwang","service": "service-user","level": "INFO","logger": "org.apache.coyote.http11.Http11NioProtocol","thread": "main","message": "Starting ProtocolHandler [\"http-nio-7203\"]"
}
{"timestamp": "2025-08-17 19:29:56.439","host": "johnwang","service": "service-user","level": "INFO","logger": "org.springframework.boot.web.embedded.tomcat.TomcatWebServer","thread": "main","message": "Tomcat started on port 7203 (http) with context path '/'"
}
{"timestamp": "2025-08-17 19:29:56.771","host": "johnwang","service": "service-user","level": "INFO","logger": "com.alibaba.cloud.nacos.registry.NacosServiceRegistry","thread": "main","message": "nacos registry, DEFAULT_GROUP service-user 192.168.171.1:7203 register finished"
}
{"timestamp": "2025-08-17 19:29:57.606","host": "johnwang","service": "service-user","level": "INFO","logger": "com.yourcompanyname.projname.ServiceUserApplication","thread": "main","message": "Started ServiceUserApplication in 20.963 seconds (process running for 23.326)"
}
{"timestamp": "2025-08-17 19:29:57.724","host": "johnwang","service": "service-user","level": "INFO","logger": "com.alibaba.cloud.nacos.refresh.NacosContextRefresher","thread": "main","message": "[Nacos Config] Listening config: dataId=service-user.yaml, group=DEFAULT_GROUP"
}
{"timestamp": "2025-08-17 19:30:10.982","host": "johnwang","service": "service-user","level": "INFO","logger": "org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]","thread": "http-nio-7203-exec-1","message": "Initializing Spring DispatcherServlet 'dispatcherServlet'"
}
{"timestamp": "2025-08-17 19:30:10.982","host": "johnwang","service": "service-user","level": "INFO","logger": "org.springframework.web.servlet.DispatcherServlet","thread": "http-nio-7203-exec-1","message": "Initializing Servlet 'dispatcherServlet'"
}
{"timestamp": "2025-08-17 19:30:10.986","host": "johnwang","service": "service-user","level": "INFO","logger": "org.springframework.web.servlet.DispatcherServlet","thread": "http-nio-7203-exec-1","message": "Completed initialization in 3 ms"
}
{"timestamp": "2025-08-17 19:30:11.581","host": "johnwang","service": "service-user","level": "INFO","logger": "com.zaxxer.hikari.HikariDataSource","thread": "http-nio-7203-exec-1","message": "HikariCP - Starting..."
}
{"timestamp": "2025-08-17 19:30:12.007","host": "johnwang","service": "service-user","level": "INFO","logger": "com.zaxxer.hikari.pool.HikariPool","thread": "http-nio-7203-exec-1","message": "HikariCP - Added connection com.mysql.cj.jdbc.ConnectionImpl@d123cb8"
}
{"timestamp": "2025-08-17 19:30:12.014","host": "johnwang","service": "service-user","level": "INFO","logger": "com.zaxxer.hikari.HikariDataSource","thread": "http-nio-7203-exec-1","message": "HikariCP - Start completed."
}
{"timestamp": "2025-08-17 19:30:12.314","host": "johnwang","service": "service-user","level": "INFO","logger": "com.yourcompanyname.projname.guess.controller.GuessUserController","thread": "http-nio-7203-exec-1","message": "This is an info log test"
}
{"timestamp": "2025-08-17 19:30:12.314","host": "johnwang","service": "service-user","level": "WARN","logger": "com.yourcompanyname.projname.guess.controller.GuessUserController","thread": "http-nio-7203-exec-1","message": "This is a warn log test"
}
{"timestamp": "2025-08-17 19:30:41.521","host": "johnwang","service": "service-user","level": "INFO","logger": "com.yourcompanyname.projname.guess.controller.LogTestController","thread": "http-nio-7203-exec-2","message": "This is an info message"
}
{"timestamp": "2025-08-17 19:30:41.523","host": "johnwang","service": "service-user","level": "ERROR","logger": "com.yourcompanyname.projname.guess.controller.LogTestController","thread": "http-nio-7203-exec-2","message": "Division error occurred","exception": "java.lang.ArithmeticException: / by zero\r\n\tat com.yourcompanyname.projname.guess.controller.LogTestController.testLog(LogTestController.java:40)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)\r\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:568)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)\r\n\tat jakarta.servlet.http.HttpServlet\r\n... [truncated]"
}

http://www.dtcms.com/a/335692.html

相关文章:

  • Ansible 管理变量和事实
  • 计算机毕设选题推荐-基于大数据的全面皮肤病症状数据可视化分析系统【Hadoop、spark、python】
  • 麒麟V10静默安装Oracle11g:lsnrctl、tnsping等文件大小为0的解决方案
  • Android 对话框 - 基础对话框补充(不同的上下文创建 AlertDialog、AlertDialog 的三个按钮)
  • Pandas数据结构详解Series与DataFrame
  • 智能汽车领域研发,复用云原始开发范式?
  • 笔记本电脑wifi小图标不见了 或者 蓝牙功能消失、电脑开不开机解决方法
  • 深入理解C#特性:从应用到自定义
  • CentOS启动两个MySQL实例
  • C#对象的本地保存与序列化详解笔记
  • [每周一更]-(第155期):Go 1.25 发布:新特性、技术思考与 Go vs Rust 竞争格局分析
  • 【前端面试题】前端面试知识点(第三十一题到第六十一题)
  • 项目发布上线清单
  • neo4j导入导出方法
  • 《设计模式》抽象工厂模式
  • 链表OJ题讲解---试金石含金量
  • RabbitMQ入门:生产者和消费者示例
  • Java注解学习记录
  • 什么是EDA(Exploratory Data Analysis,探索性数据分析)
  • AI出题人给出的Java后端面经(十七)(日更)
  • 第 463 场周赛(GPT-3,Me-1)
  • Foreign-Memory Access API外部内存API
  • 混沌工程(Chaos engineering):系统韧性保障之道
  • 计算机网络 HTTPS 全流程
  • p5.js 3D 形状 “预制工厂“——buildGeometry ()
  • 【位运算】查询子数组最大异或值|2693
  • 图灵完备(Turing Complete)免安装中文版
  • 关于pygsp引发的一系列问题和实例小demo
  • ​​Vue 3 开发速成手册
  • 裸机框架:按键模组