踩坑记(1)——使用slf4j+logback记录日志

jar包版本:

<spring.version>3.1.0.RELEASE</spring.version>
<slf4j.version>1.7.25</slf4j.version>
<logback.version>1.2.3</logback.version>
<logback.ext.version>0.1.1</logback.ext.version>

commons-logging:scope为provided,这样是为了打包时不会被带上,也就是不使用commons-logging而是准备使用slf4j
jcl-over-slf4j:这个是桥接包,将已经使用commons-logging记录日志又没法改变(spring默认使用的就是commons-logging)的jar包的日志桥接到slf4
slf4j-api:这就是我们要用的slf4j的日志接口,其实和commons-logging一样都是接口,不是具体实现
logback-classic:具体的日志实现,真正记录日志的jar
logback-ext-spring:为了将logback和spring集成而使用的包,如果不用这个包也可以记录日志,但会有个问题(下文会说)

<!-- log -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>${logback.ext.version}</version>
</dependency>

准备好依赖后,开始配置logback的使用环境
在web.xml中配置logback的监听器,ch.qos.logback.ext.spring.web.LogbackConfigListener类就是logback-ext-spring.jar中的
logback默认也会查找几个地方的配置文件,不过我喜欢自定义路径,毕竟并不是所有公司都会讲配置全部放到resources目录下而是统一在硬盘上进行的管理

<!-- logback -->
<context-param>
<param-name>logbackExposeWebAppRoot</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>logbackConfigLocation</param-name>
<param-value>file:/opt/config/testservice/logback.xml</param-value>
</context-param>
<listener>
<listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
</listener>

问题一:
程序正常启动,本来很开心的一件事,却遇到了转折,当改了java文件的代码并保存后,tomcat热部署reload会导致在项目重新加载过程中爆出异常——说可能导致内存泄露??纳里,表示完全是懵逼的

静下心看了看,发现居然是logback-1这个线程在重载的过程中没有被释放掉,那么每重载一次就会多出一个logback线程,当然也就会造成内存泄露了;在eclipse的debug视图的dubug窗口中查看线程,确实也是这种情况,重载前只有一个logback-1线程,重载后却有两个同名的logback-1了:

重载后如下图,报出内存泄露异常也是对的

那么什么原因造成的呢?我跟着监听器ch.qos.logback.ext.spring.web.LogbackConfigListener跟了下代码,发现是contextDestroyed执行时报错,所以也懒得深究原因了(其实就是代码写的有问题,在logback-ext-spring的0.1.2版本修复了)。

将logback-ext-spring从0.1.1替换到0.1.2(高于0.1.1就行)问题就解决了,看来这个jar包的作者也发现这个问题并修复了。我最后使用的版本就是<logback.ext.version>0.1.3</logback.ext.version>;完全看自己了最高版本目前是0.1.4而我的spring是3.1的最高只能和0.1.3的一起使用。

问题二:

当解决了问题一后,以为终于可以好好玩耍了(其实完全可以正常玩耍了,只是强迫症。。。);同样看了下debug视图的debug窗口,发现刚启动的时候只有一个logback-1线程

之后,每一分钟会多出一个logback-n线程,一共会多出到logback-8,记一个日志有必要这么多线程么?

刚开始以为是哪里代码又问题,后来一想不可能,启动后什么也没做就慢慢增加,所以猜测是logback内部有什么猫腻,然后找到了logback-core内部创建线程池的地方,果然发现指定了常驻线程池的线程数

JDK文档,明确写了“保留在池中的线程数”,这个我是觉得有点多了,所以我就开始找低版本的

发现CoreConstants类中SCHEDULED_EXECUTOR_POOL_SIZE这个常量随着版本在变化,如下:

1.1.9以上     8
1.1.8       2
1.1.7       2
1.1.6及以下   无

最终分析,个人觉得没必要开启常驻内存8个线程来记录日志,所以我选择了1.1.7(参考maven仓库使用记录,选择使用人数较多的)

最终确定jar包版本:

<spring.version>3.1.0.RELEASE</spring.version>
<slf4j.version>1.7.25</slf4j.version>
<logback.version>1.1.7</logback.version>
<logback.ext.version>0.1.3</logback.ext.version>

总结:jar包并不是越新越好,而是要看你用了哪些功能,以上来就使用最新的包往往会出现一些与预期不一致的效果,解决起来又比较头疼~~

