Встроенный Tomcat, использующий log4j для регистрации
Я использую встроенный Tomcat 8.5.4, т.е.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.4</version>
</dependency>
Реализация работает отлично (Tomcat работает как шарм), единственное, что меня беспокоит, это то, что встроенный Tomcat входит в систему System.out
, Внутри моего приложения я использую log4j
для ведения журнала, так что это приводит к следующей смеси ведения журнала (а не регистрации Tomcat в любой файл):
...
2017-07-30 17:57:54 DEBUG EmbeddedTomcat:136 - Binding servlet 'sample' to path '/sample/*'.
Jul 30, 2017 5:57:54 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-15000"]
Jul 30, 2017 5:57:54 PM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFO: Using a shared selector for servlet write/read
Jul 30, 2017 5:57:54 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Tomcat
Jul 30, 2017 5:57:54 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/8.5.4
Jul 30, 2017 5:57:54 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler [http-nio-15000]
2017-07-30 17:57:54 INFO EmbeddedTomcat:80 - Successfully started Tomcat on port 15000 (base: null, url: http://localhost:15000).
...
В этом фрагменте первая и последняя строка (после и перед ...
) регистрируются моим приложением, используя log4j и конфигурацию log4j (которая записывает в файл и System.out
). Тем не менее, средняя часть (ведение журнала Tomcat) обрабатывается встроенным Tomcat, и я понятия не имею, как заставить Tomcat использовать доступный log4j (и его конфигурацию).
Я попытался добавить следующую зависимость (8.5.4
версия недоступна в репозитории Maven или Maven Central), но безуспешно.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-log4j</artifactId>
<version>8.5.2</version>
</dependency>
Кто-нибудь знает, как заставить Embedded Tomcat войти в систему с помощью log4j (Версия 1, я не использую log4j2)?
Я посмотрел / попробовал следующие ответы Stackru:
https://tomcat.apache.org/tomcat-8.0-doc/logging.html Поэтому я посмотрел документацию, в которой упоминается
log4j
в качестве основы ведения журнала. Это упоминаетtomcat-juli-adapters.jar
, который я не смог найти для встроенной версии (это так же, как "нормальный" Tomcat?). Как бы я сделал это программно, то есть в рамках моей реализации Embedded Tomcat.Tomcat Logging с использованием log4j? Это не та проблема, с которой я столкнулся, она не основана на Embedded Tomcat, ее версия довольно старая, и я на самом деле использую log4j, а не
System.out
,Встроенная регистрация Tomcat через logback / sl4j Этот вопрос на самом деле касается
logback
и автор упоминает, чтоI found some info about using a standalone tomcat with log4j
, но автономный отличается, я вижу, что автор использует аналогичные зависимости, но не уверен, было ли когда-либо решение.Как включить встроенное ведение журнала Tomcat Сначала я подумал, что это может быть решением, но все это просто связано с дополнительным ведением журнала для Embedded Tomcat. Я хочу, чтобы Embedded Tomcat использовал приложения
log4j
, так чтоlog4j.properties
файл, который определяет, как все регистрируется.Вход в Embedded Tomcat Я не уверен, почему этот ответ даже помечен как правильный, но это всего лишь объяснение того, как Tomcat пишет
catalina.out
файл, а не как работает регистрация встраиваемых Tomcat.
1 ответ
Это заняло у меня некоторое время, но после того, как я получил источники 8.5.4
реализации, я понял, что juli
Реализация регистрации добавляется в core
баночка.
Версия <= 8.5.2
Поэтому я вернулся и начал работать с 8.5.2
версия и используется tomcat-embed-logging-log4j-8.5.2.jar
, так же как tomcat-embed-core-8.5.2.jar
, Первое, на что нужно обратить внимание, это то, что в отношении большей части документации в Интернете важно не добавлять tomcat-embed-logging-juli-8.5.2.jar
, С учетом сказанного 8.5.2
версия работает с log4j
из коробки и больше ничего не поделаешь.
Версия> 8.5.2
При использовании более новой версии встроенного Tomcat, т. Е. 8.5.4.
или даже самый новый 8.5.19
, LogFactory
уже включен в банку. Таким образом, при добавлении старшего tomcat-embed-logging-log4j-8.5.2.jar
на пути к классам есть два LogFactory
реализации доступны сейчас. Первый предоставляется с core
и загружает DirectJDKLog
(Я называю это как Core-LogFactory
) и второй предоставляется через log4j
(упоминается как Log4j-LogFactory
). Таким образом, когда LogFactory
загружается из пути к классу, Core-LogFactory
выбран (потому что он находится в той же банке и, следовательно, "ближе" (не нужно углубляться в порядок загрузки classpath)). Вообще, это плохая практика иметь один и тот же класс (в том же пакете) на пути к классам. Это приведет только к путанице, и вы в основном никогда не узнаете, какой класс на самом деле используется (да, я знаю, что есть способы и правила, но, если коротко, это не хорошо). Таким образом, я решил вместо того, чтобы использовать tomcat-embed-logging-log4j-8.5.2.jar
кроме того, я следовал ServiceLoader
подход, который фактически реализуется в Core-LogFactory
из более новых версий ( https://svn.apache.org/repos/asf/tomcat/trunk/java/org/apache/juli/logging/LogFactory.java).
private LogFactory() {
// Look via a ServiceLoader for a Log implementation that has a
// constructor taking the String name.
ServiceLoader<Log> logLoader = ServiceLoader.load(Log.class);
Constructor<? extends Log> m=null;
for (Log log: logLoader) {
Class<? extends Log> c=log.getClass();
try {
m=c.getConstructor(String.class);
break;
}
catch (NoSuchMethodException | SecurityException e) {
throw new Error(e);
}
}
discoveredLogConstructor=m;
}
Для этого я добавил файл org.apache.juli.logging.Log
в META-INF/services
папку (внутри моего jar/sources) и добавил полное имя моего "собственного" Log
реализация, т.е. net.meisen.tomcat.logging.Log4jLog
, который выглядит следующим образом:
package net.meisen.tomcat.logging;
import org.apache.juli.logging.Log;
import org.apache.log4j.Logger;
public class Log4jLog implements Log {
private final Logger logger;
// this constructor is important, otherwise the ServiceLoader cannot start
public Log4jLog() {
logger = Logger.getLogger(Log4jLog.class);
}
// this constructor is needed by the LogFactory implementation
public Log4jLog(final String name) {
logger = Logger.getLogger(name);
}
// now we have to implement the `Log` interface
@Override
public boolean isFatalEnabled() {
return true;
}
// ... more isLevelEnabled()
@Override
public boolean isTraceEnabled() {
return logger.isTraceEnabled();
}
// ... and also all the fatal(...) - trace(...) methods
@Override
public void fatal(final Object msg) {
logger.fatal(msg);
}
@Override
public void fatal(final Object msg, final Throwable throwable) {
logger.fatal(msg, throwable);
}
}
И вот, вот окончательный результат:
2017-07-31 19:27:04 TRACE EmbeddedTomcat:48 - Initializing Tomcat on port 15000 (base: null)...
2017-07-31 19:27:33 INFO Http11NioProtocol:69 - Initializing ProtocolHandler ["http-nio-15000"]
2017-07-31 19:27:33 INFO NioSelectorPool:69 - Using a shared selector for servlet write/read
2017-07-31 19:27:33 INFO StandardService:69 - Starting service [Tomcat]
2017-07-31 19:27:33 INFO StandardEngine:69 - Starting Servlet Engine: Apache Tomcat/8.5.19
2017-07-31 19:27:34 WARN SessionIdGeneratorBase:79 - Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [170] milliseconds.
2017-07-31 19:27:34 INFO Http11NioProtocol:69 - Starting ProtocolHandler ["http-nio-15000"]
2017-07-31 19:27:34 INFO EmbeddedTomcat:80 - Successfully started Tomcat on port 15000 (base: null, url: http://localhost:15000).
Приложение:
Вот несколько ссылок, которые помогли мне выяснить ServiceLoader
и почему я решил довольно быстро, чтобы в моем проекте не было одного и того же класса в одном и том же пакете: