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

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

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

Ответы [ 10 ]

99 голосов
/ 19 октября 2008

Tomcat устанавливает системное свойство catalina.home. Вы можете использовать это в вашем файле свойств log4j. Примерно так:

log4j.rootCategory=DEBUG,errorfile

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

В Debian (включая Ubuntu) ${catalina.home} не будет работать, поскольку он указывает на / usr / share / tomcat6, который не имеет ссылки на / var / log / tomcat6. Вот только используйте ${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
53 голосов
/ 20 октября 2008

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

Добавлен 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, и пока работает нормально.

Что вы думаете?

14 голосов
/ 26 ноября 2008

Если вы используете 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) Укажите уникальное имя переменной для корня вашего веб-приложения, например, «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

6 голосов
/ 06 января 2010

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

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

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

5 голосов
/ 20 октября 2008

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

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

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

2 голосов
/ 19 ноября 2014

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

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

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

1 голос
/ 18 апреля 2017

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

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

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

1 голос
/ 03 сентября 2015

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

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

подробности:

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

    log4j.appender.MyAppFileAppender = org.apache.log4j.FileAppender
    log4j.appender.MyAppFileAppender.file = ${webAppRoot}/WEB-INF/logs/my-app.log
    ...
    
  3. И у меня есть прослушиватель контекста, подобный этому (становится намного короче с синтаксисом try-with-resource в Java 7):

    @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 голос
/ 17 апреля 2013

Если вы используете 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>
    

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

  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. Вот и все!

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

1 голос
/ 25 декабря 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...