使用可执行JAR时指定Log4j2配置文件

26

当我使用可执行JAR文件时,我在指定Log4j2配置文件的位置方面遇到了困难。如果我将所有的JAR文件分离开来,则可以正常工作,但是当我尝试将它们合并成一个可执行的JAR文件时,由于某种原因,log4j2.xml文件未被从命令行中捕获。

我已经尝试过以下两种指定位置的方法:

java -Djava.libary.path=..\bin -cp ..\config -jar MyApplication.jar

java -Djava.libary.path=..\bin -Dlog4j.configurationFile=..\config\log4j2.xml -jar MyApplication.jar

这两个都不起作用。我还尝试将包含配置文件的目录添加到JAR清单文件中的类路径中:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.2
Created-By: 1.7.0_21-b11 (Oracle Corporation)
Main-Class: com.abc.MyApplication
Class-Path: ../config/

我也没有用这种方法取得成功。你有什么想法,我可能做错了什么吗?

提前感谢任何帮助!


编辑

啊,我想我误解了问题。最初,这是我在命令行输出中看到的错误:

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

但在我修改东西的某个时候,错误消息不知不觉地变成了这个:

ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...
所以我发现,尽管我正在构建的可执行JAR包中已经包含了log4j-core-2.1.jarlog4j-api-2.1.jar JAR文件,并在MANIFEST文件的类路径中设置了这些JAR包,但还是出现了问题。我编写Ant文件将库合并到正在创建的单个JAR中的方式成功地复制了目录和类文件,但出于某种原因未能复制其他类型的文件,这些文件显然也是必需的(例如Log4j-config.xsd、Log4j-events.dtd等)。
为了解决这个问题,我改变了Ant构建文件中合并JAR的方式:
<jar destfile="${dist}/${jarName}" basedir="${classes}" 
    excludes=".svn">

    <!-- Merge this JAR with all the JARs in the lib directory, so that
    we are only creating one distribution JAR that includes all the
    libraries that you need. -->
    <fileset dir="${classes}" includes="**/*.class" />
    <zipgroupfileset dir="${lib}" includes="**/*.jar" />

    <!-- Specify the manifest file of the JAR -->
    <manifest>
        <attribute name="Main-Class" value="com.abc.MyApplication"/>
        <attribute name="Class-Path" value=". ${manifest.classpath}"/>
    </manifest>
</jar>

这样解决了问题,并将所有文件从JAR复制到了我新创建的JAR中。

一旦解决了这个问题,我发布的上述第二条命令就可以用来指定配置文件的位置。(如@ rewolf 所指出的那样,在JAR MANIFEST 中指定的类路径会覆盖在命令行上指定的任何类路径)。

感谢您的回复,它们肯定帮助我找到了解决错误的正确途径。


那么你的配置文件不在应用程序的JAR包里? - rewolf
不需要,我认为最好的做法是将配置文件放在JAR之外,这样用户可以根据需要更改配置。我需要将文件包含在JAR中吗? - Steph
1
你如何创建单个jar文件?log4j2-core jar包含必须包含的配置文件,否则log4j2将无法正常工作。 - Remko Popma
1
请添加您从log4j接收到的输出。我原以为这是默认状态记录器抱怨没有配置文件 - 但假设如此可能是一个错误。 - rewolf
4个回答

42

Java文档中没有很好地解释,如果您使用可执行的Jar文件,则仅将Manifest文件中指定的Class-Path用作路径,它不会侦听-cp--classpath参数。

-Dlog4j.configurationFile=directory/file.xml

这应该绝对有效。鉴于您的斜杠方向,我假设您正在Windows上运行。 您确定从正确的相对目录运行它了吗?

更新

我在Windows上尝试了一下,没有任何问题。 我使用了以下清单:

Manifest-Version: 1.0
Built-By: andrew.flower
Build-Jdk: 1.7.0_67
Class-Path: lib/log4j-api-2.1.jar lib/log4j-core-2.1.jar
Created-By: Apache Maven 3.2.3
Main-Class: com.andrew_flower.test.Log4jTest
Archiver-Version: Plexus Archiver

