无法为 class 的实例创建单独的日志文件,它们分别在各自的线程上 运行 - log4j2
Unable to create separate log file for instances of a class which are running on their own threads separately - log4j2
很抱歉提出这样一个常见问题,但是在应用这些解决方案后我无法解决我的问题。
所以基本上,我已经创建了一个网络,它允许我分别在它们自己的单独线程上执行不同的服务器。现在问题是它除了日志记录外工作正常。
What I want to achieve:
I want to have separate log file per server.. based on the id of that server, for example
main.log , server1.log , server2.log , server3.log , server4.log , etc...
目前发生了什么?
我尝试过的两种主要方法:-
尝试了选项 1:-
Log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} %l - %msg%n"/>
</Console>
<File name="AppMain" filename="logs/main.log" append="false">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} %l - %msg%n"/>
</File>
<Routing name="RoutingAppender">
<Routes pattern="$${sys:logFilename}">
<Route>
<File name="Rolling-${sys:logFilename}" fileName="logs/${sys:logFilename}.log" append="false">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} %l - %msg%n"/>
</File>
</Route>
<!-- By having this set to ${ctx:logFileName} it will match when filename
is not set in the context -->
<Route ref="Console" key="${sys:logFilename}"/>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Root level="info">
<!--<AppenderRef ref="Console"/>-->
<AppenderRef ref="Console"/>
<AppenderRef ref="AppMain"/>
</Root>
<Logger name="ServerRouting" level="all" additivity="false">
<!-- <AppenderRef ref="Console"/>-->
<AppenderRef ref="RoutingAppender"/>
</Logger>
</Loggers>
</Configuration>
Server.java:-
public class Server {
private static Logger logger;
private long id;
private SomeClass someClass;
public Server(long id, SomeClass someClass) {
this.id=id;
this.someClass=someClass;
System.setProperty("logFilename", "server"+id);
logger = LogManager.getLogger(Constants.DYNAMIC_SERVERS);
this.someClass.setLogger(logger);
}
public void bindSockets(String servername, int port) throws IOException { /*Some functionality*/}
public void start() throws IOException { /*Some functionality*/}
}
Constants.java
public class Constants {
static {
System.setProperty("log4j.configurationFile", "log4j2.xml");
}
public static String APP_NAME = "AppMain";
public static String DYNAMIC_SERVERS = "ServerRouting";
}
使用这种方法 - 当我启动 4 个服务器时,我得到:
main.log , server2.log , server3.log , server4.log
However the internal entries are all mixed up , and no file for server1 (i.e. server1.log) is created
尝试了选项 2:-
Log4j2.xml
我替换了早期日志中的 Routes 块
<Routes pattern="$${ctx:ROUTINGKEY}">
<!-- This route is chosen if ThreadContext has value 'special' for key ROUTINGKEY. -->
<Route>
<RollingFile name="Rolling-${ctx:ROUTINGKEY}" fileName="logs/${ctx:ROUTINGKEY}.log"
filePattern="./logs/${date:yyyy-MM}/${ctx:ROUTINGKEY}-special-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout>
<pattern>%d{ISO8601} [%t] %p %c{3} - %m%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="6" modulate="true"/>
<SizeBasedTriggeringPolicy size="10 MB"/>
</Policies>
</RollingFile>
</Route>
</Routes>
Server.java:-
我在这里更改的是,我没有使用 System.setProperty(),而是使用 ThreadContext.put(),将日志文件名发送到 log4j2
public class Server {
private static Logger logger;
private long id;
private SomeClass someClass;
public Server(long id, SomeClass someClass) {
this.id=id;
this.someClass=someClass;
ThreadContext.put("ROUTINGKEY", "server"+id);
logger = LogManager.getLogger(Constants.DYNAMIC_SERVERS);
this.someClass.setLogger(logger);
}
public void bindSockets(String servername, int port) throws IOException { /*Some functionality*/}
public void start() throws IOException { /*Some functionality*/}
}
使用这种方法 - 当我启动 4 个服务器时,我得到:只有这两个文件
main.log , ${ctx:ROUTINGKEY}.log
Instead of 4 , as mentioned in beginning.
Where, all the internal entries for all servers have been added to single file i.e. ${ctx:ROUTINGKEY}.log
结论
谁能告诉我我做错了什么?这将是一个巨大的帮助。
显然欢迎新的建议,如果我的问题有歧义,请告诉我。
我认为有两个问题。
- 您在
Server
class 中将 logger
声明为 static
,因此在该 class 的所有实例之间共享记录器。
LogManager.getLogger
方法不是线程安全的,以这种方式使用时必须同步。
下面是一些适用于我的示例代码和配置:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
public class Server {
private Logger logger;
private long id;
public Server(long id, Object lock) {
this.id=id;
ThreadContext.put("ROUTINGKEY", "server"+id);
synchronized(lock){
logger = LogManager.getLogger(Constants.DYNAMIC_SERVERS);
}
}
public void doStuff(){
logger.info("Server "+ id +" did some stuff");
}
}
A class 在单独的线程中启动 4 个服务器:
public class Main {
public static void main(String[] args) {
final Object lock = new Object();
Thread t1 = new Thread(new Runnable(){
public void run(){
Server s = new Server(1,lock);
s.doStuff();
}
});
Thread t2 = new Thread(new Runnable(){
public void run(){
Server s = new Server(2,lock);
s.doStuff();
}
});
Thread t3 = new Thread(new Runnable(){
public void run(){
Server s = new Server(3,lock);
s.doStuff();
}
});
Thread t4 = new Thread(new Runnable(){
public void run(){
Server s = new Server(4,lock);
s.doStuff();
}
});
t1.start();
t2.start();
t3.start();
t4.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
为了完整起见,常量class:
public class Constants {
public static String APP_NAME = "AppMain";
public static String DYNAMIC_SERVERS = "ServerRouting";
}
和log4j2.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} %l - %msg%n" />
</Console>
<File name="AppMain" filename="logs/main.log" append="false">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} %l - %msg%n" />
</File>
<Routing name="RoutingAppender">
<Routes pattern="$${ctx:ROUTINGKEY}">
<!-- This route is chosen if ThreadContext has value 'special' for key
ROUTINGKEY. -->
<Route>
<RollingFile name="Rolling-${ctx:ROUTINGKEY}" fileName="logs/${ctx:ROUTINGKEY}.log"
filePattern="logs/${date:yyyy-MM}/${ctx:ROUTINGKEY}-special-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout>
<pattern>%d{ISO8601} [%t] %p %c{3} - %m%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="6"
modulate="true" />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>
</Route>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Root level="info">
<!--<AppenderRef ref="Console"/> -->
<AppenderRef ref="Console" />
<AppenderRef ref="AppMain" />
</Root>
<Logger name="ServerRouting" level="all" additivity="false">
<!-- <AppenderRef ref="Console"/> -->
<AppenderRef ref="RoutingAppender" />
</Logger>
</Loggers>
</Configuration>
运行 上面的 Main
class 和 class 路径上的 log4j2.xml 生成 5 个日志文件 - 每个服务器一个,"main" 日志 - 每个服务器日志仅包含该服务器生成的日志。主日志为空,因为没有事件路由到那里。
希望对您有所帮助!
很抱歉提出这样一个常见问题,但是在应用这些解决方案后我无法解决我的问题。
所以基本上,我已经创建了一个网络,它允许我分别在它们自己的单独线程上执行不同的服务器。现在问题是它除了日志记录外工作正常。
What I want to achieve: I want to have separate log file per server.. based on the id of that server, for example main.log , server1.log , server2.log , server3.log , server4.log , etc...
目前发生了什么? 我尝试过的两种主要方法:-
尝试了选项 1:- Log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} %l - %msg%n"/>
</Console>
<File name="AppMain" filename="logs/main.log" append="false">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} %l - %msg%n"/>
</File>
<Routing name="RoutingAppender">
<Routes pattern="$${sys:logFilename}">
<Route>
<File name="Rolling-${sys:logFilename}" fileName="logs/${sys:logFilename}.log" append="false">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} %l - %msg%n"/>
</File>
</Route>
<!-- By having this set to ${ctx:logFileName} it will match when filename
is not set in the context -->
<Route ref="Console" key="${sys:logFilename}"/>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Root level="info">
<!--<AppenderRef ref="Console"/>-->
<AppenderRef ref="Console"/>
<AppenderRef ref="AppMain"/>
</Root>
<Logger name="ServerRouting" level="all" additivity="false">
<!-- <AppenderRef ref="Console"/>-->
<AppenderRef ref="RoutingAppender"/>
</Logger>
</Loggers>
</Configuration>
Server.java:-
public class Server {
private static Logger logger;
private long id;
private SomeClass someClass;
public Server(long id, SomeClass someClass) {
this.id=id;
this.someClass=someClass;
System.setProperty("logFilename", "server"+id);
logger = LogManager.getLogger(Constants.DYNAMIC_SERVERS);
this.someClass.setLogger(logger);
}
public void bindSockets(String servername, int port) throws IOException { /*Some functionality*/}
public void start() throws IOException { /*Some functionality*/}
}
Constants.java
public class Constants {
static {
System.setProperty("log4j.configurationFile", "log4j2.xml");
}
public static String APP_NAME = "AppMain";
public static String DYNAMIC_SERVERS = "ServerRouting";
}
使用这种方法 - 当我启动 4 个服务器时,我得到:
main.log , server2.log , server3.log , server4.log However the internal entries are all mixed up , and no file for server1 (i.e. server1.log) is created
尝试了选项 2:- Log4j2.xml 我替换了早期日志中的 Routes 块
<Routes pattern="$${ctx:ROUTINGKEY}">
<!-- This route is chosen if ThreadContext has value 'special' for key ROUTINGKEY. -->
<Route>
<RollingFile name="Rolling-${ctx:ROUTINGKEY}" fileName="logs/${ctx:ROUTINGKEY}.log"
filePattern="./logs/${date:yyyy-MM}/${ctx:ROUTINGKEY}-special-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout>
<pattern>%d{ISO8601} [%t] %p %c{3} - %m%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="6" modulate="true"/>
<SizeBasedTriggeringPolicy size="10 MB"/>
</Policies>
</RollingFile>
</Route>
</Routes>
Server.java:- 我在这里更改的是,我没有使用 System.setProperty(),而是使用 ThreadContext.put(),将日志文件名发送到 log4j2
public class Server {
private static Logger logger;
private long id;
private SomeClass someClass;
public Server(long id, SomeClass someClass) {
this.id=id;
this.someClass=someClass;
ThreadContext.put("ROUTINGKEY", "server"+id);
logger = LogManager.getLogger(Constants.DYNAMIC_SERVERS);
this.someClass.setLogger(logger);
}
public void bindSockets(String servername, int port) throws IOException { /*Some functionality*/}
public void start() throws IOException { /*Some functionality*/}
}
使用这种方法 - 当我启动 4 个服务器时,我得到:只有这两个文件
main.log , ${ctx:ROUTINGKEY}.log Instead of 4 , as mentioned in beginning. Where, all the internal entries for all servers have been added to single file i.e. ${ctx:ROUTINGKEY}.log
结论 谁能告诉我我做错了什么?这将是一个巨大的帮助。 显然欢迎新的建议,如果我的问题有歧义,请告诉我。
我认为有两个问题。
- 您在
Server
class 中将logger
声明为static
,因此在该 class 的所有实例之间共享记录器。 LogManager.getLogger
方法不是线程安全的,以这种方式使用时必须同步。
下面是一些适用于我的示例代码和配置:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
public class Server {
private Logger logger;
private long id;
public Server(long id, Object lock) {
this.id=id;
ThreadContext.put("ROUTINGKEY", "server"+id);
synchronized(lock){
logger = LogManager.getLogger(Constants.DYNAMIC_SERVERS);
}
}
public void doStuff(){
logger.info("Server "+ id +" did some stuff");
}
}
A class 在单独的线程中启动 4 个服务器:
public class Main {
public static void main(String[] args) {
final Object lock = new Object();
Thread t1 = new Thread(new Runnable(){
public void run(){
Server s = new Server(1,lock);
s.doStuff();
}
});
Thread t2 = new Thread(new Runnable(){
public void run(){
Server s = new Server(2,lock);
s.doStuff();
}
});
Thread t3 = new Thread(new Runnable(){
public void run(){
Server s = new Server(3,lock);
s.doStuff();
}
});
Thread t4 = new Thread(new Runnable(){
public void run(){
Server s = new Server(4,lock);
s.doStuff();
}
});
t1.start();
t2.start();
t3.start();
t4.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
为了完整起见,常量class:
public class Constants {
public static String APP_NAME = "AppMain";
public static String DYNAMIC_SERVERS = "ServerRouting";
}
和log4j2.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} %l - %msg%n" />
</Console>
<File name="AppMain" filename="logs/main.log" append="false">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5level %logger{36} %l - %msg%n" />
</File>
<Routing name="RoutingAppender">
<Routes pattern="$${ctx:ROUTINGKEY}">
<!-- This route is chosen if ThreadContext has value 'special' for key
ROUTINGKEY. -->
<Route>
<RollingFile name="Rolling-${ctx:ROUTINGKEY}" fileName="logs/${ctx:ROUTINGKEY}.log"
filePattern="logs/${date:yyyy-MM}/${ctx:ROUTINGKEY}-special-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout>
<pattern>%d{ISO8601} [%t] %p %c{3} - %m%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="6"
modulate="true" />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>
</Route>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Root level="info">
<!--<AppenderRef ref="Console"/> -->
<AppenderRef ref="Console" />
<AppenderRef ref="AppMain" />
</Root>
<Logger name="ServerRouting" level="all" additivity="false">
<!-- <AppenderRef ref="Console"/> -->
<AppenderRef ref="RoutingAppender" />
</Logger>
</Loggers>
</Configuration>
运行 上面的 Main
class 和 class 路径上的 log4j2.xml 生成 5 个日志文件 - 每个服务器一个,"main" 日志 - 每个服务器日志仅包含该服务器生成的日志。主日志为空,因为没有事件路由到那里。
希望对您有所帮助!