From 044c70b3ba991eea8557487c38a733de8a5d63b1 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 9 Nov 2022 10:20:24 +0100 Subject: [PATCH] [jOOQ/jOOQ#14146] Add a LoggingDiagnosticsListener, a default DiagnosticsListener implementation that logs events --- .../src/main/java/org/jooq/conf/Settings.java | 42 +++++ .../org/jooq/impl/DiagnosticsListeners.java | 8 +- .../jooq/impl/LoggerDiagnosticsListener.java | 160 ++++++++++++++++++ .../org/jooq/xsd/jooq-runtime-3.18.0.xsd | 4 + 4 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 jOOQ/src/main/java/org/jooq/impl/LoggerDiagnosticsListener.java diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 3bf6207447..4fbb0caa08 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -309,6 +309,8 @@ public class Settings @XmlElement(defaultValue = "true") protected Boolean executeLogging = true; @XmlElement(defaultValue = "true") + protected Boolean diagnosticsLogging = true; + @XmlElement(defaultValue = "true") protected Boolean updateRecordVersion = true; @XmlElement(defaultValue = "true") protected Boolean updateRecordTimestamp = true; @@ -3673,6 +3675,30 @@ public class Settings this.executeLogging = value; } + /** + * When set to true, this will add jOOQ's default logging DiagnosticsListeners. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isDiagnosticsLogging() { + return diagnosticsLogging; + } + + /** + * Sets the value of the diagnosticsLogging property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setDiagnosticsLogging(Boolean value) { + this.diagnosticsLogging = value; + } + /** * Whether store(), insert(), and update() methods should update the record version prior to the operation, for use with {@link #executeWithOptimisticLocking}. * @@ -6068,6 +6094,11 @@ public class Settings return this; } + public Settings withDiagnosticsLogging(Boolean value) { + setDiagnosticsLogging(value); + return this; + } + public Settings withUpdateRecordVersion(Boolean value) { setUpdateRecordVersion(value); return this; @@ -6767,6 +6798,7 @@ public class Settings builder.append("executeListenerStartInvocationOrder", executeListenerStartInvocationOrder); builder.append("executeListenerEndInvocationOrder", executeListenerEndInvocationOrder); builder.append("executeLogging", executeLogging); + builder.append("diagnosticsLogging", diagnosticsLogging); builder.append("updateRecordVersion", updateRecordVersion); builder.append("updateRecordTimestamp", updateRecordTimestamp); builder.append("executeWithOptimisticLocking", executeWithOptimisticLocking); @@ -7934,6 +7966,15 @@ public class Settings return false; } } + if (diagnosticsLogging == null) { + if (other.diagnosticsLogging!= null) { + return false; + } + } else { + if (!diagnosticsLogging.equals(other.diagnosticsLogging)) { + return false; + } + } if (updateRecordVersion == null) { if (other.updateRecordVersion!= null) { return false; @@ -8735,6 +8776,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)+((diagnosticsLogging == null)? 0 :diagnosticsLogging.hashCode())); result = ((prime*result)+((updateRecordVersion == null)? 0 :updateRecordVersion.hashCode())); result = ((prime*result)+((updateRecordTimestamp == null)? 0 :updateRecordTimestamp.hashCode())); result = ((prime*result)+((executeWithOptimisticLocking == null)? 0 :executeWithOptimisticLocking.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/impl/DiagnosticsListeners.java b/jOOQ/src/main/java/org/jooq/impl/DiagnosticsListeners.java index c6c8d3b176..3766cc7b8c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DiagnosticsListeners.java +++ b/jOOQ/src/main/java/org/jooq/impl/DiagnosticsListeners.java @@ -38,6 +38,7 @@ package org.jooq.impl; import static java.lang.Boolean.FALSE; +import static org.jooq.impl.Tools.combine; import static org.jooq.impl.Tools.map; import java.util.function.Predicate; @@ -60,7 +61,12 @@ final class DiagnosticsListeners implements DiagnosticsListener { } static final DiagnosticsListeners get(Configuration configuration) { - return new DiagnosticsListeners(configuration.diagnosticsListenerProviders()); + DiagnosticsListenerProvider[] p = configuration.diagnosticsListenerProviders(); + + if (!FALSE.equals(configuration.settings().isDiagnosticsLogging())) + p = combine(DefaultDiagnosticsListenerProvider.providers(new LoggerDiagnosticsListener()), p); + + return new DiagnosticsListeners(p); } private static final boolean check(DiagnosticsContext ctx, Predicate test) { diff --git a/jOOQ/src/main/java/org/jooq/impl/LoggerDiagnosticsListener.java b/jOOQ/src/main/java/org/jooq/impl/LoggerDiagnosticsListener.java new file mode 100644 index 0000000000..0667598216 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/LoggerDiagnosticsListener.java @@ -0,0 +1,160 @@ +/* + * 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; + +import static java.util.stream.Collectors.toList; + +import java.util.stream.Collectors; + +import org.jooq.DiagnosticsContext; +import org.jooq.DiagnosticsListener; +import org.jooq.tools.JooqLogger; + +/** + * A default implementation of a {@link DiagnosticsListener} that logs + * diagnostics. + * + * @author Lukas Eder + */ +public class LoggerDiagnosticsListener implements DiagnosticsListener { + + private static final JooqLogger log = JooqLogger.getLogger(LoggerDiagnosticsListener.class); + + private void log(String text, DiagnosticsContext ctx) { + log(text, ctx, null); + } + + private void log(String text, DiagnosticsContext ctx, String additionalContext) { + if (log.isInfoEnabled()) { + if (additionalContext != null) + text += "\n" + additionalContext; + + if (ctx.actualStatement().equals(ctx.normalisedStatement())) + text += "\nStatement: " + ctx.actualStatement(); + else + text += "\nActual statement : " + ctx.actualStatement() + + "\nNormalised statement: " + ctx.normalisedStatement(); + + log.info("Diagnostics", text); + } + } + + @Override + public void duplicateStatements(DiagnosticsContext ctx) { + log(""" + Duplicate statements were encountered. Why is it bad? See: https://www.jooq.org/doc/latest/manual/sql-execution/diagnostics/diagnostics-duplicate-statements/ + """, + ctx, + "Recent statements include: " + ctx.duplicateStatements().stream().limit(5).map(s -> "\n " + s).collect(toList()) + ); + } + + @Override + public void repeatedStatements(DiagnosticsContext ctx) { + log(""" + Repeated statements were encountered. Why is it bad? See: https://www.jooq.org/doc/latest/manual/sql-execution/diagnostics/diagnostics-repeated-statements/ + """, + ctx, + "Recent statements include: " + ctx.repeatedStatements().stream().limit(5).map(s -> "\n " + s).collect(toList()) + ); + } + + + @Override + public void tooManyColumnsFetched(DiagnosticsContext ctx) { + log(""" + Too many columns were fetched and never read. Why is it bad? See: https://www.jooq.org/doc/latest/manual/sql-execution/diagnostics/diagnostics-too-many-columns/ + """, + ctx, + "Fetched columns : " + ctx.resultSetFetchedColumnNames() + + "\nConsumed columns: " + ctx.resultSetConsumedColumnNames() + ); + } + + @Override + public void tooManyRowsFetched(DiagnosticsContext ctx) { + log(""" + Too many rows were fetched and never read. Why is it bad? See: https://www.jooq.org/doc/latest/manual/sql-execution/diagnostics/diagnostics-too-many-rows/ + """, + ctx, + "Fetched rows : " + ctx.resultSetFetchedRows() + + "\nConsumed rows: " + ctx.resultSetConsumedRows() + ); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd index 8c01a11969..b048f2bc6d 100644 --- a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd +++ b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd @@ -1065,6 +1065,10 @@ case of which, this defaults to INLINED]]> + + + +