最终确定jar包版本:

时间: 2024-08-03 17:13:04

踩坑记(1)——使用slf4j+logback记录日志的相关文章

踩坑记:httpComponents 的 EntityUtils

今天写的一个服务程序,有人报告获得的数据中文乱码,而我是用 apache 通过 httpComponents 去取得数据的,于是开启日志的 debug 级别. 在日志里果然发现中文不见了,有乱码出现: 2014-07-02 16:35:01.348 DEBUG [Wire.java:86] http-outgoing-8 << "<?xml version="1.0" encoding="UTF-8"?>... subject=&q

Spark踩坑记——数据库(Hbase+Mysql)转

转自:http://www.cnblogs.com/xlturing/p/spark.html 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streaming进行实时的数据流处理时,我需要将计算好的数据更新到hbase和mysql中,所以本文对spark操作hbase和mysql的内容进行总结,并且对自己踩到的一些坑进行记录. Spark Streaming持久化设计

Spring @Transactional踩坑记

@Transactional踩坑记 总述 ? Spring在1.2引入@Transactional注解, 该注解的引入使得我们可以简单地通过在方法或者类上添加@Transactional注解,实现事务控制. 然而看起来越是简单的东西,背后的实现可能存在很多默认规则和限制.而对于使用者如果只知道使用该注解,而不去考虑背后的限制,就可能事与愿违,到时候线上出了问题可能根本都找不出啥原因. 踩坑记 1. 多数据源 事务不生效 背景介绍 ? 由于数据量比较大,项目的初始设计是分库分表的.于是在配置文件中

[转]Spark 踩坑记:数据库(Hbase+Mysql)

https://cloud.tencent.com/developer/article/1004820 Spark 踩坑记:数据库(Hbase+Mysql) 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值. 最近一个实时消费者处理任务,在使用spark streaming进行实时的数据流处理时,我需要将计算好的数据更新到hbase和mysql中,所以本文对spark操作hbase和mysql的内容进行总结,并且对自己

记一次 Spring 事务配置踩坑记

记一次 Spring 事务配置踩坑记 问题描述:(SpringBoot + MyBatisPlus) 业务逻辑伪代码如下.理论上,插入数据 t1 后,xxService.getXxx() 方法的查询条件会不满足,会查询不到数据.结果事与愿违,后一次的查询,居然查到了数据. void saveXxx(){  xxService.getXxx(); // 查到一条数据 data1  xxService.insert(); // 插入一条数据 t1  xxService.getXxx(); // 查到

阿里云ECS搭建Kubernetes集群踩坑记

阿里云ECS搭建Kubernetes集群踩坑记 [TOC] 1. 现有环境.资源 资源 数量 规格 EIP 1 5M带宽 ECS 3 2 vCPU 16 GB内存 100G硬盘 ECS 3 2 vCPU 16 GB内存 150G硬盘 SLB 2 私网slb.s1.small 2. 规划 坑: 上网问题,因为只有一个EIP,所有其它节点只能通过代理上网; 负载均衡问题,因为阿里不支持LVS,负载均衡TCP方式后端又不支持访问负载均衡,HTTP和HTTPS方式,只支持后端协议为HTTP; 为了避免上

HttpWebRequest 改为 HttpClient 踩坑记-请求头设置

HttpWebRequest 改为 HttpClient 踩坑记-请求头设置 Intro 这两天改了一个项目,原来的项目是.net framework 项目,里面处理 HTTP 请求使用的是 WebReauest,但是 WebRequest 已经不再推荐使用了,你如果在项目中使用的话,编译器会警告, WebRequest已过时,新项目要 .Net standard 重写就直接 HttpClient 来处理 HTTP 请求了,在改的过程中踩了几个坑,记录一下 请求头处理 HttpClient 通常

windows container 踩坑记

windows container 踩坑记 Intro 我们有一些服务是 dotnet framework 的,不能直接跑在 docker linux container 下面,最近一直在折腾把它部署在 windows container 下,折腾的有点恶心,记录一下. Windows Container 介绍 Windows Container 是微软在 Windows 上的虚拟化实践,它可以提供操作系统级别的虚拟化. 通过我们说的容器化大多是指 Linux Container,基于 linu

coding的svn服务踩坑记

https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/ 前言 Q:咳咳,为啥会用到Coding的SVN?A:博主电脑上已经配好一个co