Log4j2的jar包位于lib/目录中,而log4j2.xml则位于conf/目录中。我执行了以下命令,成功找到了配置文件。

java -Dlog4j.configurationFile=conf\log4j2.xml -jar log4j2test1-1.0-SNAPSHOT.jar

是的,我正在运行Windows操作系统。我有99.9%的把握我正在从正确的目录中运行它。我已经进行了四重检查,但似乎找不到任何问题。 - Steph
在 Windows 上的 GitBash 上运行良好。 - Java Main

9

我通过在我的Java代码中包含以下内容解决了在Eclipse创建的可运行Jar中指定log4j2配置位置的问题:

System.setProperty("log4j.configurationFile", "resources/log4j2.xml");

我有一个包,因此需要指定我的“资源”文件夹的路径(在Eclipse中的“src”文件夹中):

System.setProperty("log4j.configurationFile", "com/company/app/resources/log4j2.xml");

请注意,我的路径中没有包含"src",我认为需要的是"bin"文件夹中的路径:例如,在我的情况下是"com/company/app/resources/log4j2.xml"

我的配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration> 

<appenders>

<Console name="Console" target="SYSTEM_OUT">
  <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level - %msg%n"/>  
</Console>

<RollingFile 
        name="RollingFile" 
        fileName="${sys:logFilename}"
        filePattern="${sys:logFilename}-%d{yyyy-MM-dd}-%i.log"> 
  <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level - %msg%n"/>      
  <Policies>
    <SizeBasedTriggeringPolicy size="1 MB"/>
  </Policies>  
  <DefaultRolloverStrategy max="10"/> 
</RollingFile>

</appenders> 


<loggers>     
 <root level="all">
  <appender-ref ref="Console"/>      
  <appender-ref ref="RollingFile"/> 
 </root>    
</loggers>

请注意,我通过在Java代码中包含"${sys:logFilename}"来动态分配滚动日志文件的路径和名称。

System.setProperty("logFilename", "logs/myApp.log");

为了让这两个动态的System.setProperty分配起作用,它们需要在“getLogger”语句之前执行,因此我的Java代码如下:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class MyTestLoggingClass {

 public static Logger logger = null;

 ...................
 setUpLogging();
 ...............

 public static void setUpLogging() {
    System.setProperty("log4j.configurationFile",  "com/company/app/resources/log4j2.xml");
    System.setProperty("logFilename", "logs/myApp.log");

    logger = LogManager.getLogger(Logger.class.getName());  
 }

在我的类开始处声明“logger”(但在我的2个System.setProperty语句之前没有调用“getLogger”)使我能够在其他方法中引用“logger”。我虽然必须对其进行初始化,但是我选择了“null”,然后稍后使用“getLogger”语句更新它-鉴于此,我不能将其设置为“final”(只能分配一次),但可以将其设置为静态-一个常量类变量。

注意,我在构建路径中包含的2个log4j2 jar文件是:

  1. log4j-api-2.6.2.jar

  2. log4j-core-2.6.2.jar


我认为最佳解决方案是: - Jack'

8

对于其他可能遇到此问题的人...

  1. 确保你的-Dlog4j.configurationFile选项在'-jar'之前而不是之后,这可能显而易见,但我曾经看到过这个错误。
  2. 尝试将文件位置视为url并查看是否有效。 即使用%20等转义空格。同时使用'file://路径',将反斜杠替换为正斜杠。
  3. Windows路径可以写成file://c:/path/to/log4j2.xml

因此,如果你的程序文件夹中有一个log4j2.xml,例如在C:\Program Files\ExampleApp中,那么...

java.exe -Dlog4j.configurationFile=file://c:/program%20files/exampleapp/log4j2.xml -jar exampleApp.jar ... 

应该可以正常工作


在Windows上,Git Bash运行良好。 - Java Main

0

我在使用Log4j2的2.8版本时遇到了问题。 当将相应的Log4j2 jars替换为2.6版本时,问题消失了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接