Skip to content

Commit c5bf627

Browse files
authored
Fix logging IP version 6 addresses with scope in RediscoveryImpl (#1435)
The `Inet6Address.getHostAddress()` returns a string with `%scope-id` at the end if it is scoped. For instance, `fe80:0:0:0:ce66:1564:db8q:94b6%6`. The `RediscoveryImpl` error handling logic used to construct a log message with such address that it logged using the `Logger.warn(String, Object...)` method. Example: `log.warn(message)`. Some implementations of the `Logger` interface supply the values given directly to the `String.format(String, Object...)` method. Given that the first argument is considered to be a format string, an `IllegalFormatException` may be thrown. That used to happen when the log message contained the scoped IP version 6 `getHostAddress()` value since the log message was treated as the format string. This update fixes this issue by supplying the format string and the address values individually and letting the logger implementations to do the formatting as the log message should not be seen as the format string value.
1 parent 2660b23 commit c5bf627

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

driver/src/main/java/org/neo4j/driver/internal/cluster/RediscoveryImpl.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -316,13 +316,11 @@ private ClusterComposition handleRoutingProcedureError(
316316
throw new CompletionException(error);
317317
}
318318

319-
// Retriable error happened during discovery.
320-
DiscoveryException discoveryError =
321-
new DiscoveryException(format(RECOVERABLE_ROUTING_ERROR, routerAddress), error);
319+
// Retryable error happened during discovery.
320+
var discoveryError = new DiscoveryException(format(RECOVERABLE_ROUTING_ERROR, routerAddress), error);
322321
Futures.combineErrors(baseError, discoveryError); // we record each failure here
323-
String warningMessage = format(RECOVERABLE_DISCOVERY_ERROR_WITH_SERVER, routerAddress);
324-
log.warn(warningMessage);
325-
log.debug(warningMessage, discoveryError);
322+
log.warn(RECOVERABLE_DISCOVERY_ERROR_WITH_SERVER, routerAddress);
323+
log.debug(format(RECOVERABLE_DISCOVERY_ERROR_WITH_SERVER, routerAddress), discoveryError);
326324
routingTable.forget(routerAddress);
327325
return null;
328326
}

driver/src/test/java/org/neo4j/driver/internal/cluster/RediscoveryTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import static org.junit.jupiter.api.Assertions.assertNotNull;
2929
import static org.junit.jupiter.api.Assertions.assertThrows;
3030
import static org.mockito.ArgumentMatchers.any;
31+
import static org.mockito.BDDMockito.given;
32+
import static org.mockito.Mockito.doAnswer;
3133
import static org.mockito.Mockito.mock;
3234
import static org.mockito.Mockito.never;
3335
import static org.mockito.Mockito.startsWith;
@@ -54,6 +56,7 @@
5456
import java.util.List;
5557
import java.util.Map;
5658
import java.util.Set;
59+
import java.util.concurrent.CompletableFuture;
5760
import org.junit.jupiter.api.Disabled;
5861
import org.junit.jupiter.api.Test;
5962
import org.junit.jupiter.params.ParameterizedTest;
@@ -525,6 +528,35 @@ void shouldFailImmediatelyOnUnsupportedFeatureException() {
525528
verify(table).forget(A);
526529
}
527530

531+
@Test
532+
void shouldLogScopedIPV6AddressWithStringFormattingLogger() throws UnknownHostException {
533+
// GIVEN
534+
var initialRouter = new BoltServerAddress("initialRouter", 7687);
535+
var compositionProvider = compositionProviderMock(Collections.emptyMap());
536+
var resolver = resolverMock(initialRouter, initialRouter);
537+
var domainNameResolver = mock(DomainNameResolver.class);
538+
var address = mock(InetAddress.class);
539+
given(address.getHostAddress()).willReturn("fe80:0:0:0:ce66:1564:db8q:94b6%6");
540+
given(domainNameResolver.resolve(initialRouter.host())).willReturn(new InetAddress[] {address});
541+
var table = routingTableMock(true);
542+
var pool = mock(ConnectionPool.class);
543+
given(pool.acquire(any(), any()))
544+
.willReturn(CompletableFuture.failedFuture(new ServiceUnavailableException("not available")));
545+
var logging = mock(Logging.class);
546+
var logger = mock(Logger.class);
547+
given(logging.getLog(any(Class.class))).willReturn(logger);
548+
doAnswer(invocationOnMock -> String.format(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)))
549+
.when(logger)
550+
.warn(any());
551+
var rediscovery =
552+
new RediscoveryImpl(initialRouter, compositionProvider, resolver, logging, domainNameResolver);
553+
554+
// WHEN & THEN
555+
assertThrows(
556+
ServiceUnavailableException.class,
557+
() -> await(rediscovery.lookupClusterComposition(table, pool, Collections.emptySet(), null, null)));
558+
}
559+
528560
private Rediscovery newRediscovery(
529561
BoltServerAddress initialRouter,
530562
ClusterCompositionProvider compositionProvider,

0 commit comments

Comments
 (0)