[jOOQ/jOOQ#14652] Add a SQLExceptionLoggerListener that logs additional information to help debug constraint violations
This commit is contained in:
parent
f9012935f5
commit
b109886ec1
@ -342,6 +342,8 @@ public class Settings
|
||||
@XmlElement(defaultValue = "true")
|
||||
protected Boolean executeLogging = true;
|
||||
@XmlElement(defaultValue = "true")
|
||||
protected Boolean executeLoggingSQLExceptions = true;
|
||||
@XmlElement(defaultValue = "true")
|
||||
protected Boolean diagnosticsLogging = true;
|
||||
@XmlElement(defaultValue = "DEFAULT")
|
||||
@XmlSchemaType(name = "string")
|
||||
@ -4171,7 +4173,7 @@ public class Settings
|
||||
}
|
||||
|
||||
/**
|
||||
* When set to true, this will add jOOQ's default logging ExecuteListeners.
|
||||
* When set to true, this will add jOOQ's default {@link org.jooq.tools.LoggerListener} for debug logging. This is meant for use in development only.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
@ -4194,6 +4196,30 @@ public class Settings
|
||||
this.executeLogging = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* [#14420] Whether constraint violations and other {@link java.sql.SQLException} should produce additional log information about the column name and data causing the problem. Unlike {@link #executeLogging}, this is meant for use in production as well as development. This feature is available only in commercial distributions.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link Boolean }
|
||||
*
|
||||
*/
|
||||
public Boolean isExecuteLoggingSQLExceptions() {
|
||||
return executeLoggingSQLExceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the executeLoggingSQLExceptions property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link Boolean }
|
||||
*
|
||||
*/
|
||||
public void setExecuteLoggingSQLExceptions(Boolean value) {
|
||||
this.executeLoggingSQLExceptions = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* When set to true, this will add jOOQ's default logging DiagnosticsListeners.
|
||||
*
|
||||
@ -6777,6 +6803,11 @@ public class Settings
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings withExecuteLoggingSQLExceptions(Boolean value) {
|
||||
setExecuteLoggingSQLExceptions(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings withDiagnosticsLogging(Boolean value) {
|
||||
setDiagnosticsLogging(value);
|
||||
return this;
|
||||
@ -7516,6 +7547,7 @@ public class Settings
|
||||
builder.append("executeListenerStartInvocationOrder", executeListenerStartInvocationOrder);
|
||||
builder.append("executeListenerEndInvocationOrder", executeListenerEndInvocationOrder);
|
||||
builder.append("executeLogging", executeLogging);
|
||||
builder.append("executeLoggingSQLExceptions", executeLoggingSQLExceptions);
|
||||
builder.append("diagnosticsLogging", diagnosticsLogging);
|
||||
builder.append("diagnosticsConnection", diagnosticsConnection);
|
||||
builder.append("updateRecordVersion", updateRecordVersion);
|
||||
@ -8831,6 +8863,15 @@ public class Settings
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (executeLoggingSQLExceptions == null) {
|
||||
if (other.executeLoggingSQLExceptions!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!executeLoggingSQLExceptions.equals(other.executeLoggingSQLExceptions)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (diagnosticsLogging == null) {
|
||||
if (other.diagnosticsLogging!= null) {
|
||||
return false;
|
||||
@ -9684,6 +9725,7 @@ public class Settings
|
||||
result = ((prime*result)+((executeListenerStartInvocationOrder == null)? 0 :executeListenerStartInvocationOrder.hashCode()));
|
||||
result = ((prime*result)+((executeListenerEndInvocationOrder == null)? 0 :executeListenerEndInvocationOrder.hashCode()));
|
||||
result = ((prime*result)+((executeLogging == null)? 0 :executeLogging.hashCode()));
|
||||
result = ((prime*result)+((executeLoggingSQLExceptions == null)? 0 :executeLoggingSQLExceptions.hashCode()));
|
||||
result = ((prime*result)+((diagnosticsLogging == null)? 0 :diagnosticsLogging.hashCode()));
|
||||
result = ((prime*result)+((diagnosticsConnection == null)? 0 :diagnosticsConnection.hashCode()));
|
||||
result = ((prime*result)+((updateRecordVersion == null)? 0 :updateRecordVersion.hashCode()));
|
||||
|
||||
@ -59,9 +59,13 @@ import org.jooq.tools.LoggerListener;
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class ExecuteListeners implements ExecuteListener {
|
||||
|
||||
private static final ExecuteListener EMPTY_LISTENER = new DefaultExecuteListener();
|
||||
private static final JooqLogger LOGGER_LISTENER_LOGGER = JooqLogger.getLogger(LoggerListener.class);
|
||||
|
||||
|
||||
|
||||
|
||||
private final ExecuteListener[][] listeners;
|
||||
|
||||
// In some setups, these two events may get mixed up chronologically by the
|
||||
@ -116,6 +120,14 @@ final class ExecuteListeners implements ExecuteListener {
|
||||
(list = init(list)).add(new LoggerListener());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for (ExecuteListenerProvider provider : ctx.configuration().executeListenerProviders())
|
||||
|
||||
// Could be null after deserialisation
|
||||
|
||||
@ -54,12 +54,14 @@ import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.Keywords.K_DEFAULT_VALUES;
|
||||
import static org.jooq.impl.Keywords.K_VALUES;
|
||||
import static org.jooq.impl.QueryPartCollectionView.wrap;
|
||||
import static org.jooq.impl.Tools.EMPTY_FIELD;
|
||||
import static org.jooq.impl.Tools.anyMatch;
|
||||
import static org.jooq.impl.Tools.filter;
|
||||
import static org.jooq.impl.Tools.flatten;
|
||||
import static org.jooq.impl.Tools.flattenCollection;
|
||||
import static org.jooq.impl.Tools.flattenFieldOrRows;
|
||||
import static org.jooq.impl.Tools.lazy;
|
||||
import static org.jooq.impl.Tools.row0;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.AbstractMap;
|
||||
@ -86,6 +88,7 @@ import org.jooq.Param;
|
||||
// ...
|
||||
import org.jooq.Record;
|
||||
import org.jooq.RenderContext.CastMode;
|
||||
import org.jooq.Row;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.Table;
|
||||
@ -531,9 +534,23 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
nextRow++;
|
||||
}
|
||||
|
||||
final List<Map<Field<?>, Field<?>>> maps() {
|
||||
initNextRow();
|
||||
final List<Row> rows() {
|
||||
List<Map<Field<?>, Field<?>>> maps = maps();
|
||||
|
||||
return new AbstractList<Row>() {
|
||||
@Override
|
||||
public Row get(int index) {
|
||||
return row0(maps.get(index).values().toArray(EMPTY_FIELD));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return rows;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
final List<Map<Field<?>, Field<?>>> maps() {
|
||||
return new AbstractList<Map<Field<?>, Field<?>>>() {
|
||||
@Override
|
||||
public Map<Field<?>, Field<?>> get(int index) {
|
||||
@ -548,8 +565,6 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
}
|
||||
|
||||
final Map<Field<?>, Field<?>> map(final int index) {
|
||||
initNextRow();
|
||||
|
||||
return new AbstractMap<Field<?>, Field<?>>() {
|
||||
transient Set<Entry<Field<?>, Field<?>>> entrySet;
|
||||
|
||||
|
||||
@ -1215,7 +1215,7 @@ implements
|
||||
|
||||
@Override
|
||||
public final UnmodifiableList<? extends Row> $values() {
|
||||
return QOM.unmodifiable(new ArrayList<>());
|
||||
return QOM.unmodifiable(insertMaps.rows());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
208
jOOQ/src/main/java/org/jooq/impl/SQLExceptionLoggerListener.java
Normal file
208
jOOQ/src/main/java/org/jooq/impl/SQLExceptionLoggerListener.java
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: https://www.jooq.org/legal/licensing
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1220,7 +1220,11 @@ case of which, this defaults to INLINED]]></jxb:javadoc></jxb:property></appinfo
|
||||
</element>
|
||||
|
||||
<element name="executeLogging" type="boolean" minOccurs="0" maxOccurs="1" default="true">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[When set to true, this will add jOOQ's default logging ExecuteListeners.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[When set to true, this will add jOOQ's default {@link org.jooq.tools.LoggerListener} for debug logging. This is meant for use in development only.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="executeLoggingSQLExceptions" type="boolean" minOccurs="0" maxOccurs="1" default="true">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[[#14420] Whether constraint violations and other {@link java.sql.SQLException} should produce additional log information about the column name and data causing the problem. Unlike {@link #executeLogging}, this is meant for use in production as well as development. This feature is available only in commercial distributions.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="diagnosticsLogging" type="boolean" minOccurs="0" maxOccurs="1" default="true">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user