锁定老帖子 主题:log4j 动态日志文件名 的线程安全问题
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-03-15
captmjc 写道 > 方法一对原有写日志的程序需要改动所以我觉得不是很合适
反正你原来的代码,: System.setOut(....); System.out.println(.....); 我觉得,使用同一个Logger,然后根据不同的msg,输出到不特定的有点麻烦,改动log4j的地方太多,IMHO反而更不合适。 > 方法二试过效率实在太低了,影响业务程序 不知道你并发量,JDBCAppender确实很弱,甚至还有bug。但是合理tuning或者自己重写一个DB类的Appender,理论上还是可行的。 还有一种方法,扩展一个File/WriterAppender,路径通过注入clientId自动获取。Override其中的doAppend方法,判断LoggingEvent中的message是否固定格式,比如你这里的"client: ${clientId} "开头,如果是,则super.doAppend(event)否则return. 然后写个AppenderFactory,根据clientId获得不同的实例。 log动作开始前, Appender appender = factory.getAppender(clientId); if (!log.isAttached(appender)) { log.addAppender(appender); } 然后再写日志。 由于org.apache.log4j.helpers.AppenderAttachableImpl.isAttached(Appender)中间使用的是==比较,因此factory.getAppender(clientId)需要用map保留原有实例。 扩展一个File/WriterAppender,路径通过注入clientId自动获取 这个方法应该可以。 也可以参考下面这种方式 http://topic.csdn.net/u/20080102/17/7db9e11c-46ab-4bdc-bdcb-9c19e13c9ef9.html 楼主的client不是太多可以考虑这么做。 如果client会大量增加是不是考虑做日志分析。 |
|
返回顶楼 | |
发表时间:2012-03-15
配置多个logger就没有并发问题,每个logger name为clientid,
LogManager.getLoggerRepository().getLogger(clientid)来获取独立的logger |
|
返回顶楼 | |
发表时间:2012-03-15
感觉这个问题本身用override Appender的subAppend和rollover有点杀鸡用牛刀。
最简单的就是log的同事加上当期thread的id或者name来实现in和out的匹配。 |
|
返回顶楼 | |
发表时间:2012-03-15
kimmking 写道 感觉这个问题本身用override Appender的subAppend和rollover有点杀鸡用牛刀。
最简单的就是log的同事加上当期thread的id或者name来实现in和out的匹配。 请问 in 和out匹配 怎么理解? |
|
返回顶楼 | |
发表时间:2012-03-15
下面的代码能够做到 按clientId写日志文件,,在线程启动的时候 MDC.put("clientId",clientId);
import org.apache.log4j.RollingFileAppender; import org.apache.log4j.spi.LoggingEvent; public class MyRollingFileAppender extends RollingFileAppender{ @Override public synchronized void doAppend(LoggingEvent event) { // TODO Auto-generated method stub String filename = (String)event.getMDC("clientId") ; setFile(filename); activateOptions(); super.doAppend(event); } } 测试了一下,效率略有影响,不知道有没有更好的办法。 效率下降的原因应该是调用activateOptions() 时log4j关闭其它clientId的log文件,打开当前线程对应的clientId的log文件。 不知道有没有更好的办法 |
|
返回顶楼 | |
发表时间:2012-03-15
最后修改:2012-03-15
clientid是固定且是知道的吧,如果是,则可以在log4j配置里配置每个clientid对应logger,logger的名字按照C+clientid的规则,比如C1:
log4j.logger.CLIENTID1=INFO,C1 log4j.appender.C1=org.apache.log4j.DailyRollingFileAppender log4j.appender.C1.file=../../logs/c1.log log4j.appender.C1.file.datepattern=... log4j.appender.C1.layout=org.apache.log4j.PatternLayout log4j.appender.C1.layout.ConversionPattern=%d [%-5p][-t] 然后在程序中建立clientid对应的C+clientid的Map<clientid,Logger>缓存,当新的请求过来时,根据第一个参数clientid从Map中获取对应的Logger,将该Logger放入ThreadLocal中,供后续使用。 |
|
返回顶楼 | |
发表时间:2012-03-15
railway 写道 clientid是固定且是知道的吧,如果是,则可以在log4j配置里配置每个clientid对应logger(名字按照C+clientid的规则,比如C1、C2...),然后在程序中建立clientid对应的C+clientid的Map<clientid,Logger>缓存,当新的请求过来时,根据第一个参数clientid从Map中获取对应的Logger,将该Logger放入ThreadLocal中,供后续使用。
也可行,但是对原来代码的改动太大了。原来的代码都是下面的模式打的日志 import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class Hello{ private static Log log = LogFactory.getLog(Hello.class); public void XX(){ log.info("client :" + clientId +" in-------<"); } |
|
返回顶楼 | |
发表时间:2012-03-15
最后修改:2012-03-15
hasi 写道
railway 写道
clientid是固定且是知道的吧,如果是,则可以在log4j配置里配置每个clientid对应logger(名字按照C+clientid的规则,比如C1、C2...),然后在程序中建立clientid对应的C+clientid的Map<clientid,Logger>缓存,当新的请求过来时,根据第一个参数clientid从Map中获取对应的Logger,将该Logger放入ThreadLocal中,供后续使用。
也可行,但是对原来代码的改动太大了。原来的代码都是下面的模式打的日志 import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Hello{
private static Log log = LogFactory.getLog(Hello.class);
public void XX(){
log.info("client :" + clientId +" in-------<");
}
|
|
返回顶楼 | |
发表时间:2012-03-15
railway 写道
hasi 写道
railway 写道
clientid是固定且是知道的吧,如果是,则可以在log4j配置里配置每个clientid对应logger(名字按照C+clientid的规则,比如C1、C2...),然后在程序中建立clientid对应的C+clientid的Map<clientid,Logger>缓存,当新的请求过来时,根据第一个参数clientid从Map中获取对应的Logger,将该Logger放入ThreadLocal中,供后续使用。
也可行,但是对原来代码的改动太大了。原来的代码都是下面的模式打的日志 import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Hello{
private static Log log = LogFactory.getLog(Hello.class);
public void XX(){
log.info("client :" + clientId +" in-------<");
}
业务类多的很,真的该不过来,再说如果改了就和log4j绑死了。 |
|
返回顶楼 | |
发表时间:2012-03-15
railway 写道
hasi 写道
railway 写道
clientid是固定且是知道的吧,如果是,则可以在log4j配置里配置每个clientid对应logger(名字按照C+clientid的规则,比如C1、C2...),然后在程序中建立clientid对应的C+clientid的Map<clientid,Logger>缓存,当新的请求过来时,根据第一个参数clientid从Map中获取对应的Logger,将该Logger放入ThreadLocal中,供后续使用。
也可行,但是对原来代码的改动太大了。原来的代码都是下面的模式打的日志 import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Hello{
private static Log log = LogFactory.getLog(Hello.class);
public void XX(){
log.info("client :" + clientId +" in-------<");
}
再说了 假设以后不根据clientId分日志文件,,要根据别的特性拆分日志文件的时候也太不灵活了吧 |
|
返回顶楼 | |