我想使用LogJ4 2中的XML配置文件来登录我的projects文件夹中的某个文件。这是一个共享项目,所以我不能只编写到所需位置的完整路径。 根据编译程序的机器,路径必须是动态的,以便始终正确生成日志文件。
我已经在这里阅读了多种方法,但它们都没有为我工作。
这是我的整体结构: src:log.class config文件夹:log4j2.xml logs:Id就像要写在这里的日志文件
XML源代码如下所示:
<properties>
<property name="logFilePosition">${sys:logFilename}</property>
</properties>
和
<File name="OutputFile" fileName="${logFilePosition}" immediateFlush="true">
<PatternLayout>
<Pattern>%d{HH:mm:ss} %m; %n</Pattern>
</PatternLayout>
</File>
也
<Root level="trace">
<AppenderRef ref="Console" level="trace" />
<AppenderRef ref="OutputFile" level="trace" />
</Root>
我也尝试使用fileName="${sys:logFilename}"
,但也无效。
此XML不完整,但会显示相关部分。
我的Log类看起来像这样:
private static Logger logger = LogManager.getLogger(Log.class.getName());
LoggerContext ctx = (LoggerContext)LogManager.getContext(false);
// Returns current location based on individual location
private static URL location = Log.class.getProtectionDomain().getCodeSource().getLocation();
private static String final_location = location.toString().substring(6, location.toString().length());
Log(){
// Sets system property required for XML configuration file in order to reference desired output location
// of log file by the use of "logFilename"
System.setProperty("logFilename", final_location+"logs/mylog.log");
//LoggerContext ctx = (LoggerContext)LogManager.getContext(false);
ctx.reconfigure();
如果我只做System.out.println(final_location+"logs/mylog.log");
,则会显示正确的路径。如果我只是复制此路径并将其直接插入XML文件,则会生成一个日志文件。
问题似乎是在Log()构造函数之外,就像在此类的其他方法中一样,属性“logFilename”为null。我怎么能绕过这个?
我在这里缺少什么?我非常感谢任何帮助。
谢谢, 亚历
答案 0 :(得分:0)
虽然很久以前就提出这个问题,但我现在正在阅读它,而且我有一个有效的解决方案。似乎问题在于定义系统属性的时间。您在设置系统属性之前通过在类的顶部执行以下操作来调用log4j2 API:
private static Logger logger = LogManager.getLogger(Log.class.getName());
LoggerContext ctx = (LoggerContext)LogManager.getContext(false);
如果您在设置系统属性之前调用logger
上的方法(在调用构造函数之前 - 可能在静态方法中),那么您当然会看到该属性为null。
解决方案是确保在开始使用log4j之前定义系统属性。这是一个有效的例子:
package example;
import java.net.URL;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
public class Log4j2JvmProp {
//This static block will run before anything else and ensure that the system property is
// set before log4j is initialized or used.
static{
URL location = Log4j2JvmProp.class.getProtectionDomain().getCodeSource().getLocation();
String final_location = location.toString().substring(6, location.toString().length());
System.setProperty("logFilename", final_location+"logs/mylog.log");
}
private static Logger logger = LogManager.getLogger();
static LoggerContext ctx = (LoggerContext)LogManager.getContext(false);
public static void main(String[] args) {
logger.info("Hello world!");
}
}
这是log4j2.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<File name="logFile" fileName="${sys:logFilename}" immediateFlush="false"
append="true">
<PatternLayout
pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="logFile" />
</Root>
</Loggers>
</Configuration>
作为代码状态中的注释,当运行此注释时,静态块将首先执行并在发生任何其他事件之前设置系统属性。即使你从其他类调用此类的静态方法,静态块仍然首先执行,因为它在类本身被加载时运行。