Skip to content

Commit

Permalink
Merge pull request #233 from outofcoffee/feature/compose-child-logs
Browse files Browse the repository at this point in the history
Adds the ability to tail child container logs.
  • Loading branch information
rnorth committed Nov 8, 2016
2 parents 4e284ec + 7e5b8dc commit 292d012
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.slf4j.LoggerFactory;
import org.slf4j.profiler.Profiler;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.output.OutputFrame;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.containers.startupcheck.IndefiniteWaitOneShotStartupCheckStrategy;
import org.testcontainers.utility.*;
Expand Down Expand Up @@ -49,6 +50,8 @@ public class DockerComposeContainer<SELF extends DockerComposeContainer<SELF>> e
private Map<String, Integer> scalingPreferences = new HashMap<>();
private DockerClient dockerClient;
private boolean localCompose;
private boolean pull = true;
private boolean tailChildContainers;

private static final Object MUTEX = new Object();

Expand Down Expand Up @@ -99,9 +102,14 @@ public void starting(Description description) {
profiler.start("Docker Compose container startup");

synchronized (MUTEX) {
pullImages();
if (pull) {
pullImages();
}
applyScaling(); // scale before up, so that all scaled instances are available first for linking
createServices();
if (tailChildContainers) {
tailChildContainerLogs();
}
registerContainersForShutdown();
startAmbassadorContainers(profiler);
}
Expand All @@ -119,6 +127,16 @@ private void createServices() {
.start();
}

private void tailChildContainerLogs() {
listChildContainers().forEach(container ->
LogUtils.followOutput(dockerClient,
container.getId(),
new Slf4jLogConsumer(logger()).withPrefix(container.getNames()[0]),
OutputFrame.OutputType.STDOUT,
OutputFrame.OutputType.STDERR)
);
}

private DockerCompose getDockerCompose(String cmd) {
final DockerCompose dockerCompose;
if (localCompose) {
Expand Down Expand Up @@ -147,10 +165,7 @@ private void applyScaling() {
private void registerContainersForShutdown() {
// Ensure that all service containers that were launched by compose will be killed at shutdown
try {
List<Container> containers = dockerClient.listContainersCmd()
.withLabelFilter("name=/" + identifier)
.withShowAll(true)
.exec();
final List<Container> containers = listChildContainers();

// register with ResourceReaper to ensure final shutdown with JVM
containers.forEach(container ->
Expand All @@ -175,6 +190,15 @@ private void registerContainersForShutdown() {
}
}

private List<Container> listChildContainers() {
return dockerClient.listContainersCmd()
.withShowAll(true)
.exec().stream()
.filter(container -> Arrays.stream(container.getNames()).anyMatch(name ->
name.startsWith("/" + identifier)))
.collect(Collectors.toList());
}

private void startAmbassadorContainers(Profiler profiler) {
for (final Map.Entry<String, AmbassadorContainer> address : ambassadorContainers.entrySet()) {

Expand Down Expand Up @@ -315,6 +339,26 @@ public SELF withLocalCompose(boolean localCompose) {
return self();
}

/**
* Whether to pull images first.
*
* @return this instance, for chaining
*/
public SELF withPull(boolean pull) {
this.pull = pull;
return self();
}

/**
* Whether to tail child container logs.
*
* @return this instance, for chaining
*/
public SELF withTailChildContainers(boolean tailChildContainers) {
this.tailChildContainers = tailChildContainers;
return self();
}

private SELF self() {
return (SELF) this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.command.LogContainerCmd;
import com.github.dockerjava.api.exception.DockerException;
import com.github.dockerjava.api.model.*;
import com.google.common.base.Preconditions;
Expand Down Expand Up @@ -770,17 +769,7 @@ public void followOutput(Consumer<OutputFrame> consumer) {
*/
@Override
public void followOutput(Consumer<OutputFrame> consumer, OutputFrame.OutputType... types) {
LogContainerCmd cmd = dockerClient.logContainerCmd(containerId)
.withFollowStream(true);

FrameConsumerResultCallback callback = new FrameConsumerResultCallback();
for (OutputFrame.OutputType type : types) {
callback.addConsumer(type, consumer);
if (type == STDOUT) cmd.withStdOut(true);
if (type == STDERR) cmd.withStdErr(true);
}

cmd.exec(callback);
LogUtils.followOutput(dockerClient, containerId, consumer, types);
}

/**
Expand Down
37 changes: 37 additions & 0 deletions core/src/main/java/org/testcontainers/utility/LogUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.testcontainers.utility;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.LogContainerCmd;
import lombok.experimental.UtilityClass;
import org.testcontainers.containers.output.FrameConsumerResultCallback;
import org.testcontainers.containers.output.OutputFrame;

import java.util.function.Consumer;

import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR;
import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT;

/**
* Provides utility methods for logging.
*/
@UtilityClass
public class LogUtils {
/**
* {@inheritDoc}
*/
public void followOutput(DockerClient dockerClient, String containerId,
Consumer<OutputFrame> consumer, OutputFrame.OutputType... types) {

final LogContainerCmd cmd = dockerClient.logContainerCmd(containerId)
.withFollowStream(true);

final FrameConsumerResultCallback callback = new FrameConsumerResultCallback();
for (OutputFrame.OutputType type : types) {
callback.addConsumer(type, consumer);
if (type == STDOUT) cmd.withStdOut(true);
if (type == STDERR) cmd.withStdErr(true);
}

cmd.exec(callback);
}
}

0 comments on commit 292d012

Please sign in to comment.