Я пытаюсь войти в базу данных PostgreSQL с помощью этого объединенного регистратора JDBC в моем приложении Spring.
Основная идея исходит отсюда: Как инициализировать log4j с помощью приложения Spring Boot?
@Component
public class JdbcAppenderConfiguration implements
ApplicationListener<ContextRefreshedEvent> {
private static Logger LOGGER =
LogManager.getLogger(JdbcAppenderConfiguration.class);
private final DataSource dataSource;
public JdbcAppenderConfiguration(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final ColumnConfig[] cc = {
ColumnConfig.newBuilder()
.setConfiguration(ctx.getConfiguration())
.setName("level")
.setPattern("%level")
.setUnicode(false)
.build()
};
final Appender appender = JdbcAppender
.newBuilder()
.setName("databaseAppender")
.setIgnoreExceptions(false)
.setConnectionSource(new ConnectionFactory(dataSource))
.setTableName("logs2")
.setColumnConfigs(cc)
.build();
appender.start();
ctx.getConfiguration().addAppender(appender);
final LoggerConfig loggerConfig =
ctx.getConfiguration()
.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
loggerConfig.addAppender(appender, null, null);
ctx.updateLoggers();
}
}
И фабрика соединений:
public class ConnectionFactory extends AbstractConnectionSource {
private final DataSource dataSource;
public ConnectionFactory(DataSource dataSource) {
AssertUtils.notNull(dataSource, "dataSource");
this.dataSource = dataSource;
}
@Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
Но при регистрации я получаю эту ошибку:
2020-12-12 08:03:05,860 restartedMain ERROR Невозможно записать в база данных [JdbcManager {имя = databaseAppender, bufferSize = 0, tableName=logs2, columnConfigs=[{ name=level, layout=%level, literal=null, timestamp=false }], columnMappings=null}] для добавления [приложение базы данных]. org.apache.logging.log4j.core.appender.db.DbAppenderLoggingException: Не удалось вставить запись для события журнала в диспетчере JDBC: org.postgresql.util.PSQLException: ОШИБКА: синтаксическая ошибка в или около ")" Позиция: 20 [columnConfigs=[{ name=level, layout=%level, literal=null, timestamp=false }], sqlStatement=вставить в logs2 () значения (?), factoryData = Заводские данные [connectionSource=ConnectionFactory@ca2c455, tableName=logs2, columnConfigs=[{ name=level, layout=%level, литерал = ноль, временная метка = ложь}], столбецMappings = ноль, непосредственныйFail=false, повтор=true, reconnectIntervalMillis=5000, truncateStrings=true], соединение=HikariProxyConnection@1535828764 упаковка org.postgresql.jdbc.PgConnection@603942ae, заявление = HikariProxyPreparedStatement@1512335087 оберточная вставка в значения logs2 () («INFO»), reconnector=null, isBatchSupported=true, столбецMetaData = {}]
есть проблема с недействительным оператором SQL INSERT:
sqlStatement=вставить в logs2() значения (?),
Вопрос: У вас есть идея, почему log4J не правильно/полностью составляет команду? Что не так с моим кодом?
Это ошибка в Log4j2.
Я настроил быстрый проект в IntelliJ, добавил log4j2 2.14 API и основные JAR-файлы, а также JAR-файл драйвера базы данных и запустил ваш код, и мне удалось воспроизвести неправильно отформатированный оператор INSERT
в вашем сообщении об ошибке.
Я использовал IntelliJ, чтобы загрузить исходный JAR-файл log4j2 и прикрепить его, а также прошел код, который собрал оператор INSERT
. Метод, добавляющий имена столбцов в строку SQL, называется appendColumnNames
и относится к классу JdbcDatabaseManager
.
Он содержит следующий код, который я сократил для ясности:
if (data.columnMappings != null) {
for (final ColumnMapping colMapping : data.columnMappings) {
// append column from colMapping
}
if (data.columnConfigs != null) {
for (final ColumnConfig colConfig : data.columnConfigs) {
// append column from colConfig
}
}
}
В этом случае мы видим, что имена столбцов из ColumnConfig
s не используются, если ColumnMapping
s являются null
. Такое поведение неверно: вы должны указать только ColumnConfig
s. Второй if
не должен быть вложен в первый.
Log4j2 поддерживает использование ColumnMapping
s, а также ColumnConfig
s для указания столбцов для записи в вашей таблице журналов, поэтому одним из обходных путей является использование их вместо этого. Альтернативный обходной путь — добавить строку
.setColumnMappings(new ColumnMapping[0])
на строительство вашего JdbcAppender
. Я внес это изменение в ваш код, и Log4j2 сгенерировал правильную строку SQL.
Да, тем временем я тоже это понял - мне нужно назначить пустой ColumnMapping
final ColumnMapping[] columnMappings = new ColumnMapping[0];