Log4j, 상대 경로를 사용하도록 웹앱 구성


80

Win 또는 Linux 시스템에 배포해야하는 Java 웹 응용 프로그램이 있습니다. 이제 로깅을 위해 log4j를 추가하고 모든 배포에서 파일 경로를 변경하고 싶지 않기 때문에 로그 파일의 상대 경로를 사용하고 싶습니다. 컨테이너는 Tomcat 일 가능성이 높지만 반드시 그런 것은 아닙니다.

이를 수행하는 가장 좋은 방법은 무엇입니까?


3
이것은 질문의 절반에 불과합니다. 로그 파일에 대한 동적 경로를 갖는 것은 좋지만 구성 파일 자체는 어떻습니까? 동적 인 로그 파일 위치 만 있다면 이것이 배포되는 모든 위치에서 동일한 로그 수준을 갖게 될 것이며, 이것이 바람직하다고 생각하지 않습니다. 내 개발 환경이 DEBUG에 로그인하고 INFO / WARN에서 prod 할 수 있도록 구성을 동적으로 지정하는 가장 좋은 방법을 알고 싶습니다. 어떻게 생각해?
루카스

답변:


100

Tomcat은 catalina.home 시스템 속성을 설정합니다. log4j 속성 파일에서 이것을 사용할 수 있습니다. 이 같은:

log4j.rootCategory=DEBUG,errorfile

log4j.appender.errorfile.File=${catalina.home}/logs/LogFilename.log

Debian (Ubuntu 포함)에서는 ${catalina.home}/ var / log / tomcat6에 대한 링크가없는 / usr / share / tomcat6을 가리 키므로 작동하지 않습니다. 여기에서 ${catalina.base}.

다른 컨테이너를 사용하는 경우 유사한 시스템 속성을 찾거나 직접 정의하십시오. 시스템 속성 설정은 플랫폼 및 컨테이너에 따라 다릅니다. 그러나 Linux / Unix의 Tomcat의 경우 CATALINA_HOME / bin 디렉토리에 setenv.sh를 만듭니다. 다음이 포함됩니다.

export JAVA_OPTS="-Dcustom.logging.root=/var/log/webapps"

그러면 log4j.properties는 다음과 같습니다.

log4j.rootCategory=DEBUG,errorfile

log4j.appender.errorfile.File=${custom.logging.root}/LogFilename.log

2
솔직히이 접근 방식이 내 대답에서 설명 한 Listener를 사용하는 것보다 어떤 이점이 있는지 모르겠습니다. 컨테이너가 무엇인지 상관하지 않고 어디에서 배포하든 상관없이 작동하지만 귀하의 접근 방식에서는 환경을 변경하면 값을 변경합니다.
Iker Jimenez

4
두 솔루션 모두 시스템 속성을 사용하고 있지만 다르게 설정하는 것입니다. 유연성과 단순성에 달려 있습니다. 애플리케이션이 실행되는 모든 Tomcat 서버를 관리하므로 유연성이 마음에 듭니다. 타사 사용을 위해 전쟁을 배포하는 경우 단순성이 의미가 있습니다
Steve K

54

마침내 이런 식으로 해냈습니다.

다음을 수행하는 ServletContextListener를 추가했습니다.

public void contextInitialized(ServletContextEvent event) {
    ServletContext context = event.getServletContext();
    System.setProperty("rootPath", context.getRealPath("/"));
}

그런 다음 log4j.properties 파일에서 :

log4j.appender.file.File=${rootPath}WEB-INF/logs/MyLog.log

이렇게하면 "rootPath"시스템 속성이 설정되기 전에 사용하지 않는 한 Log4j는 올바른 폴더에 기록합니다. 즉, ServletContextListener 자체에서는 사용할 수 없지만 앱의 다른 곳에서는 사용할 수 있어야합니다.

컨테이너 별 시스템 속성에 의존하지 않고 OS 별 경로 문제의 영향을받지 않으므로 모든 웹 컨테이너 및 OS에서 작동해야합니다. Tomcat 및 Orion 웹 컨테이너와 Windows 및 Linux에서 테스트되었으며 지금까지 잘 작동합니다.

어떻게 생각해?


4
이것은 좋은 생각이지만, log4j 코드가 초기화되기 전에 항상 설정 / 사용 가능하므로 catalina.home을 사용하는 것이 더 안전 할 수 있다고 생각합니다.
matt b

6
Tomcat 만 사용하는 경우에는 해당되지만 내 요구 사항은 구성이 0 인 모든 컨테이너에서 작동해야한다는 것입니다. 내 접근 방식은 이것을 충족하며 아무도 이에 대한 더 나은 접근 방식을 제안하지 않았습니다.
Iker Jimenez

2
이 솔루션은 Servlet을 사용하는 웹 애플리케이션에서 작동 할 수 있지만 Steve K의 솔루션 ( stackoverflow.com/questions/216781/… )은 Log4j를 사용하는 모든 애플리케이션에서 작동합니다.
Derek Mahar

