GH-2800 - Introduce additional loggers for cypher notifications.

Closes #2800
This commit is contained in:
Gerrit Meier
2023-09-26 17:09:46 +02:00
parent eb89011e4e
commit 9a6490bfd2
5 changed files with 63 additions and 56 deletions

View File

@@ -12,6 +12,8 @@ include::custom-queries.adoc[]
include::spatial-types.adoc[]
include::logging.adoc[]
include::migrating.adoc[]
include::build.adoc[]

View File

@@ -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`

View File

@@ -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<String> 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<String> 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.
*

View File

@@ -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<ILoggingEvent> {
private static final List<String> 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;
}
}

View File

@@ -18,7 +18,6 @@
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="org.springframework.data.neo4j.test.TestLogFilter" />
<encoder>
<pattern>[%t] %d %5p %40.40c:%4L - %m%n</pattern>
</encoder>
@@ -31,6 +30,13 @@
<logger name="InboundMessageDispatcher" level="info"/>
<logger name="org.springframework.data.neo4j.cypher" level="info"/>
<logger name="org.springframework.data.neo4j.cypher.performance" level="info"/>
<logger name="org.springframework.data.neo4j.cypher.hint" level="info"/>
<logger name="org.springframework.data.neo4j.cypher.unrecognized" level="error"/>
<logger name="org.springframework.data.neo4j.cypher.unsupported" level="error"/>
<!-- if deprecation gets set to "warn" or finer, all id() deprecation will get logged -->
<logger name="org.springframework.data.neo4j.cypher.deprecation" level="error"/>
<logger name="org.springframework.data.neo4j.cypher.generic" level="error"/>
<logger name="org.springframework.data.neo4j" level="info"/>
<logger name="org.springframework.data.neo4j.test" level="info"/>
<logger name="org.springframework.data.neo4j.repository.query.Neo4jQuerySupport" level="debug" />