2009-12-18 28 views
10

我在使用Log4J一个项目。其中一个要求是为每个线程创建一个单独的日志文件;这本身就是一个奇怪的问题,通过即时创建一个新的FileAppender并将其附加到Logger实例来进行排序。Log4J的 - SiftingAppender一样的功能

Logger logger = Logger.getLogger(<thread dependent string>); 
FileAppender appender = new FileAppender(); 
appender.setFile(fileName); 
appender.setLayout(new PatternLayout(lp.getPattern())); 
appender.setName(<thread dependent string>); 
appender.setThreshold(Level.DEBUG); 
appender.activateOptions(); 
logger.addAppender(appender); 

一切正常,直到我们意识到,其他图书馆,我们使用 - Spring Framework V3.0.0(使用Commons Logging) - 只能由初始化附加目的地春节日志数据被“看到” - 不符合上述技术打球从log4.configuration文件中,而不是由运行时创建的Appenders。 所以,回到原点。

经过一番调查,我发现新的和改进的LogBack有一个appender - SiftingAppender - 这正是我们所需要的,即独立文件上的线程级别日志记录。

目前,移动的logback是不是一种选择,因此,被卡住Log4J的,我怎么能实现SiftingAppender一样的功能,并保持弹簧快乐呢?

注:春天仅用于JdbcTemplate功能,没有IOC;以“钩子”春天的共享记录到Log4J的我加了这条线在log4j.properties文件:

log4j.logger.org.springframework = DEBUG

的指示here

+1

如果您只使用Spring的jdbc功能,那么您可能需要考虑使用类似于apache commons-dbutils的东西。 – 2009-12-18 18:45:34

回答

3

的logback经由slf4j api访问。有一个叫jcl-over-sjf4j适配器库,暴露了公共登录界面,但让所有的记录到SLF4J API,它直接进入执行 - 的logback。如果您正在使用Maven,这里的依存关系:

<dependency> 
    <groupId>org.slf4j</groupId> 
    <artifactId>slf4j-api</artifactId> 
    <version>1.5.8</version> 
</dependency> 
<dependency> 
    <groupId>org.slf4j</groupId> 
    <artifactId>jcl-over-slf4j</artifactId> 
    <version>1.5.8</version> 
</dependency> 
<dependency> 
    <groupId>ch.qos.logback</groupId> 
    <artifactId>logback-core</artifactId> 
    <version>0.9.18</version> 
</dependency> 

(并添加共享记录到排除列表,请参阅here

0

我想包括所有SLF4J外墙/重新路由器/ whateveryoucallthem。还要注意“提供的”黑客攻击,它可以阻止依赖项拉动公共日志记录;以前我使用的是一个虚假的空公共日志记录库,名为版本-99.0-不存在。

另见http://blog.springsource.com/2009/12/04/logging-dependencies-in-spring/

<dependencies> 
    <dependency> 
     <groupId>commons-logging</groupId> 
     <artifactId>commons-logging</artifactId> 

     <!-- use provided scope on real JCL instead --> 
     <!-- <version>99.0-does-not-exist</version> --> 

     <version>1.1.1</version> 

     <scope>provided</scope> 
    </dependency> 

    <dependency> 
     <groupId>commons-logging</groupId> 
     <artifactId>commons-logging-api</artifactId> 

     <!-- use provided scope on real JCL instead --> 
     <!-- <version>99.0-does-not-exist</version> --> 

     <version>1.1</version> 

     <scope>provided</scope> 
    </dependency> 

    <!-- the slf4j commons-logging replacement --> 
    <!-- if any package is using jakarta commons logging this will --> 
    <!-- re-route it through slf4j. --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>jcl-over-slf4j</artifactId> 

     <version>${version.slf4j}</version> 
    </dependency> 

    <!-- the slf4j log4j replacement. --> 
    <!-- if any package is using log4j this will re-route --> 
    <!-- it through slf4j. --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>log4j-over-slf4j</artifactId> 

     <version>${version.slf4j}</version> 
    </dependency> 

    <!-- the slf4j java.util.logging replacement. --> 
    <!-- if any package is using java.util.logging this will re-route --> 
    <!-- it through slf4j. --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>jul-to-slf4j</artifactId> 
     <version>${version.slf4j}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-api</artifactId> 

     <version>${version.slf4j}</version> 
    </dependency> 

    <dependency> 
     <groupId>ch.qos.logback</groupId> 
     <artifactId>logback-classic</artifactId> 

     <version>${version.logback}</version> 
    </dependency> 
</dependencies> 

<properties> 
    <version.logback>0.9.15</version.logback> 
    <version.slf4j>1.5.8</version.slf4j> 
</properties> 
0

你看着log4j.NDC和MDC?这至少允许您将特定于线程的数据标记到日志中。不完全是你问的,但可能是有用的。有一个讨论here

3

我苦苦挣扎了一段时间才在log4j中找到类似SiftingAppender的功能(因为有一些依赖关系,我们无法切换到logback),最后得到了一个程序化的解决方案,运行得非常好,使用MDC和追加记录器运行时间:

// this can be any thread-specific string 
String processID = request.getProcessID(); 

Logger logger = Logger.getRootLogger(); 

// append a new file logger if no logger exists for this tag 
if(logger.getAppender(processID) == null){ 

    try{ 
    String pattern = "%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n"; 
    String logfile = "log/"+processID+".log"; 

    FileAppender fileAppender = new FileAppender(
     new PatternLayout(pattern), logfile, true); 
    fileAppender.setName(processID); 

    // add a filter so we can ignore any logs from other threads 
    fileAppender.addFilter(new ProcessIDFilter(processID)); 

    logger.addAppender(fileAppender); 
    }catch(Exception e){ 
    throw new RuntimeException(e); 
    } 
} 

// tag all child threads with this process-id so we can separate out log output 
MDC.put("process-id", processID); 

//whatever you want to do in the thread 
LOG.info("This message will only end up in "+processID+".log!"); 

MDC.remove("process-id"); 

以上只是附加的过滤器检查特定的进程ID:

public class RunIdFilter extends Filter { 

    private final String runId; 

    public RunIdFilter(String runId) { 
    this.runId = runId; 
    } 

    @Override 
    public int decide(LoggingEvent event) { 
    Object mdc = event.getMDC("run-id"); 

    if (runId.equals(mdc)) { 
     return Filter.ACCEPT; 
    } 

    return Filter.DENY; 
    } 
} 

希望这有助于一点。

0

在Log4j2,我们现在可以使用RoutingAppender

的RoutingAppender评估LOGEVENTS,然后把它们路由到下级追加程序。目标Appender可以是之前配置的appender,可以通过其名称来引用,或者Appender可以根据需要动态创建。

从他们FAQ

如何动态地写入单独的日志文件? 看看RoutingAppender。您可以在配置中定义多个路由,并将值放入ThreadContext映射中,以确定此线程中后续事件记录到哪个日志文件。