2
상대 경로를 기반으로하는 Spencer K의 솔루션은 기본 디렉토리를 예측 가능한 경로로 설정했다고 가정하고 Log4j를 사용하는 모든 응용 프로그램에서 작동합니다.
Derek Mahar

12
이 솔루션은 단일 웹 애플리케이션이이를 사용하도록 구성된 경우에만 작동합니다. 시스템 속성이 tomcat에 전역 적이므로 두 번째 앱을 시작하면 첫 번째 웹앱이 설정 한 값을 덮어 씁니다. 각 웹앱에 고유 한 속성 이름을 부여 할 수 있지만 그렇게하려는 경우 $ {catalina.home}을 사용하고 log4j.properties 파일에 경로의 고유 한 부분을 추가 할 수 있습니다. .
3urdoch

14

Spring을 사용하면 다음을 수행 할 수 있습니다.

1) "/WEB-INF/classes/log4j-myapp.properties"와 같은 log4j 구성 파일을 만듭니다. 이름을 "log4j.properties"로 지정하지 마십시오.

예:

log4j.rootLogger=ERROR, stdout, rollingFile

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n

log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.File=${myWebapp-instance-root}/WEB-INF/logs/application.log
log4j.appender.rollingFile.MaxFileSize=512KB
log4j.appender.rollingFile.MaxBackupIndex=10
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.rollingFile.Encoding=UTF-8

나중에 (3)에서 "myWebapp-instance-root"를 정의 할 것입니다.

2) web.xml에서 구성 위치를 지정하십시오.

<context-param>
  <param-name>log4jConfigLocation</param-name>
  <param-value>/WEB-INF/classes/log4j-myapp.properties</param-value>
</context-param>

3) 웹앱의 루트에 고유 한 변수 이름을 지정 하십시오. 예 : "myWebapp-instance-root"

<context-param>
  <param-name>webAppRootKey</param-name>
  <param-value>myWebapp-instance-root</param-value>
</context-param>

4) Log4jConfigListener 추가 :

<listener>
  <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

다른 이름을 선택하는 경우 log4j-myapp.properties에서도 변경해야합니다.

내 기사를 참조하십시오 (이탈리아어 만 ...하지만 이해할 수 있어야 함) : http://www.megadix.it/content/configurare-path-relativi-log4j-utilizzando-spring

업데이트 (2009/08/01) 내 기사를 영어로 번역했습니다 : http://www.megadix.it/node/136


6

Iker의 솔루션 에 대한 의견입니다 .

ServletContext문제에 대한 좋은 해결책입니다. 하지만 유지 관리에는 좋지 않다고 생각합니다. 대부분의 경우 로그 파일은 오랫동안 저장해야합니다.

이후 ServletContext배포 된 파일에서 파일을 만들어 서버가 재배치 될 때, 그것은 제거됩니다. 내 제안은 자식 폴더 대신 rootPath의 부모 폴더를 사용하는 것입니다.


5

FileAppender의 경로 속성에 루트 디렉터리를 지정하지 않으면 log4j가 응용 프로그램 루트 디렉터리를 사용하지 않습니까? 따라서 다음을 사용할 수 있어야합니다.

log4j.appender.file.File = logs / MyLog.log

Java 웹 개발을 한 지 오래되었지만 가장 직관적 인 것 같고 $ {catalina.home} / logs 디렉토리에 쓰는 다른 이름의 로그와 충돌하지 않습니다.


4
내가 본 것에서 절대 경로를 제공하지 않으면 사용자의 홈 디렉토리 또는 컨테이너의 홈 디렉토리를 사용할 수 있습니다.
Iker Jimenez

1
@Iker : 컨테이너 또는 애플리케이션 구성에서 애플리케이션 루트 디렉토리를 명시 적으로 설정할 수없는 이유는 무엇입니까? 개발 및 프로덕션에서 한 번 수행하면 상대 경로를 안정적으로 사용할 수 있습니다. 루트 디렉터리가 올바르게 설정되어 있다고 가정하면 상대 경로가 가장 이식 가능한 (재 찾기 가능) 솔루션입니다.
Derek Mahar

1
나는 이것이 오래된 게시물이라는 것을 알고 있지만 다른 사람들을 위해 이것에 대해 메모하고 싶었습니다. tomcat의 경우 응용 프로그램 루트 디렉토리가 명시 적으로 설정되지 않은 경우 Tomcat을 시작한 디렉토리가 기본값이라고 생각합니다.
Geren White

2

https://stackoverflow.com/a/218037/2279200 에 대한 추가 의견으로 , 웹 앱이 다른 ServletContextListener를 암시 적으로 시작하여 이전에 호출 될 수 있고 이미 log4j를 사용하려고 시도하는 경우 중단 될 수 있습니다. log4j 구성은 로그 루트 디렉토리를 결정하는 속성이 설정되기 전에 이미 읽고 구문 분석됩니다 => 로그 파일은 현재 디렉토리 (톰캣을 시작할 때 현재 디렉토리) 아래 어딘가에 나타납니다.

