После обновления до slf4j 2.0.13, logback 1.5.6 и logback-db 1.2.11.1 конфигурация XML для logback, которая раньше работала нормально, дает сбой. Насколько я могу судить, платформа пытается инициализировать средства ведения журнала до инициализации DriverManagerConnectionSource. Я подозреваю, что я пропустил новое требование к конфигурации.
Я сравнил файл конфигурации с примером DBAppender по адресу https://logback.qos.ch/manual/appenders.html
Когда я отслеживаю исходный код, DBAppenderBase.start() содержит следующую строку:
DBUtil.getDialectFromCode(connectionSource.getSQLDialectCode());
ConnectionSource (экземпляр DriverManagerConnectionSource) содержит значение null в качестве SQLDialectCode. Если копнуть глубже, то DriverManagerConnectionSource должен установить SQLDialectCode в своем методе start() на основе URL-адреса, указанного в теге ConnectionSource.url. Я использовал точку останова в отладчике, чтобы убедиться, что DriverManagerConnectionSource.start() никогда не вызывается.
Я не могу быть единственным человеком, который когда-либо использовал DBAppender, поэтому мне интересно, какие требования к конфигурации изменились с тех пор, как мы в последний раз обновляли наши ссылки POM для входа в систему.
пом.xml:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.13</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.4.14</version>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>
<dependency>
<groupId>ch.qos.logback.db</groupId>
<artifactId>logback-classic-db</artifactId>
<version>1.2.11.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback.db</groupId>
<artifactId>logback-core-db</artifactId>
<version>1.2.11.1</version>
</dependency>
Java-код:
package com.me.myApp;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@WebListener
public class MyContextListener implements ServletContextListener {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void contextInitialized(ServletContextEvent sce) {
System.setProperty("my.web.container", sce.getServletContext().getServerInfo());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
logger.info("Shutting down.");
}
}
XML-конфигурация:
<?xml version = "1.0" encoding = "UTF-8"?>
<configuration scan = "true" scanPeriod = "30 seconds">
<contextListener class = "ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
<property file = "/my/properties/my-datastore.properties"/>
<!-- To enable JMX Management -->
<jmxConfigurator />
<!-- Notification Appender -->
<appender name = "me.notification.appender" class = "ch.qos.logback.classic.db.DBAppender">
<filter class = "ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<connectionSource class = "ch.qos.logback.core.db.DriverManagerConnectionSource">
<driverClass>org.postgresql.Driver</driverClass>
<url>jdbc:postgresql://me.myapp.com:5432/mydb</url>
<user>postgres</user>
<password>postgres</password>
</connectionSource>
<encoder>
<pattern>%-5level %logger{0} - %msg%n</pattern>
<pattern>Id : %X{Id},Name : %X{Name},ModelName : %X{ModelName} %thread %date{ISO8601} %-5level %logger{5} - %msg%n</pattern>
</encoder>
</appender>
<logger name = "me.notification" level = "info">
<appender-ref ref = "me.notification.appender" />
<appender-ref ref = "logFile" />
</logger>
</configuration>
Код журнала регистрации, который не делает того, что я ожидаю, исходя из этой конфигурации XML:
public abstract class DBAppenderBase<E> extends UnsynchronizedAppenderBase<E> {
protected ConnectionSource connectionSource;
protected boolean cnxSupportsGetGeneratedKeys = false;
protected boolean cnxSupportsBatchUpdates = false;
protected SQLDialect sqlDialect;
protected abstract Method getGeneratedKeysMethod();
protected abstract String getInsertSQL();
@Override
public void start() {
if (connectionSource == null) {
throw new IllegalStateException("DBAppender cannot function without a connection source");
}
sqlDialect = DBUtil.getDialectFromCode(connectionSource.getSQLDialectCode());
if (getGeneratedKeysMethod() != null) {
cnxSupportsGetGeneratedKeys = connectionSource.supportsGetGeneratedKeys();
} else {
cnxSupportsGetGeneratedKeys = false;
}
cnxSupportsBatchUpdates = connectionSource.supportsBatchUpdates();
if (!cnxSupportsGetGeneratedKeys && (sqlDialect == null)) {
throw new IllegalStateException(
"DBAppender cannot function if the JDBC driver does not support getGeneratedKeys method *and* without a specific SQL dialect");
}
...
// all nice and dandy on the eastern front
super.start();
}
Сообщение об ошибке: «DBAppender не может работать, если драйвер JDBC не поддерживает метод getGeneratedKeys и без определенного диалекта SQL». Регистратору не удается инициализироваться, поэтому приложение вообще не запускается. Этот фрагмент кода минимально воспроизводит основную проблему: DBAppender инициализируется перед DriverManagerConnectionSource.
Обнаруженные проблемы (множественное число): загрузчик классов, eclipse + tomcat, перспектива отладки Eclipse и ложный файл конфигурации был зарегистрирован в пути к классам. Logback не очень дружелюбен, когда он не может начать работу.




Было несколько взаимодействующих проблем, каждая из которых (индивидуально) приводила к одному и тому же симптому (DBAppender cannot function if the JDBC driver does not support getGeneratedKeys method and without a specific SQL dialect), который мне удалось отследить с помощью отладчика.
Измените это на
<configuration debug = "true" scan = "true" scanPeriod = "30 seconds">Что происходит? Код возврата, который не делает того, что я ожидаю, исходя из этой конфигурации XML: я не вижу там никакого входа в систему...