docs/features/container_logs.md
It is possible to capture container output using:
getLogs() method, which simply returns a String snapshot of a container's entire log outputfollowOutput() method. This method accepts a Consumer and (optionally)
a varargs list stating which of STDOUT, STDERR, or both, should be followed. If not specified, both will be followed.At present, container output will always begin from the time of container creation.
getLogs() is the simplest mechanism for accessing container logs, and can be used as follows:
Accessing all output (stdout and stderr) inside_block:docsGetAllLogs
<!--/codeinclude--> <!--codeinclude-->Accessing just stdout inside_block:docsGetStdOut
<!--/codeinclude--> <!--codeinclude-->Accessing just stderr inside_block:docsGetStdErr
<!--/codeinclude-->Testcontainers includes some out-of-the-box Consumer implementations that can be used with the streaming followOutput() model; examples follow.
Given an existing SLF4J logger instance named LOGGER:
Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER);
container.followOutput(logConsumer);
By default both standard out and standard error will both be emitted at INFO level. Standard error may be emitted at ERROR level, if desired:
Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER).withSeparateOutputStreams();
The Mapped Diagnostic Context (MDC) for emitted messages may be configured using the withMdc(...) option:
Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER).withMdc("key", "value");
or using an existing map of key-value pairs:
Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER).withMdc(map);
To stream logs live or customize the decoding, ToStringConsumer may be used:
ToStringConsumer toStringConsumer = new ToStringConsumer();
container.followOutput(toStringConsumer, OutputType.STDOUT);
String utf8String = toStringConsumer.toUtf8String();
// Or if the container output is not UTF-8
String otherString = toStringConsumer.toString(CharSet.forName("ISO-8859-1"));
WaitingConsumer will block until a frame of container output (usually a line) matches a provided predicate.
A timeout may be specified, as shown in this example.
WaitingConsumer consumer = new WaitingConsumer();
container.followOutput(consumer, STDOUT);
consumer.waitUntil(frame ->
frame.getUtf8String().contains("STARTED"), 30, TimeUnit.SECONDS);
Additionally, as the Java 8 Consumer functional interface is used, Consumers may be composed together. This is useful, for example, to capture all the container output but only when a matching string has been found. e.g.:
WaitingConsumer waitingConsumer = new WaitingConsumer();
ToStringConsumer toStringConsumer = new ToStringConsumer();
Consumer<OutputFrame> composedConsumer = toStringConsumer.andThen(waitingConsumer);
container.followOutput(composedConsumer);
waitingConsumer.waitUntil(frame ->
frame.getUtf8String().contains("STARTED"), 30, TimeUnit.SECONDS);
String utf8String = toStringConsumer.toUtf8String();