【问题标题】:Log4J2 - assigning user specific file appender filename at runtimeLog4J2 - 在运行时分配用户特定的文件附加文件名
【发布时间】:2014-04-25 21:57:12
【问题描述】:

我想使用 LogJ4 2 中的 XML 配置文件登录到我的项目文件夹中的某个文件。这是一个共享项目,所以我不能只在所需位置的完整路径中编码。 该路径必须根据编译程序的机器是动态的,以便始终正确生成日志文件。

我在这里阅读了多种方法,但没有一种对我有用。

这是我的整体结构: 源:log.class 配置文件夹:log4j2.xml logs:我想把日志文件写在这里

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”为空。我怎样才能绕过这个?

我在这里缺少什么?我真的很感激任何帮助。

谢谢, 亚历克斯

【问题讨论】:

    标签: xml eclipse logging log4j log4j2


    【解决方案1】:

    虽然这个问题是很久以前提出的,但我现在才正在阅读它,并且我有一个有效的解决方案。似乎问题在于定义系统属性的时间。您在设置系统属性之前调用 log4j2 API,方法是在类的顶部执行以下操作:

    private static Logger logger = LogManager.getLogger(Log.class.getName());
    LoggerContext ctx = (LoggerContext)LogManager.getContext(false);
    

    如果您在设置系统属性之前(在调用构造函数之前 - 可能在静态方法中)还调用 logger 上的方法,那么您当然会看到该属性为空。

    解决方案是确保在开始使用 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>
    

    作为处于代码状态的 cmets,当它运行时,静态块将首先执行并在其他任何事情发生之前设置系统属性。即使你从其他类调用这个类的静态方法,静态块仍然首先执行,因为它在类本身加载时运行。

    【讨论】:

      猜你喜欢
      • 2013-01-29
      • 1970-01-01
      • 2021-07-05
      • 2013-09-25
      • 1970-01-01
      • 2018-11-06
      • 1970-01-01
      • 2019-07-27
      • 2015-04-18
      相关资源
      最近更新 更多