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

Java 使用可执行JAR时指定Log4j2配置文件,java,logging,executable-jar,log4j2,Java,Logging,Executable Jar,Log4j2,在使用可执行JAR文件时,我在指定Log4j2配置文件位置时遇到问题。如果我分离所有JAR,效果很好,但是当我尝试将它们合并到一个可执行JAR文件中时,由于某种原因,log4j2.xml文件没有从命令行中获取 我尝试了以下两种指定位置的方法: java -Djava.libary.path=..\bin -cp ..\config -jar MyApplication.jar java -Djava.libary.path=..\bin -Dlog4j.configurationFile=..

在使用可执行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.JAR
log4j-api-2.1.JAR
JAR,但在其内部和
MANIFEST
文件的类路径中,仍然存在问题。我编写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的
清单中指定的类路径将覆盖命令行中指定的任何类路径


感谢您的回复,他们肯定帮助我找到了正确的方法来找出我的错误。

Java文档中没有很好/明显地解释的一点是,如果您使用的是可执行Jar,它将只使用清单文件中指定的类路径。它不会侦听
-cp
or
——类路径
参数

-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

对于可能有此问题的其他人

  • 确保-Dlog4j.configurationFile选项出现在“-jar”之前而不是之后。可能看起来很明显,但曾经看到过这个错误
  • 尝试将文件位置视为url,看看是否有效。例如,带有%20等的转义空间也使用'file://path,将反斜杠替换为正斜杠
  • Windows路径可以写成文件:://c:/path/to/log4j2.xml
  • 因此,如果在
    C:\program Files\exampleApp
    中的exampleApp的程序文件夹中有一个log4j2.xml,那么

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

    …应该可以工作

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

    System.setProperty("log4j.configurationFile", "resources/log4j2.xml");
    
    System.setProperty("logFilename", "logs/myApp.log");
    
    我有一个包,因此我需要指定“资源”文件夹的路径(在Eclipse中的“src”文件夹中):

    注意,我的路径中没有包含“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>
    
    为了使这两个dynamic 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是:

  • log4j-api-2.6.2.jar

  • log4j-core-2.6.2.jar


  • 我在Log4j2的2.8版中遇到了这个问题。
    当相应的Log4j2 jar被Log4j2的版本2.6替换时,这种情况就消失了。

    因此您的配置文件不在应用程序jar中?不,我认为最好将配置文件保留在jar之外,以便用户可以根据需要更改配置。我需要将该文件包含在jar中吗?如何创建您的单个jar?log4j2核心jar包含必须包含的配置文件,否则log4j2将无法正常工作。请添加您从log4j收到的输出。我假设它是默认状态记录器,抱怨没有配置文件-但假设soYes是在Windows上运行的,这可能是一个错误。我99.9%确信这一点我从正确的目录运行它。我已经检查了四次,似乎没有发现任何问题。根据我的建议,这是最好的解决方案
    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());  
     }