in log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java [948:1048]
protected void writeInternal(final LogEvent event, final Serializable serializable) {
// Don't close StringReaders because of (1) batching, (2) resources are not allocated, and (3) they'll be GC'd
// away.
// See https://github.com/apache/logging-log4j2/issues/3127 where closing StringReaders too soon can cause
// problems.
try {
if (!this.isRunning() || isClosed(this.connection) || isClosed(this.statement)) {
throw new AppenderLoggingException(
"Cannot write logging event; JDBC manager not connected to the database, running=%s, [%s]).",
isRunning(), fieldsToString());
}
// Clear in case there are leftovers.
statement.clearParameters();
if (serializable instanceof MapMessage) {
setFields((MapMessage<?, ?>) serializable);
}
int j = 1; // JDBC indices start at 1
if (this.factoryData.columnMappings != null) {
for (final ColumnMapping mapping : this.factoryData.columnMappings) {
if (ThreadContextMap.class.isAssignableFrom(mapping.getType())
|| ReadOnlyStringMap.class.isAssignableFrom(mapping.getType())) {
this.statement.setObject(j++, event.getContextData().toMap());
} else if (ThreadContextStack.class.isAssignableFrom(mapping.getType())) {
this.statement.setObject(j++, event.getContextStack().asList());
} else if (Date.class.isAssignableFrom(mapping.getType())) {
this.statement.setObject(
j++,
DateTypeConverter.fromMillis(
event.getTimeMillis(), mapping.getType().asSubclass(Date.class)));
} else {
final StringLayout layout = mapping.getLayout();
if (layout != null) {
if (Clob.class.isAssignableFrom(mapping.getType())) {
this.statement.setClob(j++, new StringReader(layout.toSerializable(event)));
} else if (NClob.class.isAssignableFrom(mapping.getType())) {
this.statement.setNClob(j++, new StringReader(layout.toSerializable(event)));
} else {
final Object value =
TypeConverters.convert(layout.toSerializable(event), mapping.getType(), null);
setStatementObject(j++, mapping.getNameKey(), value);
}
}
}
}
}
for (final ColumnConfig column : this.columnConfigs) {
if (column.isEventTimestamp()) {
this.statement.setTimestamp(j++, new Timestamp(event.getTimeMillis()));
} else if (column.isClob()) {
final Reader reader = new StringReader(column.getLayout().toSerializable(event));
if (column.isUnicode()) {
this.statement.setNClob(j++, reader);
} else {
this.statement.setClob(j++, reader);
}
} else if (column.isUnicode()) {
this.statement.setNString(
j++,
Objects.toString(
truncate(
column.getColumnNameKey(),
column.getLayout().toSerializable(event)),
null));
} else {
this.statement.setString(
j++,
Objects.toString(
truncate(
column.getColumnNameKey(),
column.getLayout().toSerializable(event)),
null));
}
}
if (isBuffered() && this.isBatchSupported) {
logger().debug("addBatch for {}", this.statement);
this.statement.addBatch();
} else {
final int executeUpdate = this.statement.executeUpdate();
logger().debug("executeUpdate = {} for {}", executeUpdate, this.statement);
if (executeUpdate == 0) {
throw new AppenderLoggingException(
"No records inserted in database table for log event in JDBC manager [%s].",
fieldsToString());
}
}
} catch (final SQLException e) {
throw new DbAppenderLoggingException(
e, "Failed to insert record for log event in JDBC manager: %s [%s]", e, fieldsToString());
} finally {
// Release ASAP
try {
// statement can be null when a AppenderLoggingException is thrown at the start of this method
if (statement != null) {
statement.clearParameters();
}
} catch (final SQLException e) {
// Ignore
}
}
}