


























One of the benefits of Testcontainers is the ability to programmatically configure containers.
This blog posts shows how to configure PostgreSQL container to log SQL queries, but you can use similar approach to other containers and use cases.
By default, Postgres does not log any queries. It can be configured by switching the log_statement configuration property to all. In similar way, if you want to log all incoming connections - switch log_connections to on. To log disconnections log_disconnections to on. There are quite a few logging related configuration options, I recommend looking into the official PostgreSQL docs.
To put it all together, to run Postgres with Docker and log all connections and statements, run following command:
$ docker run -p 5432:5432 -e POSTGRES_PASSWORD=password postgres:13.3 -c log_connections=on -c log_disconnections=on -c log_statement=allLet's now see how it can be translated to Testcontainers.
Testcontainers comes higher level module for Postgres which saves us from any low level coding - if we want to stick to defaults:
java
try (var postgres = new PostgreSQLContainer("postgres:13.3")) {
postgres.start();
}Under the hood, Testcontainers run Postgres with command postgres -c fsync=off to speed up startup time (see more).
To enable logging, we need to modify Docker command:
java
try (var postgres = new PostgreSQLContainer("postgres:13.3")) {
postgres.setCommand("postgres", "-c", "fsync=off", "-c", "log_statement=all");
postgres.start();
}Now we can hook into container and capture its logs.
java
postgres.followOutput(<consumer>);If you use Slf4j, you can just pipe container logs into an Slf4j logger:
java
Logger LOGGER = LoggerFactory.getLogger(MyComponent.class);
//...
try (var postgres = new PostgreSQLContainer("postgres:13.3")) {
postgres.setCommand("postgres", "-c", "fsync=off", "-c", "log_statement=all");
postgres.start();
postgres.followOutput(new Slf4jLogConsumer(LOGGER));
}Note that followOutput must be called after container is started. Which also means that you will not get this way access to container startup logs that happen before postgres.start() method finished. To do it call postgres.getLogs() before followOutput(..).
java
Logger LOGGER = LoggerFactory.getLogger(MyComponent.class);
//...
try (var postgres = new PostgreSQLContainer("postgres:13.3")) {
postgres.setCommand("postgres", "-c", "fsync=off", "-c", "log_statement=all");
postgres.start();
LOGGER.debug(postgres.getLogs()); // prints startup logs
postgres.followOutput(new Slf4jLogConsumer(LOGGER));
}There is a chance that you want only selection of logs from Postgres to appear in your logs and you need some kind of filtering. Container#followOutput take simple Java Consumer as a parameter making it easy to plug in filtering:
java
public class FilteringConsumer implements Consumer<OutputFrame> {
private final Consumer<OutputFrame> delegate;
private final Predicate<OutputFrame> predicate;
public FilteringConsumer(Predicate<OutputFrame> predicate, Consumer<OutputFrame> delegate) {
this.delegate = delegate;
this.predicate = predicate;
}
@Override
public void accept(OutputFrame outputFrame) {
if (predicate.test(outputFrame)) {
delegate.accept(outputFrame);
}
}
}And then instead of using Sfl4jLogConsumer directly, we set it as a delegate of FilteringConsumer:
java
// likely you will use more sophisticated predicate than that
postgres.followOutput(new FilteringConsumer(frame -> frame.getUtf8String().contains("select"), new Slf4jLogConsumer(LOGGER)));That's it!
Let's stay in touch and follow me on Twitter: @maciejwalkowiak
Subscribe to RSS feed ![]()
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。