Log4j, настройка веб-приложения на использование относительного пути
-
03-07-2019 - |
Вопрос
У меня есть веб-приложение Java, которое должно быть развернуто либо на компьютерах с Win, либо на Linux.Теперь я хочу добавить log4j для ведения журнала, и я хотел бы использовать относительный путь к файлу журнала, поскольку я не хочу изменять путь к файлу при каждом развертывании.Контейнером, скорее всего, будет Tomcat, но не обязательно.
Каков наилучший способ сделать это?
Решение 2
Я наконец сделал это таким образом.
Добавлен 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, и пока работает нормально.
Что ты думаешь?
Другие советы
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
Если вы используете 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-экземпляр-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
Просто комментарий о решении Iker . Р>
ServletContext
- хорошее решение вашей проблемы. Но я не думаю, что это хорошо для поддержания. Большую часть времени файлы журнала необходимо сохранять в течение длительного времени. Р>
Поскольку ServletContext
создает файл в развернутом файле, он будет удален при повторном развертывании сервера. Я предлагаю использовать родительскую папку rootPath вместо дочерней.
Разве log4j не использует просто корневой каталог приложения, если вы не указываете корневой каталог в свойстве path вашего FileAppender?Так что вы должны просто уметь использовать:
log4j.приложение.файл.Файл=журналы/MyLog.log
Прошло некоторое время с тех пор, как я занимался веб-разработкой на Java, но это кажется наиболее интуитивно понятным, а также не сталкивается с другими, к сожалению, названными журналами, записываемыми в каталог $ {catalina.home} /logs.
В качестве дополнительного комментария к https://stackoverflow.com/a/218037/2279200 - это может сломаться, если веб-приложение неявно запускает другой ServletContextListener, который может быть вызван ранее и который уже пытается использовать log4j - в этом случае конфигурация log4j будет прочитана и проанализирована уже перед тем, как свойство, определяющее корневой каталог журнала, будет установлено = > файлы журналов появятся где-то ниже текущего каталога (текущего каталога при запуске tomcat).
Я мог думать только о следующем решении этой проблемы: - переименуйте файл log4j.properties (или logj4.xml) в файл, который log4j не будет автоматически читать. - В вашем контекстном фильтре после установки свойства вызовите вспомогательный класс DOM / PropertyConfigurator, чтобы убедиться, что ваш log4j -. {Xml, properties} читается - Сброс конфигурации log4j (у IIRC есть способ сделать это)
Это немного грубая сила, но мне кажется, это единственный способ сделать ее водонепроницаемой.
Если вы используете 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, но, к сожалению, у меня недостаточно опыта.
Мое предложение заключается в том, что файл журнала всегда должен регистрироваться выше корневого контекста webApp, поэтому в случае повторного развертывания webApp мы не хотим переопределять существующие файлы журналов.
Мое решение похоже на решение Икера Хименеса решение, но вместо того , чтобы использовать System.setProperty(...)
Я использую org.apache.log4j.PropertyConfigurator.configure(Properties)
.Для этого мне также нужно, чтобы log4j не смог самостоятельно найти свою конфигурацию, и я загружаю ее вручную (оба пункта описаны в книге Вольфганга Либиха ответ).
Это работает для 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(...) } ... }
Вы можете указать относительный путь к файлу журнала, используя рабочий каталог :
appender.file.fileName = ${sys:user.dir}/log/application.log
Это не зависит от контейнера сервлета и не требует передачи пользовательской переменной в системную среду.