近来在做部门的开发技术支持,但是在解决问题的过程中,发现一个很苦逼的事情。。。。就是日志各种混乱。
由于其部分模块,是多条任务线并行处理的,所以,打印日志时,一条任务线在打印日志时,不同类中的方法被调用时打印的日志,可能会被其他线程打印的日志分隔开N行。。查询起来,非常痛苦。。
如
高亮部分为所需日志信息。
因此,我想到,对于这种大量并行的,拥有一条主线索的日志记录,可以用另一个打印方式—就是在任务开始时,用LoggerFactory.getLogger(“任务ID”)获取logger对象。
这样的话,每个活动的日志,都可以用一个简单的 “grep 任务ID ” ,就抽取出来了,非常便于查看。
例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SimpleLog4jTest {
public static void main(String[] args) {
int thrednum = 3;
Logger[] ls = new Logger[thrednum];
for(int a = 0; a < thrednum ; a++){
ls[a] = LoggerFactory.getLogger("我是活动"+ a);
new Thread(new Tlog41(LoggerFactory.getLogger("我是活动"+ a))).start();
}
//TODO 序列化 log对象,下个还可以用。。。不一定需要。
// 场景: ccms节点要流动的,但是如等待节点,时间节点,需要等待很久,可以将该logger对象序列化保存,然后下次继续使用
// 当然了。。如果要序列化保存logger对象的话,对象可以在logger基础上封装一层,保留更多的信息。
// 如果仅仅是logger对象,也可以在每次获取(LoggerFactory.getLogger("活动ID")) 时,将活动id从库中搜出,放入。
// 下部分代码可以运行,运行内容:
// 将上面的Logger对象序列化,等待20秒后,再反序列化后,使用其进行打印,打印信息中的name部分,仍为原name,及原活动ID。
// for(int a = 0; a < thrednum ; a++){
// try {
// FileOutputStream fos = new FileOutputStream("c://" + "我是活动"+ a+ ".out");
// ObjectOutputStream oos = new ObjectOutputStream(fos);
// oos.writeObject(ls[a]);
// oos.close();
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// try {
// Thread.sleep(1000L);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.err.println("序列化好了,你有9秒钟检查。。。");
//
// try {
// Thread.sleep(20000L);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// for(int a = 0; a < thrednum ; a++){
// try {
// String path = "c://" + "我是活动"+ a+ ".out";
// Logger s ;
// FileInputStream fis = new FileInputStream(path);
// ObjectInputStream ois = new ObjectInputStream(fis);
// s = (Logger) ois.readObject();
//
// new Thread(new Tlog41(s)).start();
//
// } catch (Exception ex) {
// ex.printStackTrace();
// }
// }
}
}
class Tlog41 implements Runnable{
private static int b = 0;
private int c = 0;
Logger logger = null;
public Tlog41(Logger logger){
this.logger = logger;
b++;
c = b;
}
@Override
public void run() {
for(int a = 0; a < 100 ; a++){
logger.info(a+ "我zhi dao 就是"+ a+ "试试afsdfkjsdlgkjd"+ "----"+ c);
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
if(c%2 ==0){
throw new Exception(" 要死。。出异常了。。。");
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
}
日志打印如下:
可以发现,名字清晰。。。
这样,一条任务相关日志的抽取,会非常容易。。。
也便于后期,做更规范的日志打印,使得日志成为一个更有效的监控和处理问题的手段(如在每次打印时,统一打印每次打印间的时间间隔,当然若要增强其功能,需要对logger对象进行一定的封装的。。)。
PS:每个线程其实就类似于每个方法,在调用方法时,传入logger对象。。进行打印。。
另外,就是, LoggerFactory.getLogger(name
),在打印异常时,其实堆栈、类名、方法名及行数,其实已经都包含了,所以这个name根本就没必要再用类名这个信息了,而是应该用更有意义的内容,当做 name。
文章写的比较乱。。。从公司头脑风暴中,拉过来的,没有得到太多回应。希望在此找到有相同想法的朋友。。。