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

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

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

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 

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

Добавлен 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, и до сих пор он отлично работает.

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

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

  log4jConfigLocation /WEB-INF/classes/log4j-myapp.properties  

3) Укажите уникальное имя переменной для вашего корня webapp, например «myWebapp-instance-root»,

  webAppRootKey myWebapp-instance-root  

4) Добавьте Log4jConfigListener:

  org.springframework.web.util.Log4jConfigListener  

Если вы выберете другое имя, не забудьте также изменить его в log4j-myapp.properties.

См. Мою статью (только итальянский … но это должно быть понятно): http://www.megadix.it/content/configurare-path-relativi-log4j-utilizzando-spring

ОБНОВЛЕНИЕ (2009/08/01) Я перевел статью на английский: http://www.megadix.it/node/136

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

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

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

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

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

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

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

  1. Измените файл pom.xml, чтобы включить следующие строки:

       linux   unix    /var/log/tomcat6    windows   windows    ${catalina.home}/logs    

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

  2. Использовать уже определенное свойство log4j.properties файле 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. Это оно!

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

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

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

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

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

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

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

Детали:

  1. У меня есть мои свойства в файле log4j-no-autoload.properties в пути к classам (например, в моем проекте 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(...) } ... } 

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

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

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

  • Можно ли отключить HttpSession в web.xml?
  • В IndexedDB есть способ сделать отсортированный составной запрос?
  • Адрес уже используется: JVM_Bind java
  • Что такое файл web.xml и что я могу сделать с ним?
  • NoClassDefFoundError JsonAutoDetect при анализе объекта JSON
  • Как отличать сеансы в браузерах?
  • Выполнение стресс-теста в веб-приложении?
  • вопрос о GWT, Cookies и веб-странице
  • Как преобразовать веб-сайт ASP.NET в веб-приложение ASP.NET
  • Страница пользовательской ошибки ASP.NET - Server.GetLastError () - null
  • .dll уже загружен в другой загрузчик classов?
  • Interesting Posts

    Отсутствует библиотека для ссылки на типы соединений OLEDB

    Обновление подмодуля git необходимо только изначально?

    Java закончила с ненулевым значением выхода 2 – Android Gradle

    Как я могу сделать анимацию Java Swing более гладкой

    дублирующие символы для архитектуры i386 clang

    Зеркальная колонка на отдельном листе в Excel 2010

    Что такое возврат каретки, перевод строки и фид?

    Могу ли я получить проверку орфографии в MS Word, чтобы помнить мои грамматические решения?

    React Native android build не удалось. Местоположение SDK не найдено

    Проблема с преобразованием int в строку в Linq для объектов

    Использование пользовательского шрифта в android TextView с помощью xml

    C пишут в середине двоичного файла без перезаписи любого существующего содержимого

    Как настроить новую домашнюю группу в Win 7, когда в сети есть другая настройка домашней группы

    Отправить расширенные узлы TreeGrid в cookie

    Как работает тип Dynamic и как его использовать?

    Давайте будем гением компьютера.