이 문제에 대한 해결책은 다음과 같을뿐입니다.-log4j.properties (또는 logj4.xml) 파일의 이름을 log4j가 자동으로 읽지 않는 이름으로 바꿉니다. -컨텍스트 필터에서 속성을 설정 한 후 DOM / PropertyConfigurator 도우미 클래스를 호출하여 log4j-. {xml, properties}를 읽었는지 확인합니다.-log4j 구성 재설정 (IIRC에는이를 수행하는 방법이 있습니다)

이것은 약간의 무자비한 힘이지만, 그것이 방수로 만드는 유일한 방법입니다.


1

Maven을 사용하는 경우 훌륭한 솔루션이 있습니다.

  1. 다음 행을 포함하도록 pom.xml 파일을 편집하십시오.

    <profiles>
        <profile>
            <id>linux</id>
            <activation>
                <os>
                    <family>unix</family>
                </os>
            </activation>
            <properties>
                <logDirectory>/var/log/tomcat6</logDirectory>
            </properties>
        </profile>
        <profile>
            <id>windows</id>
            <activation>
                <os>
                    <family>windows</family>
                </os>
            </activation>
            <properties>
                <logDirectory>${catalina.home}/logs</logDirectory>
            </properties>
        </profile>
    </profiles>
    

    여기서 logDirectoryOS 제품군에 대한 속성을 특별히 정의 합니다.

  2. 파일에 이미 정의 된 logDirectory속성 사용 log4j.properties:

    log4j.appender.FILE=org.apache.log4j.RollingFileAppender
    log4j.appender.FILE.File=${logDirectory}/mylog.log
    log4j.appender.FILE.MaxFileSize=30MB
    log4j.appender.FILE.MaxBackupIndex=10
    log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
    log4j.appender.FILE.layout.ConversionPattern=%d{ISO8601} [%x] %-5p [%t] [%c{1}] %m%n
    
  3. 그게 다야!

추신 : 나는 이것이 Ant를 사용하여 달성 될 수 있다고 확신하지만 불행히도 그것에 대한 충분한 경험이 없습니다.


1

내 제안은 로그 파일이 항상 웹앱의 루트 컨텍스트 위에 기록되어야한다는 것입니다. 따라서 웹앱을 재배포하는 경우 기존 로그 파일을 재정의하고 싶지 않습니다.


1

내 솔루션 이케르 네즈의 유사합니다 솔루션 , 대신에 사용하는 System.setProperty(...)I 사용을 org.apache.log4j.PropertyConfigurator.configure(Properties). 이를 위해 자체 구성을 찾을 수 없도록 log4j가 필요하며 수동으로로드합니다 (둘 다 Wolfgang Liebich의 답변에 설명되어 있음 ).

부두와 톰캣, 독립형 또는 IDE에서 실행,이 작품은, 제로 구성이 필요없이, 자신의 폴더에 각 응용 프로그램의 로그를 넣지 수 있습니다 방법 용기 내부에 많은 애플 리케이션 (인 문제System기반 솔루션). 이런 식으로 웹 앱 내부 어디에나 log4j 구성 파일을 넣을 수 있습니다 (예 : 하나의 프로젝트에서 모든 구성 파일이 내부에 있음 WEB-INF/).

세부:

  1. log4j-no-autoload.properties클래스 경로 의 파일에 속성이 있습니다 (예 : Maven 프로젝트에서는 원래 src/main/resources,에 패키지 됨 WEB-INF/classes).
  2. 다음과 같이 구성된 파일 어 펜더가 있습니다.

    log4j.appender.MyAppFileAppender = org.apache.log4j.FileAppender
    log4j.appender.MyAppFileAppender.file = ${webAppRoot}/WEB-INF/logs/my-app.log
    ...
    
  3. 그리고 다음과 같은 컨텍스트 리스너가 있습니다 (Java 7의 "try-with-resource"구문으로 훨씬 짧아짐).

    @WebListener
    public class ContextListener implements ServletContextListener {
        @Override
        public void contextInitialized(final ServletContextEvent event) {
            Properties props = new Properties();
            InputStream strm =
                ContextListener.class.getClassLoader()
                    .getResourceAsStream("log4j-no-autoload.properties");
            try {
                props.load(strm);
            } catch (IOException propsLoadIOE) {
                throw new Error("can't load logging config file", propsLoadIOE);
            } finally {
                try {
                    strm.close();
                } catch (IOException configCloseIOE) {
                    throw new Error("error closing logging config file", configCloseIOE);
                }
            }
            props.put("webAppRoot", event.getServletContext().getRealPath("/"));
            PropertyConfigurator.configure(props);
            // from now on, I can use LoggerFactory.getLogger(...)
        }
        ...
    }
    

1

작업 디렉토리를 사용하여 로그 파일에 대한 상대 경로를 지정할 수 있습니다 .

appender.file.fileName = ${sys:user.dir}/log/application.log

이것은 서블릿 컨테이너와 독립적이며 사용자 정의 변수를 시스템 환경에 전달할 필요가 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.