Skip to content

Commit c3f1c3b

Browse files
committed
Add query logger
[resolves #201]
1 parent 5d26efd commit c3f1c3b

File tree

6 files changed

+58
-16
lines changed

6 files changed

+58
-16
lines changed

README.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,15 @@ This driver accepts the following extensions:
362362

363363
* `CodecRegistrar` to contribute `Codec`s for Postgres ObjectIDs.
364364

365-
Extensions can be registered programmatically using `PostgresConnectionConfiguration` or discovered using Java's `ServiceLoader` mechanism (from `META-INF/services/io.r2dbc.postgresql.extension.Extension`).
365+
Extensions can be registered programmatically using `PostgresConnectionConfiguration` or discovered using Java's `ServiceLoader` mechanism (from `META-INF/services/io.r2dbc.postgresql.extension.Extension`).
366+
367+
## Logging
368+
If SL4J is on the classpath, it will be used. Otherwise, there are two possible fallbacks: Console or `java.util.logging.Logger`). By default, the Console fallback is used. To use the JDK loggers, set the `reactor.logging.fallback` System property to `JDK`.
369+
370+
Logging facilities:
371+
372+
* Driver Logging: `io.r2dbc.postgresql`.
373+
* Query Logging: `io.r2dbc.postgresql.QUERY` on `DEBUG` level.
366374

367375
## License
368376
This project is released under version 2.0 of the [Apache License][l].

src/main/java/io/r2dbc/postgresql/ExtendedQueryPostgresqlStatement.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ private Flux<io.r2dbc.postgresql.api.PostgresqlResult> execute(String sql) {
183183
ExceptionFactory factory = ExceptionFactory.withSql(sql);
184184
return this.statementCache.getName(this.bindings.first(), sql)
185185
.flatMapMany(name -> ExtendedQueryMessageFlow
186-
.execute(Flux.fromIterable(this.bindings.bindings), this.client, this.portalNameSupplier, name, this.forceBinary))
186+
.execute(Flux.fromIterable(this.bindings.bindings), this.client, this.portalNameSupplier, name, sql, this.forceBinary))
187187
.filter(RESULT_FRAME_FILTER)
188188
.windowUntil(CloseComplete.class::isInstance)
189189
.map(messages -> PostgresqlResult.toResult(this.codecs, messages, factory));

src/main/java/io/r2dbc/postgresql/client/ExtendedQueryMessageFlow.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,20 @@ private ExtendedQueryMessageFlow() {
6565
* @param bindings the {@link Binding}s to bind
6666
* @param client the {@link Client} to exchange messages with
6767
* @param portalNameSupplier supplier unique portal names for each binding
68-
* @param statement the name of the statement to execute
68+
* @param statementName the name of the statementName to execute
69+
* @param query the query to execute
6970
* @param forceBinary force backend to return column data values in binary format for all columns
7071
* @return the messages received in response to the exchange
71-
* @throws IllegalArgumentException if {@code bindings}, {@code client}, {@code portalNameSupplier}, or {@code statement} is {@code null}
72+
* @throws IllegalArgumentException if {@code bindings}, {@code client}, {@code portalNameSupplier}, or {@code statementName} is {@code null}
7273
*/
73-
public static Flux<BackendMessage> execute(Publisher<Binding> bindings, Client client, PortalNameSupplier portalNameSupplier, String statement, boolean forceBinary) {
74+
public static Flux<BackendMessage> execute(Publisher<Binding> bindings, Client client, PortalNameSupplier portalNameSupplier, String statementName, String query, boolean forceBinary) {
7475
Assert.requireNonNull(bindings, "bindings must not be null");
7576
Assert.requireNonNull(client, "client must not be null");
7677
Assert.requireNonNull(portalNameSupplier, "portalNameSupplier must not be null");
77-
Assert.requireNonNull(statement, "statement must not be null");
78+
Assert.requireNonNull(statementName, "statementName must not be null");
7879

7980
return client.exchange(Flux.from(bindings)
80-
.flatMap(binding -> toBindFlow(binding, portalNameSupplier, statement, forceBinary))
81+
.flatMap(binding -> toBindFlow(binding, portalNameSupplier, statementName, query, forceBinary))
8182
.concatWith(Mono.just(Sync.INSTANCE)));
8283
}
8384

@@ -109,7 +110,7 @@ private static Collection<Format> resultFormat(boolean forceBinary) {
109110
}
110111
}
111112

112-
private static Flux<FrontendMessage> toBindFlow(Binding binding, PortalNameSupplier portalNameSupplier, String statement, boolean forceBinary) {
113+
private static Flux<FrontendMessage> toBindFlow(Binding binding, PortalNameSupplier portalNameSupplier, String statementName, String query, boolean forceBinary) {
113114
String portal = portalNameSupplier.get();
114115

115116
return Flux.fromIterable(binding.getParameterValues())
@@ -123,10 +124,10 @@ private static Flux<FrontendMessage> toBindFlow(Binding binding, PortalNameSuppl
123124
})
124125
.collectList()
125126
.flatMapMany(values -> {
126-
Bind bind = new Bind(portal, binding.getParameterFormats(), values, resultFormat(forceBinary), statement);
127+
Bind bind = new Bind(portal, binding.getParameterFormats(), values, resultFormat(forceBinary), statementName);
127128

128129
return Flux.just(bind, new Describe(portal, PORTAL), new Execute(portal, NO_LIMIT), new Close(portal, PORTAL));
129-
});
130+
}).doOnSubscribe(ignore -> QueryLogger.logQuery(query));
130131
}
131132

