Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove extra newlines in container log output #3752

Merged
merged 2 commits into from Feb 10, 2021

Conversation

perlun
Copy link
Contributor

@perlun perlun commented Feb 2, 2021

stringBuffer.write(outputFrame.getBytes());
stringBuffer.flush();
firstLine = false;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This essentially reverts the change done here: https://github.com/testcontainers/testcontainers-java/pull/643/files#diff-321431024ed34199142ebf2d70a46ba89f8a09e66582d40527885123e429b4d9R22-R24

It's not entirely clear to me if this will work for all use cases; it could very well be that this breaks (so it might be that we'll have to conditionalize it). I was unable to run all the tests locally, so maybe CI will shed some light on this.

@perlun
Copy link
Contributor Author

perlun commented Feb 5, 2021

@bsideup Any progress on this? We are seeing some intermittent failures in our CI tests, and it would be interesting to see if this (the extra newline being added after each logging frame) could be a potential root cause. Thanks in advance. 🙇

@bsideup
Copy link
Member

bsideup commented Feb 5, 2021

@perlun we're currently at low capacity and trying to catch up with some old PRs first, unless something is broken. Since there is a workaround (including a custom consumer), I am afraid we need a bit more time to get to this PR, but eventually we will, I promise! :D

@perlun
Copy link
Contributor Author

perlun commented Feb 5, 2021

@bsideup Thanks, that's perfectly understandable. I know how it can be at times. 👍

For my particular use case (using a WaitingConsumer), I unfortunately don't have any workaround. (and looking at the WaitingConsumer code I wonder if it's even affected by this issue; its accept method doesn't do any strange newline adding at all)

So, my problem is: We have a WaitingConsumer which intermittently fails in CI. Even in cases where the log message it's waiting for is actually printed, it sometimes fails. Any ideas? (We have a fairly high timeout in this case, 120 seconds)

@bsideup
Copy link
Member

bsideup commented Feb 5, 2021

@perlun have you tried adjusting the pattern so that it ignores newlines?

@perlun
Copy link
Contributor Author

perlun commented Feb 8, 2021

@perlun have you tried adjusting the pattern so that it ignores newlines?

To make things more complex, I have my own WaitStrategy to avoid having to write regexps for this; it uses a String.contains()-based approach instead. Below is the full code for it.

One ugly workaround I thought about: use the retryUntilSuccess-approach and get the whole log every time (instead of waiting for one frame, then continuing). Unsure if it would help though, if the extra newlines are still there. 😅 Any suggestions in any directions whatsoever would be highly appreciated.

public class LogMessageContainsWaitStrategy extends AbstractWaitStrategy {

    private static final int TIMES = 1;

    private final String needle;

    public LogMessageContainsWaitStrategy( String needle ) {
        this.needle = needle;
    }

    @Override
    protected void waitUntilReady() {
        WaitingConsumer waitingConsumer = new WaitingConsumer();

        LogContainerCmd cmd = DockerClientFactory.instance().client().logContainerCmd( waitStrategyTarget.getContainerId() )
                .withFollowStream( true )
                .withSince( 0 )
                .withStdOut( true )
                .withStdErr( true );

        try ( FrameConsumerResultCallback callback = new FrameConsumerResultCallback() ) {
            callback.addConsumer( STDOUT, waitingConsumer );
            callback.addConsumer( STDERR, waitingConsumer );

            cmd.exec( callback );

            // This is the actual predicate that gets checked each time a new output frame is received
            Predicate<OutputFrame> waitPredicate = outputFrame ->
                    outputFrame.getUtf8String().contains( needle );

            try {
                waitingConsumer.waitUntil( waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, TIMES );
            }
            catch ( TimeoutException e ) {
                throw new ContainerLaunchException( "Timed out waiting for log output including '" + needle + "'" );
            }
        }
        catch ( IOException e ) {
            throw new UncheckedIOException( e );
        }
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + ", looking for log output including '" + needle + "'";
    }
}

@bsideup
Copy link
Member

bsideup commented Feb 10, 2021

@perlun I just applied some fixes and added more tests. Will merge once green 👍

@bsideup bsideup added this to the next milestone Feb 10, 2021
@bsideup bsideup merged commit 106463b into testcontainers:master Feb 10, 2021
@perlun perlun deleted the fix/remove-extra-newlines branch February 11, 2021 09:16
@perlun
Copy link
Contributor Author

perlun commented Feb 11, 2021

@perlun I just applied some fixes and added more tests. Will merge once green +1

Thanks a lot for this. 🙏 Let me know if/when we get a new release including this, and I'll happily test it on our code base to see it it resolves the intermittent issues we're seeing.

@bsideup
Copy link
Member

bsideup commented Feb 11, 2021

@perlun the release engines are running now :)

@perlun
Copy link
Contributor Author

perlun commented Feb 17, 2021

FWIW: this fix did not help me in my original problem (briefly described in #3752 (comment)). What did seem to help, at least to the point of removing spurious newlines in the Docker output is to create the container like this.

(In our particular case, the Docker output comes from a Tomcat container running a bunch of Java web applications, with SLF4J + Logback writing to stdout.)

        withCreateContainerCmdModifier( cmd -> cmd.withTty( true ) );

With this in place, I am no longer getting any spurious newlines in the middle of the logs. Posting this here in the help that it might help others as well.

@bsideup
Copy link
Member

bsideup commented Feb 17, 2021

Now this sounds more like a bug with Docker :D Anyways, I am glad that you were able to fix it 👍

@perlun
Copy link
Contributor Author

perlun commented Feb 17, 2021

Now this sounds more like a bug with Docker :D

It could very well be. I get the feeling that there is some kind of output buffering (auto-flushing disabled) going on, which is weird since the Logback ConsoleAppender does call System.out.flush() after each log line being written.

image

I even attached a debugger to the Tomcat inside the Docker container, with the Tomcat sources loaded so I could debug it. SystemLogHandler (in Tomcat) has an out field which is a PrintStream, with autoFlush enabled. So it's really weird.

(If anyone runs into the same problem and figures this out, please post the details here so we can all learn from it and benefit. 🙏)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants