diff --git a/src/main/antora/modules/ROOT/pages/appendix/index.adoc b/src/main/antora/modules/ROOT/pages/appendix/index.adoc index 886361ff6..688ccc4e2 100644 --- a/src/main/antora/modules/ROOT/pages/appendix/index.adoc +++ b/src/main/antora/modules/ROOT/pages/appendix/index.adoc @@ -12,6 +12,8 @@ include::custom-queries.adoc[] include::spatial-types.adoc[] +include::logging.adoc[] + include::migrating.adoc[] include::build.adoc[] diff --git a/src/main/antora/modules/ROOT/pages/appendix/logging.adoc b/src/main/antora/modules/ROOT/pages/appendix/logging.adoc new file mode 100644 index 000000000..8a59feb61 --- /dev/null +++ b/src/main/antora/modules/ROOT/pages/appendix/logging.adoc @@ -0,0 +1,13 @@ +[[logging]] += Logging + +Spring Data Neo4j provides multiple loggers for https://neo4j.com/docs/status-codes/current/notifications/all-notifications/[Cypher notifications], starting with version 7.1.5. +The logger `org.springframework.data.neo4j.cypher` includes all statements that were invoked by Spring Data Neo4j and all notifications sent from the server. +To exclude or elevate some categories, the following loggers are in place: + +* `org.springframework.data.neo4j.cypher.performance` +* `org.springframework.data.neo4j.cypher.hint` +* `org.springframework.data.neo4j.cypher.unrecognized` +* `org.springframework.data.neo4j.cypher.unsupported` +* `org.springframework.data.neo4j.cypher.deprecation` +* `org.springframework.data.neo4j.cypher.generic` \ No newline at end of file diff --git a/src/main/java/org/springframework/data/neo4j/core/ResultSummaries.java b/src/main/java/org/springframework/data/neo4j/core/ResultSummaries.java index 5e39fa6af..89b461c4f 100644 --- a/src/main/java/org/springframework/data/neo4j/core/ResultSummaries.java +++ b/src/main/java/org/springframework/data/neo4j/core/ResultSummaries.java @@ -19,10 +19,13 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.logging.LogFactory; +import org.neo4j.driver.NotificationCategory; import org.neo4j.driver.summary.InputPosition; import org.neo4j.driver.summary.Notification; import org.neo4j.driver.summary.Plan; import org.neo4j.driver.summary.ResultSummary; +import org.springframework.core.log.LogAccessor; /** * Utility class for dealing with result summaries. @@ -34,6 +37,12 @@ import org.neo4j.driver.summary.ResultSummary; final class ResultSummaries { private static final String LINE_SEPARATOR = System.lineSeparator(); + private static final LogAccessor cypherPerformanceNotificationLog = new LogAccessor(LogFactory.getLog("org.springframework.data.neo4j.cypher.performance")); + private static final LogAccessor cypherHintNotificationLog = new LogAccessor(LogFactory.getLog("org.springframework.data.neo4j.cypher.hint")); + private static final LogAccessor cypherUnrecognizedNotificationLog = new LogAccessor(LogFactory.getLog("org.springframework.data.neo4j.cypher.unrecognized")); + private static final LogAccessor cypherUnsupportedNotificationLog = new LogAccessor(LogFactory.getLog("org.springframework.data.neo4j.cypher.unsupported")); + private static final LogAccessor cypherDeprecationNotificationLog = new LogAccessor(LogFactory.getLog("org.springframework.data.neo4j.cypher.deprecation")); + private static final LogAccessor cypherGenericNotificationLog = new LogAccessor(LogFactory.getLog("org.springframework.data.neo4j.cypher.generic")); /** * Does some post-processing on the giving result summary, especially logging all notifications @@ -57,15 +66,41 @@ final class ResultSummaries { String query = resultSummary.query().text(); resultSummary.notifications() .forEach(notification -> { - Consumer log = switch (notification.severity()) { - case "WARNING" -> Neo4jClient.cypherLog::warn; - case "INFORMATION" -> Neo4jClient.cypherLog::info; - default -> Neo4jClient.cypherLog::debug; - }; - log.accept(ResultSummaries.format(notification, query)); + LogAccessor log = notification.category() + .map(ResultSummaries::getLogAccessor) + .orElse(Neo4jClient.cypherLog); + Consumer logFunction = + switch (notification.severity()) { + case "WARNING" -> log::warn; + case "INFORMATION" -> log::info; + default -> log::debug; + }; + logFunction.accept(ResultSummaries.format(notification, query)); }); } + private static LogAccessor getLogAccessor(NotificationCategory category) { + if (category == NotificationCategory.HINT) { + return cypherHintNotificationLog; + } + if (category == NotificationCategory.DEPRECATION) { + return cypherDeprecationNotificationLog; + } + if (category == NotificationCategory.PERFORMANCE) { + return cypherPerformanceNotificationLog; + } + if (category == NotificationCategory.GENERIC) { + return cypherGenericNotificationLog; + } + if (category == NotificationCategory.UNSUPPORTED) { + return cypherUnsupportedNotificationLog; + } + if (category == NotificationCategory.UNRECOGNIZED) { + return cypherUnrecognizedNotificationLog; + } + return Neo4jClient.cypherLog; + } + /** * Creates a formatted string for a notification issued for a given query. * diff --git a/src/test/java/org/springframework/data/neo4j/test/TestLogFilter.java b/src/test/java/org/springframework/data/neo4j/test/TestLogFilter.java deleted file mode 100644 index 29aafc6fc..000000000 --- a/src/test/java/org/springframework/data/neo4j/test/TestLogFilter.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2011-2023 the original author or authors. - * - * 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. - */ -package org.springframework.data.neo4j.test; - -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.filter.Filter; -import ch.qos.logback.core.spi.FilterReply; - -import java.util.List; - -/** - * @author Gerrit Meier - */ -public class TestLogFilter extends Filter { - - private static final List FILTER_MESSAGES = List.of( - "ClientNotification.Statement.UnknownRelationshipTypeWarning", - "ClientNotification.Statement.UnknownLabelWarning", - "ClientNotification.Statement.UnknownPropertyKeyWarning", - "ClientNotification.Statement.FeatureDeprecationWarning" - ); - - @Override - public FilterReply decide(ILoggingEvent event) { - - String message = event.getMessage(); - - for (String filterMessage : FILTER_MESSAGES) { - if (message.contains(filterMessage)) { - return FilterReply.DENY; - } - } - - return FilterReply.ACCEPT; - } -} diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index f17c46b98..413307c32 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -18,7 +18,6 @@ - [%t] %d %5p %40.40c:%4L - %m%n @@ -31,6 +30,13 @@ + + + + + + +