Skip to content
This repository has been archived by the owner on Aug 30, 2023. It is now read-only.

feat: log request if response code is not 200 #484

Merged
merged 4 commits into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 58 additions & 77 deletions sentry-core/src/main/java/io/sentry/core/transport/HttpTransport.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import static io.sentry.core.SentryLevel.DEBUG;
import static io.sentry.core.SentryLevel.ERROR;
import static io.sentry.core.SentryLevel.INFO;
import static io.sentry.core.SentryLevel.WARNING;
import static java.net.HttpURLConnection.HTTP_OK;

import com.jakewharton.nopen.annotation.Open;
import io.sentry.core.ILogger;
Expand Down Expand Up @@ -160,25 +160,20 @@ public HttpTransport(
@Override
public @NotNull TransportResult send(final @NotNull SentryEvent event) throws IOException {
final HttpURLConnection connection = createConnection(false);

int responseCode = -1;
TransportResult result;

try (final OutputStream outputStream = connection.getOutputStream();
final GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
final Writer writer = new BufferedWriter(new OutputStreamWriter(gzip, UTF_8))) {
serializer.serialize(event, writer);

logger.log(DEBUG, "Event sent %s successfully.", event.getEventId());
return TransportResult.success();
} catch (IOException e) {
final TransportResult errorResult = getResultFromErrorCode(connection, e);
responseCode = errorResult.getResponseCode();
return errorResult;
logger.log(
ERROR, e, "An exception occurred while submitting the event to the Sentry server.");
} finally {
updateRetryAfterLimits(connection, responseCode);

closeAndDisconnect(connection);
result =
readAndLog(connection, String.format("Event sent %s successfully.", event.getEventId()));
}
return result;
}

/**
Expand Down Expand Up @@ -256,6 +251,7 @@ public boolean isRetryAfter(final @NotNull String itemType) {

connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setChunkedStreamingMode(0);
marandaneto marked this conversation as resolved.
Show resolved Hide resolved

connection.setRequestProperty("Content-Encoding", "gzip");
connection.setRequestProperty("Content-Type", contentType);
Expand All @@ -278,78 +274,72 @@ public boolean isRetryAfter(final @NotNull String itemType) {
@Override
public @NotNull TransportResult send(final @NotNull SentryEnvelope envelope) throws IOException {
final HttpURLConnection connection = createConnection(true);

int responseCode = -1;
TransportResult result;

try (final OutputStream outputStream = connection.getOutputStream();
final GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
final Writer writer = new BufferedWriter(new OutputStreamWriter(gzip, UTF_8))) {
serializer.serialize(envelope, writer);

logger.log(DEBUG, "Envelope sent successfully.");
marandaneto marked this conversation as resolved.
Show resolved Hide resolved
return TransportResult.success();
} catch (IOException e) {
final TransportResult errorResult = getResultFromErrorCode(connection, e);
responseCode = errorResult.getResponseCode();
return errorResult;
} catch (Exception e) {
return getDefaultErrorResult(e);
logger.log(
ERROR, e, "An exception occurred while submitting the envelope to the Sentry server.");
} finally {
updateRetryAfterLimits(connection, responseCode);

closeAndDisconnect(connection);
result = readAndLog(connection, "Envelope sent successfully.");
}
return result;
}

/**
* Closes the Response stream and disconnect the connection
* Read responde code, retry after header and its error stream if there are errors and log it
*
* @param connection the HttpURLConnection
* @param message the message, if custom message if its an event or envelope
* @return TransportResult.success if responseCode is 200 or TransportResult.error otherwise
*/
private void closeAndDisconnect(final @NotNull HttpURLConnection connection) {
private @NotNull TransportResult readAndLog(
final @NotNull HttpURLConnection connection, final @NotNull String message) {
try {
connection.getInputStream().close();
final int responseCode = connection.getResponseCode();

updateRetryAfterLimits(connection, responseCode);

if (!isSuccessfulResponseCode(responseCode)) {
logger.log(ERROR, "Request failed, API returned %s", responseCode);
// double check because call is expensive
if (options.isDebug()) {
String errorMessage = getErrorMessageFromStream(connection);
logger.log(ERROR, errorMessage);
}

return TransportResult.error(responseCode);
}

logger.log(DEBUG, message);

return TransportResult.success();
} catch (IOException e) {
logger.log(ERROR, e, "Error while closing the connection.");
logger.log(ERROR, e, "Error reading and logging the response stream");
} finally {
connection.disconnect();
closeAndDisconnect(connection);
}
return TransportResult.error();
}

/**
* Returns a TransportResult error with the given responseCode
* Closes the Response stream and disconnect the connection
*
* @param connection the HttpURLConnection
* @param ioException the IOException
* @return the TransportResult error
*/
private @NotNull TransportResult getResultFromErrorCode(
final @NotNull HttpURLConnection connection, final @NotNull IOException ioException) {
private void closeAndDisconnect(final @NotNull HttpURLConnection connection) {
try {
final int responseCode = connection.getResponseCode();

logErrorInPayload(connection);
return TransportResult.error(responseCode);
} catch (IOException responseCodeException) {
logger.log(ERROR, responseCodeException, "Error getting responseCode");

// this should not stop us from continuing.
return getDefaultErrorResult(ioException);
connection.getInputStream().close();
} catch (IOException ignored) {
// connection is already closed
} finally {
connection.disconnect();
}
}

/**
* Logs a default error message and return the TransportResult error with -1 responseCode
*
* @param exception the Exception
* @return the TransportResult error
*/
private @NotNull TransportResult getDefaultErrorResult(final @NotNull Exception exception) {
logger.log(
WARNING, "Failed to obtain error message while analyzing event send failure.", exception);
return TransportResult.error();
}

/**
* Read retry after headers and update the rate limit Dictionary
*
Expand Down Expand Up @@ -470,31 +460,13 @@ private long parseRetryAfterOrDefault(final @Nullable String retryAfterHeader) {
return retryAfterMillis;
}

/**
* Logs the error message from the ErrorStream
*
* @param connection the HttpURLConnection
*/
private void logErrorInPayload(final @NotNull HttpURLConnection connection) {
// just because its expensive, but internally isDebug is already checked when
// .log() is called
if (options.isDebug()) {
String errorMessage = getErrorMessageFromStream(connection);
if (null == errorMessage || errorMessage.isEmpty()) {
errorMessage = "An exception occurred while submitting the event to the Sentry server.";
}

logger.log(DEBUG, errorMessage);
}
}

/**
* Reads the error message from the error stream
*
* @param connection the HttpURLConnection
* @return the error message or null if none
*/
private @Nullable String getErrorMessageFromStream(final @NotNull HttpURLConnection connection) {
private @NotNull String getErrorMessageFromStream(final @NotNull HttpURLConnection connection) {
try (final InputStream errorStream = connection.getErrorStream();
final BufferedReader reader =
new BufferedReader(new InputStreamReader(errorStream, UTF_8))) {
Expand All @@ -511,9 +483,18 @@ private void logErrorInPayload(final @NotNull HttpURLConnection connection) {
}
return sb.toString();
} catch (IOException e) {
logger.log(ERROR, e, "Exception while reading the error message from the connection");
return "Failed to obtain error message while analyzing send failure.";
}
return null;
}

/**
* Returns if response code is OK=200
*
* @param responseCode the response code
* @return true if it is OK=200 or false otherwise
*/
private boolean isSuccessfulResponseCode(final int responseCode) {
return responseCode == HTTP_OK;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class HttpTransportTest {
@Test
fun `test serializes event`() {
val transport = fixture.getSUT()
whenever(fixture.connection.responseCode).thenReturn(200)

val event = SentryEvent()

Expand All @@ -73,6 +74,7 @@ class HttpTransportTest {
@Test
fun `test serializes envelope`() {
val transport = fixture.getSUT()
whenever(fixture.connection.responseCode).thenReturn(200)

val envelope = SentryEnvelope.fromSession(fixture.serializer, createSession())

Expand Down