132133
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.r2dbc.postgresql.client;
18+
19+
import reactor.util.Logger;
20+
import reactor.util.Loggers;
21+
22+
/**
23+
* Query logger to log queries.
24+
*/
25+
final class QueryLogger {
26+
27+
private static final Logger QUERY_LOGGER = Loggers.getLogger("io.r2dbc.postgresql.QUERY");
28+
29+
static void logQuery(String query) {
30+
QUERY_LOGGER.debug("Executing query: {}", query);
31+
}
32+
}

src/main/java/io/r2dbc/postgresql/client/SimpleQueryMessageFlow.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.r2dbc.postgresql.client;
1818

1919
import io.r2dbc.postgresql.message.backend.BackendMessage;
20+
import io.r2dbc.postgresql.message.frontend.FrontendMessage;
2021
import io.r2dbc.postgresql.message.frontend.Query;
2122
import io.r2dbc.postgresql.util.Assert;
2223
import reactor.core.publisher.Flux;
@@ -42,7 +43,7 @@ public static Flux<BackendMessage> exchange(Client client, String query) {
4243
Assert.requireNonNull(client, "client must not be null");
4344
Assert.requireNonNull(query, "query must not be null");
4445

45-
return client.exchange(Mono.just(new Query(query)));
46+
return client.exchange(Mono.<FrontendMessage>just(new Query(query)).doOnSubscribe(ignore -> QueryLogger.logQuery(query)));
4647
}
4748

4849
}

src/test/java/io/r2dbc/postgresql/client/ExtendedQueryMessageFlowTest.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ BindComplete.INSTANCE, NoData.INSTANCE, new CommandComplete("test", null, null)
6969
PortalNameSupplier portalNameSupplier = new LinkedList<>(Arrays.asList("B_0", "B_1"))::remove;
7070

7171
ExtendedQueryMessageFlow
72-
.execute(bindings, client, portalNameSupplier, "test-name", false)
72+
.execute(bindings, client, portalNameSupplier, "test-name", "", false)
7373
.as(StepVerifier::create)
7474
.expectNext(BindComplete.INSTANCE, NoData.INSTANCE, new CommandComplete("test", null, null))
7575
.expectNext(BindComplete.INSTANCE, NoData.INSTANCE, new CommandComplete("test", null, null))
@@ -78,25 +78,25 @@ BindComplete.INSTANCE, NoData.INSTANCE, new CommandComplete("test", null, null)
7878

7979
@Test
8080
void executeNoBindings() {
81-
assertThatIllegalArgumentException().isThrownBy(() -> ExtendedQueryMessageFlow.execute(null, NO_OP, () -> "", "test-statement", false))
81+
assertThatIllegalArgumentException().isThrownBy(() -> ExtendedQueryMessageFlow.execute(null, NO_OP, () -> "", "test-statement", "", false))
8282
.withMessage("bindings must not be null");
8383
}
8484

8585
@Test
8686
void executeNoClient() {
87-
assertThatIllegalArgumentException().isThrownBy(() -> ExtendedQueryMessageFlow.execute(Flux.empty(), null, () -> "", "test-statement", false))
87+
assertThatIllegalArgumentException().isThrownBy(() -> ExtendedQueryMessageFlow.execute(Flux.empty(), null, () -> "", "test-statement", "", false))
8888
.withMessage("client must not be null");
8989
}
9090

9191
@Test
9292
void executeNoPortalNameSupplier() {
93-
assertThatIllegalArgumentException().isThrownBy(() -> ExtendedQueryMessageFlow.execute(Flux.empty(), NO_OP, null, "test-statement", false))
93+
assertThatIllegalArgumentException().isThrownBy(() -> ExtendedQueryMessageFlow.execute(Flux.empty(), NO_OP, null, "test-statement", "", false))
9494
.withMessage("portalNameSupplier must not be null");
9595
}
9696

9797
@Test
9898
void executeNoStatement() {
99-
assertThatIllegalArgumentException().isThrownBy(() -> ExtendedQueryMessageFlow.execute(Flux.empty(), NO_OP, () -> "", null, false))
99+
assertThatIllegalArgumentException().isThrownBy(() -> ExtendedQueryMessageFlow.execute(Flux.empty(), NO_OP, () -> "", null, "", false))
100100
.withMessage("statement must not be null");
101101
}
102102

0 commit comments

Comments
 (0)