解决多线程log4j日志输出混乱的问题,每个线程输出独立的日志

解决多线程log4j日志输出混乱的问题,每个线程输出独立的日志

最近项目中遇到一个问题:多线程场景批量执行任务的时候,所有任务的日志输出到同一个文件中,非常的混乱,根本没有办法查看任务运行情况。

由此衍生出新的需求:多线程场景下实现每个线程日志独立输出。因为任务运行时可能会有数百个任务同时执行,所以不能采用传统的log4j配置文件解决。

解决思路:调用log4j的源码,创建新的实现了log4j接口的类,为每个线程创建logger实例,根据logger实例以变量形式动态设置输出文件。

解决过程:

通过log4j日志文件可以知道,appender主要控制日志输出到什么地方(控制台、文件),layout主要控制日志打印格式。查看org.apache.log4j.RollingFileAppender的源码了解到,构造实例时需要传入layout,filename,datepattern。



创建继承了DailyRollingFileAppender类的ThreadFileAppender类,传入指定的layout,filename,datepattern调用父类的构造函数构建appender对象。


解决了关键的问题点之后,封装一个静态方法返回logger实例,以供业务系统调用。

关键代码如下:

ThreadLogger.java封装了实现代码。

package com.niukl.log4j;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

public class ThreadLogger {

	public static Logger getLogger(String logName) {
		Logger logger = null;

		logger = Logger.getLogger(logName);
		PatternLayout layout = new PatternLayout("[%d{MM-dd HH:mm:ss}] %-5p %-8t %m%n");

		// 日志文件按照每天分文件夹存放
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String logPath = "D://logs/log4jTest/" + sdf.format(new Date()) + "/";

		// 文件输出
		ThreadLogger.ThreadFileAppender fileAppender = null;

		try {
			fileAppender = new ThreadFileAppender(layout, logPath, logName, "yyyy-MM-dd");
		} catch (IOException e) {
			e.printStackTrace();
		}
		fileAppender.setAppend(false);
		fileAppender.setImmediateFlush(true);
		fileAppender.setThreshold(Level.DEBUG);

		// 绑定到logger
		logger.setLevel(Level.DEBUG);
		logger.addAppender(fileAppender);

		return logger;
	}

	/*
	 * 继承了log4j类的内部类
	 */
	public static class ThreadFileAppender extends DailyRollingFileAppender {
		public ThreadFileAppender(Layout layout, String filePath, String fileName, String datePattern)
				throws IOException {
			super(layout, filePath + fileName + ".log", datePattern);
		}
	}
}


MyThread.java是用于执行任务线程的业务类:

package com.niukl.log4j;

import org.apache.log4j.Logger;

public class MyThread implements Runnable {

	String logName;

	public MyThread(String logName) {
		this.logName = logName;
	}

	public void run() {

		// 在run方法内实现线程独立的logger实例
		Logger logger = ThreadLogger.getLogger(logName);

		logger.info(logName + "_" + Thread.currentThread().getName() + " started!");

		logger.error("this is error!");

		logger.info(logName + "_" + Thread.currentThread().getName() + " finished!");
	}
}


TestLog.java用于管理线程:

package com.niukl.log4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;

public class TestLog {

	// 这是主线程的Logger,这些不需独立日志的类也可以创建为普通的Logger,通过log4j配置文件配置参数
	static Logger logger = ThreadLogger.getLogger("main_log");

	public static void main(String[] args) {

		try {
			ExecutorService executor = Executors.newCachedThreadPool();
			logger.info("任务开始执行");

			for (int i = 0; i < 200; i++) {
				MyThread thread = new MyThread(String.valueOf(i));

				executor.submit(thread);
			}
			executor.shutdown();

		} catch (Exception e) {
			e.printStackTrace();
		}
		logger.info("任务结束!");

	}
}



运行效果:

每个线程打印的日志都是独立的,由于任务需要周期性执行,所以采取以天为单位分文件夹存放。



ps:程序中引用的log4j的jar包是log4j-1.2.16.jar


在Ubuntu上使用GDB调试程序时,如果遇到类似 `Missing separate debuginfos` 的错误提示,这通常是因为缺少目标库或二进制文件对应的调试信息。这些调试信息可以帮助GDB更好地理解代码结构、变量位置等细节。 ### 错误原因分析 该错误表示系统中缺失了特定版本的glibc、libgcc 和 libstdc++ 等依赖包的调试符号信息(debug info)。这是因为大多数Linux发行版为了减少安装包大小,默认只提供运行所需的二进制文件,而不包含详细的调试信息。 解决问题需要手动安装相关的“调试信息”软件包。 --- ### 解决方案 #### 步骤 1:确认操作系统环境 首先,检查当前使用的操作系统及架构是否匹配所需调试信息包的要求: ```bash uname -a # 查看内核及相关版本信息 lsb_release -a # 如果有命令可用,则显示具体的 Ubuntu 版本号 ``` 注意:您提到的是 CentOS/RHEL 风格的包名(如 `.el7_9.x86_64`),而您的问题是基于 Ubuntu 发行版的环境,因此建议明确确认实际操作系统的兼容性。如果是跨平台尝试加载RPM风格的CentOS依赖到Debian系(Ubuntu)下,可能会导致更多复杂的问题。 #### 步骤 2:启用Debug Symbol Repository 对于标准的Ubuntu衍生品来说,并非直接采用CentOS那样的`debuginfo-install`工具流程。我们需要通过添加源的方式来获取deb形式的调试符号: 编辑 `/etc/apt/sources.list.d/debug-symbols.list` 文件并加入以下内容: ```text deb http://ddebs.ubuntu.com $(lsb_release -cs) main restricted universe multiverse deb http://ddebs.ubuntu.com $(lsb_release -cs)-security main restricted universe multiverse deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse ``` 接着更新APT缓存数据以便后续步骤能够识别新的仓库资源: ```bash sudo apt-get update ``` #### 步骤 3:查找并安装相关 Debug Package 例如,针对glibc可以这样做: ```bash sudo apt-get install libc6-dbg ``` 其他必要组件像GCC的标准C/C++库也可以一并搜索安装其dbg变体,比如`libgcc1-dbg`, 或者`libstdc++6-dbg`. --- ### 其他注意事项 有时即使完成了上述所有配置仍然无法解决问题,因为某些第三方应用程序自带静态链接库并没有公开发布配套DEBUG INFO的情况存在;此时只能依靠上游开发者提供的支持文档寻找替代办法。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值