Log4j, настройка веб-приложения для использования относительного пути

У меня есть java webapp, который должен быть развернут на машинах Win или Linux. Теперь я хочу добавить log4j для ведения журнала, и я бы хотел использовать относительный путь для файла журнала, поскольку я не хочу изменять путь к файлу при каждом развертывании. Контейнер, скорее всего, будет Tomcat, но не обязательно.

Какой лучший способ сделать это?

Ответ 1

Я, наконец, сделал это таким образом.

Добавлен 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

Таким образом, Log4j будет записываться в нужную папку до тех пор, пока вы не будете использовать его до того, как будет установлено системное свойство "rootPath". Это означает, что вы не можете использовать его из самого ServletContextListener, но вы должны использовать его из любого места в приложении.

Он должен работать на каждом веб-контейнере и ОС, так как он не зависит от специфичного для контейнера системного свойства и не зависит от конкретных проблем, связанных с ОС. Протестировано с веб-контейнерами Tomcat и Orion, а также в Windows и Linux, и пока он работает нормально.

Как вы думаете?

Ответ 2

Tomcat устанавливает свойство catalina.home. Вы можете использовать это в своем файле свойств log4j. Что-то вроде этого:

log4j.rootCategory=DEBUG,errorfile

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

В Debian (включая Ubuntu) ${catalina.home} не будет работать, потому что это указывает на /usr/share/tomcat 6, у которого нет ссылки на /var/log/tomcat 6. Здесь просто используйте ${catalina.base}.

Если вы используете другой контейнер, попробуйте найти аналогичное системное свойство или определите свой собственный. Настройка системного свойства будет варьироваться в зависимости от платформы и контейнера. Но для Tomcat в Linux/Unix я бы создал setenv.sh в каталоге CATALINA_HOME/bin. Он будет содержать:

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

Тогда ваши log4j.properties будут:

log4j.rootCategory=DEBUG,errorfile

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

Ответ 3

Если вы используете Spring, вы можете:

1) создать файл конфигурации log4j, например. "/WEB-INF/classes/log4j-myapp.properties" Не называть его "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

Мы определим "myWebapp-instance-root" позже в точке (3)

2) Укажите расположение конфигурации в web.xml:

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

3) Укажите имя переменной уникальное для вашего корня webapp, например. "MyWebapp-экземпляр-корень"

<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

Ответ 4

Просто комментарий к решению Iker.

ServletContext - хорошее решение для вашей проблемы. Но я не думаю, что это хорошо для поддержания. Большие файлы журналов времени должны сохраняться в течение длительного времени.

Так как ServletContext делает файл под развернутым файлом, он будет удален при перераспределении сервера. Я предлагаю перейти с родительской папкой rootPath вместо дочерней.

Ответ 5

Не работает ли log4j корневой каталог приложения, если вы не указали корневую директорию в свойстве пути FileAppender? Поэтому вы должны просто использовать:

log4j.appender.file.File = журналы /MyLog.log

Прошло некоторое время с тех пор, как я сделал веб-разработку Java, но это кажется наиболее интуитивным, а также не сталкивается с другими, к сожалению, именами журналов, записываемыми в каталог ${catalina.home}/logs.

Ответ 6

Мое предложение - файл журнала должен всегда регистрироваться выше корневого контекста webApp, поэтому, если мы повторно развернем webApp, мы не хотим переопределять существующие файлы журналов.

Ответ 7

Если вы используете Maven, у меня есть отличное решение для вас:

  • Отредактируйте файл 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>
    

    Здесь вы определяете свойство logDirectory специально для семейства ОС.

  • Использовать уже определенное свойство 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
    
  • Что это!

P.S.: Я уверен, что этого можно достичь с помощью Ant, но, к сожалению, у меня недостаточно опыта.

Ответ 8

В качестве дополнительного комментария к fooobar.com/questions/73893/... - это может сломаться, если веб-приложение неявно запускает другие ServletContextListener, которые могут быть вызваны ранее и которые уже пытаются использовать log4j - в этом случае конфигурация log4j будет считана и проанализирована уже до того, как будет установлено свойство, определяющее корневой каталог журнала = > файлы журналов будут отображаться где-то ниже текущего каталога (текущий каталог при запуске tomcat).

Я мог только думать о следующем решении этой проблемы: - переименуйте файл log4j.properties(или logj4.xml) в то, что log4j не будет автоматически читать. - В вашем контекстном фильтре после установки свойства вызовите вспомогательный класс DOM/PropertyConfigurator, чтобы убедиться, что ваш log4j -. {Xml, properties} прочитан - Reset конфигурация log4j (IIRC - метод для этого)

Это немного грубая сила, но это единственный способ сделать ее водонепроницаемой.

Ответ 9

Мое решение похоже на решение Iker Jimenez , но вместо использования System.setProperty(...) я использую org.apache.log4j.PropertyConfigurator.configure(Properties). Для этого мне также нужно, чтобы log4j не смог самостоятельно найти свою конфигурацию, и я загружаю ее вручную (обе точки, описанные в Wolfgang Liebich answer).

Это работает для Jetty и Tomcat, автономно или работает от IDE, требует нулевой конфигурации, позволяет помещать журналы каждого приложения в их собственную папку, независимо от того, сколько приложений внутри контейнера (проблема с решением, основанным на System). Таким образом можно также поместить файл конфигурации log4j в любом месте веб-приложения (например, в одном проекте у нас были все файлы конфигурации внутри WEB-INF/).

Подробнее:

  • У меня есть мои свойства в файле log4j-no-autoload.properties в пути к классам (например, в моем проекте Maven изначально в src/main/resources, он упакован в WEB-INF/classes),
  • У него есть файл-приложение, настроенное, например,:

    log4j.appender.MyAppFileAppender = org.apache.log4j.FileAppender
    log4j.appender.MyAppFileAppender.file = ${webAppRoot}/WEB-INF/logs/my-app.log
    ...
    
  • И у меня есть такой прослушиватель контекста (он намного короче с синтаксисом 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(...)
        }
        ...
    }
    

Ответ 10

Вы можете указать относительный путь к файлу журнала, используя рабочий каталог:

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

Это не зависит от контейнера сервлета и не требует передачи пользовательской переменной в системную среду.