Multithreading Log4J-筛选类似Appender的功能

Multithreading Log4J-筛选类似Appender的功能,multithreading,log4j,spring,logback,Multithreading,Log4j,Spring,Logback,我在一个项目中使用。要求之一是为每个线程创建单独的日志文件;这本身就是一个奇怪的问题,通过动态创建一个新的FileAppender并将其附加到Logger实例来排序 Logger logger = Logger.getLogger(<thread dependent string>); FileAppender appender = new FileAppender(); appender.setFile(fileName); appender.setLayout(new Patte

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

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);
Logger=Logger.getLogger();
FileAppender appender=新FileAppender();
appender.setFile(文件名);
setLayout(新的PatternLayout(lp.getPattern());
appender.setName();
appender.setThreshold(Level.DEBUG);
appender.activateOptions();
logger.addAppender(appender);
一切都进行得很顺利,直到我们意识到我们使用的另一个库——v3.0.0(即使用的库)——没有使用上述技术——Spring日志记录数据只能由从log4.configuration文件初始化的附加器“看到”,而不是由运行时创建的附加器“看到”。 那么,回到原点

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

目前,迁移到LogBack不是一个选项,因此,被Log4J困住了,我如何才能实现类似SiftingAppender的功能并让Spring感到高兴呢

注:Spring仅用于功能,无IOC;为了将Spring的Commons日志“挂钩”到Log4J,我在Log4J.properties文件中添加了这一行:

log4j.logger.org.springframework=DEBUG


按照说明。

可通过。有一个名为的适配器库,它公开了commons日志记录接口,但将所有日志记录到slf4j API,该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>

org.slf4j

)

我想包括所有的slf4j正面/路由器/你称之为什么。还要注意“提供的”hack,它防止依赖项拉入公共日志;之前,我使用了一个名为version-99.0-not-exist的伪空commons日志库

也看到


公用记录
公用记录
1.1.1
假如
公用记录
通用日志api
1.1
假如
org.slf4j
jcl-over-slf4j
${version.slf4j}
org.slf4j
log4j-over-slf4j
${version.slf4j}
org.slf4j
七月至六月
${version.slf4j}
org.slf4j
slf4j api
${version.slf4j}
回写
回归经典
${version.logback}
0.9.15
1.5.8

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

我花了一段时间努力在log4j中找到类似于SiftingAppender的功能(由于某些依赖关系,我们无法切换到logback),最终得到了一个非常好的编程解决方案,使用MDC并在运行时附加记录器:

//这可以是任何特定于线程的字符串
字符串processID=request.getProcessID();
Logger=Logger.getRootLogger();
//如果此标记不存在记录器,请附加新的文件记录器
if(logger.getAppender(processID)==null){
试一试{
字符串模式=“%d{yy/MM/dd HH:MM:ss}%p%c{2}:%m%n”;
字符串logfile=“log/”+processID+“.log”;
FileAppender FileAppender=新的FileAppender(
新模式布局(模式),日志文件,真);
setName(processID);
//添加一个过滤器,以便我们可以忽略来自其他线程的任何日志
addFilter(新的ProcessIDFilter(processID));
logger.addAppender(fileAppender);
}捕获(例外e){
抛出新的运行时异常(e);
}
}
//使用此进程id标记所有子线程,以便我们可以分离日志输出
MDC.put(“进程id”,进程id);
//不管你想在线程中做什么
LOG.info(“此消息将只以“+processID+”.LOG!”结尾);
MDC.删除(“进程id”);
上面附加的筛选器仅检查特定的进程id:

public类RunIdFilter扩展了过滤器{
私有最终字符串runId;
公共RunIdFilter(字符串runId){
this.runId=runId;
}
@凌驾
公共int决定(记录事件){
对象mdc=event.getMDC(“运行id”);
if(runId.equals(mdc)){
返回Filter.ACCEPT;
}
返回Filter.DENY;
}
}
希望这有点帮助

在Log4j2中,我们现在可以使用:

RoutingAppender评估LogEvents,然后将其路由到下级Appender。目标Appender可以是先前配置的Appender,也可以通过其名称引用,或者可以根据需要动态创建Appender

从他们的:

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


如果您只使用Spring作为JDBC功能,那么您可能需要考虑使用像Apache CAMONS DBUTILS这样的东西。我使用的是log4j1。你能帮我处理log4j1.properties吗values@Jerry对不起,我很久没碰过这个了。确保正确设置了MDC。不能提供任何其他帮助。
<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>