Skip to content

Commit

Permalink
Merge pull request #212 from palantir/better-docker-compose-logging
Browse files Browse the repository at this point in the history
Better error logging
  • Loading branch information
CRogers authored Oct 4, 2017
2 parents 3e1b9e8 + f864629 commit c31d968
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,8 @@ public SuccessOrFailure portIsListeningOnHttp(int internalPort, Function<DockerP
if (!port.isListeningNow()) {
return SuccessOrFailure.failure(internalPort + " is not listening");
}
if (!port.isHttpResponding(urlFunction, andCheckStatus)) {
return SuccessOrFailure.failure(internalPort + " does not have a http response from " + urlFunction.apply(port));
}
return SuccessOrFailure.success();
return port.isHttpRespondingSuccessfully(urlFunction, andCheckStatus)
.mapFailure(failureMessage -> internalPort + " does not have a http response from " + urlFunction.apply(port) + ":\n" + failureMessage);
} catch (Exception e) {
return SuccessOrFailure.fromException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.palantir.docker.compose.connection;

import com.palantir.docker.compose.connection.waiting.SuccessOrFailure;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetSocketAddress;
Expand Down Expand Up @@ -67,6 +68,10 @@ public boolean isListeningNow() {
}

public boolean isHttpResponding(Function<DockerPort, String> urlFunction, boolean andCheckStatus) {
return isHttpRespondingSuccessfully(urlFunction, andCheckStatus).succeeded();
}

public SuccessOrFailure isHttpRespondingSuccessfully(Function<DockerPort, String> urlFunction, boolean andCheckStatus) {
URL url;
try {
String urlString = urlFunction.apply(this);
Expand All @@ -79,19 +84,15 @@ public boolean isHttpResponding(Function<DockerPort, String> urlFunction, boolea
url.openConnection().connect();
url.openStream().read();
log.debug("Http connection acquired, assuming port active");
return true;
return SuccessOrFailure.success();
} catch (SocketException e) {
log.trace("Failed to acquire http connection, assuming port inactive", e);
return false;
return SuccessOrFailure.failureWithCondensedException("Failed to acquire http connection, assuming port inactive", e);
} catch (FileNotFoundException e) {
log.debug("Received 404, assuming port active");
return !andCheckStatus;
return SuccessOrFailure.fromBoolean(!andCheckStatus, "Received 404, assuming port inactive: " + e.getMessage());
} catch (SSLHandshakeException e) {
log.debug("Received bad SSL response, assuming port inactive");
return false;
return SuccessOrFailure.failureWithCondensedException("Received bad SSL response, assuming port inactive", e);
} catch (IOException e) {
log.trace("Error acquiring http connection, assuming port open but inactive", e);
return false;
return SuccessOrFailure.failureWithCondensedException("Error acquiring http connection, assuming port open but inactive", e);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2016 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.palantir.docker.compose.connection.waiting;

import java.util.stream.Collectors;
import org.apache.commons.lang3.exception.ExceptionUtils;

public enum Exceptions {
;

public static String condensedStacktraceFor(Throwable throwable) {
return ExceptionUtils.getThrowableList(throwable).stream()
.map(t -> t.getClass().getCanonicalName() + ": " + t.getMessage())
.collect(Collectors.joining("\n"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.palantir.docker.compose.connection.waiting;

import java.util.Optional;
import java.util.function.Function;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.immutables.value.Value;

Expand All @@ -29,6 +30,14 @@ public static SuccessOrFailure onResultOf(Attempt attempt) {
}
}

public SuccessOrFailure mapFailure(Function<String, String> mapper) {
if (this.succeeded()) {
return this;
} else {
return failure(mapper.apply(failureMessage()));
}
}

@Value.Parameter protected abstract Optional<String> optionalFailureMessage();

public static SuccessOrFailure success() {
Expand All @@ -39,6 +48,10 @@ public static SuccessOrFailure failure(String message) {
return ImmutableSuccessOrFailure.of(Optional.of(message));
}

public static SuccessOrFailure failureWithCondensedException(String message, Exception exception) {
return failure(message + ":\n" + Exceptions.condensedStacktraceFor(exception));
}

public static SuccessOrFailure fromBoolean(boolean succeeded, String possibleFailureMessage) {
if (succeeded) {
return success();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import com.palantir.docker.compose.connection.DockerPort;
import com.palantir.docker.compose.connection.Ports;
import com.palantir.docker.compose.connection.waiting.SuccessOrFailure;
import com.palantir.docker.compose.execution.DockerCompose;
import java.io.IOException;
import java.util.Arrays;
Expand Down Expand Up @@ -52,6 +53,7 @@ public DockerPort unavailableService(String service, String ip, int externalPort
public DockerPort availableHttpService(String service, String ip, int externalPortNumber, int internalPortNumber) throws Exception {
DockerPort port = availableService(service, ip, externalPortNumber, internalPortNumber);
doReturn(true).when(port).isHttpResponding(any(), eq(false));
doReturn(SuccessOrFailure.success()).when(port).isHttpRespondingSuccessfully(any(), eq(false));
return port;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2016 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.palantir.docker.compose.connection.waiting;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

import org.junit.Test;

public class ExceptionsShould {
@Test
public void print_out_a_condensed_version_of_the_stacktrace() {
RuntimeException exception = new RuntimeException("foo", new IllegalStateException("bar", new UnsupportedOperationException("baz")));
assertThat(Exceptions.condensedStacktraceFor(exception), is(
"java.lang.RuntimeException: foo\n"
+ "java.lang.IllegalStateException: bar\n"
+ "java.lang.UnsupportedOperationException: baz"
));
}
}

0 comments on commit c31d968

Please sign in to comment.