Skip to content

Commit

Permalink
Add headers-only logging level.
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeWharton committed Jul 12, 2013
1 parent 97970a1 commit 5436368
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 94 deletions.
137 changes: 74 additions & 63 deletions retrofit/src/main/java/retrofit/RestAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package retrofit;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -119,6 +118,8 @@ public enum LogLevel {
NONE,
/** Log only the request method and URL and the response status code and execution time. */
BASIC,
/** Log the basic information along with request and response headers. */
HEADERS,
/** Log the headers, body, and metadata for both requests and responses. */
FULL
}
Expand Down Expand Up @@ -246,10 +247,9 @@ private Object invokeRequest(RestMethodInfo methodDetails, Object[] args) {
Thread.currentThread().setName(THREAD_PREFIX + url.substring(serverUrl.length()));
}

if (logLevel == LogLevel.FULL) {
if (logLevel.ordinal() > LogLevel.NONE.ordinal()) {
// Log the request data.
request = logAndReplaceRequest(request);
} else if (logLevel == LogLevel.BASIC) {
logRequestLine(request);
}

Object profilerObject = null;
Expand All @@ -268,10 +268,9 @@ private Object invokeRequest(RestMethodInfo methodDetails, Object[] args) {
profiler.afterCall(requestInfo, elapsedTime, statusCode, profilerObject);
}

if (logLevel == LogLevel.FULL) {
if (logLevel.ordinal() > LogLevel.NONE.ordinal()) {
// Log the response data.
response = logAndReplaceResponse(url, response, elapsedTime);
} else if (logLevel == LogLevel.BASIC) {
logResponseLine(url, response, elapsedTime);
}

Type type = methodDetails.responseObjectType;
Expand Down Expand Up @@ -322,83 +321,95 @@ private Object invokeRequest(RestMethodInfo methodDetails, Object[] args) {
}
}

private void logRequestLine(Request request) {
/** Log request headers and body. Consumes request body and returns identical replacement. */
private Request logAndReplaceRequest(Request request) throws IOException {
log.log(String.format("---> HTTP %s %s", request.getMethod(), request.getUrl()));
}

private void logResponseLine(String url, Response response, long elapsedTime) {
log.log(String.format("<--- HTTP %s %s (%sms)", response.getStatus(), url, elapsedTime));
}
if (logLevel.ordinal() >= LogLevel.HEADERS.ordinal()) {
for (Header header : request.getHeaders()) {
log.log(header.getName() + ": " + header.getValue());
}

/** Log request headers and body. Consumes request body and returns identical replacement. */
private Request logAndReplaceRequest(Request request) throws IOException {
logRequestLine(request);
long bodySize = 0;
TypedOutput body = request.getBody();
if (body != null) {
bodySize = body.length();
String bodyMime = body.mimeType();

for (Header header : request.getHeaders()) {
log.log(header.getName() + ": " + header.getValue());
}
if (bodyMime != null) {
log.log("Content-Type: " + bodyMime);
}
if (bodySize != -1) {
log.log("Content-Length: " + bodySize);
}

TypedOutput body = request.getBody();
int bodySize = 0;
if (body != null) {
if (!request.getHeaders().isEmpty()) {
log.log("");
}
if (logLevel.ordinal() >= LogLevel.FULL.ordinal()) {
if (!request.getHeaders().isEmpty()) {
log.log("");
}
if (!(body instanceof TypedByteArray)) {
// Read the entire response body to we can log it and replace the original response
request = Utils.readBodyToBytesIfNecessary(request);
body = request.getBody();
}

ByteArrayOutputStream baos = new ByteArrayOutputStream();
body.writeTo(baos);
byte[] bodyBytes = baos.toByteArray();
bodySize = bodyBytes.length;
String bodyMime = body.mimeType();
String bodyString = new String(bodyBytes, MimeUtil.parseCharset(bodyMime));
for (int i = 0, len = bodyString.length(); i < len; i += LOG_CHUNK_SIZE) {
int end = Math.min(len, i + LOG_CHUNK_SIZE);
log.log(bodyString.substring(i, end));
byte[] bodyBytes = ((TypedByteArray) body).getBytes();
bodySize = bodyBytes.length;
String bodyCharset = MimeUtil.parseCharset(bodyMime);
String bodyString = new String(bodyBytes, bodyCharset);
for (int i = 0, len = bodyString.length(); i < len; i += LOG_CHUNK_SIZE) {
int end = Math.min(len, i + LOG_CHUNK_SIZE);
log.log(bodyString.substring(i, end));
}
}
}

body = new TypedByteArray(bodyMime, bodyBytes);
log.log(String.format("---> END HTTP (%s-byte body)", bodySize));
}

log.log(String.format("---> END HTTP (%s-byte body)", bodySize));

// Since we consumed the original request, return a new, identical one from its bytes.
return new Request(request.getMethod(), request.getUrl(), request.getHeaders(), body);
return request;
}

/** Log response headers and body. Consumes response body and returns identical replacement. */
private Response logAndReplaceResponse(String url, Response response, long elapsedTime)
throws IOException {
logResponseLine(url, response, elapsedTime);

for (Header header : response.getHeaders()) {
log.log(header.getName() + ": " + header.getValue());
}
log.log(String.format("<--- HTTP %s %s (%sms)", response.getStatus(), url, elapsedTime));

TypedInput body = response.getBody();
int bodySize = 0;
if (body != null) {
if (!response.getHeaders().isEmpty()) {
log.log("");
if (logLevel.ordinal() >= LogLevel.HEADERS.ordinal()) {
for (Header header : response.getHeaders()) {
log.log(header.getName() + ": " + header.getValue());
}

if (!(body instanceof TypedByteArray)) {
// Read the entire response body to we can log it and replace the original response
response = Utils.readBodyToBytesIfNecessary(response);
body = response.getBody();
}
long bodySize = 0;
TypedInput body = response.getBody();
if (body != null) {
bodySize = body.length();

byte[] bodyBytes = ((TypedByteArray) body).getBytes();
bodySize = bodyBytes.length;
String bodyMime = body.mimeType();
String bodyCharset = MimeUtil.parseCharset(bodyMime);
String bodyString = new String(bodyBytes, bodyCharset);
for (int i = 0, len = bodyString.length(); i < len; i += LOG_CHUNK_SIZE) {
int end = Math.min(len, i + LOG_CHUNK_SIZE);
log.log(bodyString.substring(i, end));
if (logLevel.ordinal() >= LogLevel.FULL.ordinal()) {
if (!response.getHeaders().isEmpty()) {
log.log("");
}

if (!(body instanceof TypedByteArray)) {
// Read the entire response body to we can log it and replace the original response
response = Utils.readBodyToBytesIfNecessary(response);
body = response.getBody();
}

byte[] bodyBytes = ((TypedByteArray) body).getBytes();
bodySize = bodyBytes.length;
String bodyMime = body.mimeType();
String bodyCharset = MimeUtil.parseCharset(bodyMime);
String bodyString = new String(bodyBytes, bodyCharset);
for (int i = 0, len = bodyString.length(); i < len; i += LOG_CHUNK_SIZE) {
int end = Math.min(len, i + LOG_CHUNK_SIZE);
log.log(bodyString.substring(i, end));
}
}
}
}

log.log(String.format("<--- END HTTP (%s-byte body)", bodySize));
log.log(String.format("<--- END HTTP (%s-byte body)", bodySize));
}

return response;
}
Expand Down
20 changes: 20 additions & 0 deletions retrofit/src/main/java/retrofit/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Executor;
import retrofit.client.Request;
import retrofit.client.Response;
import retrofit.mime.TypedByteArray;
import retrofit.mime.TypedInput;
import retrofit.mime.TypedOutput;

final class Utils {
private static final int BUFFER_SIZE = 0x1000;
Expand All @@ -45,6 +47,24 @@ static byte[] streamToBytes(InputStream stream) throws IOException {
return baos.toByteArray();
}

/**
* Conditionally replace a {@link Request} with an identical copy whose body is backed by a
* byte[] rather than an input stream.
*/
static Request readBodyToBytesIfNecessary(Request request) throws IOException {
TypedOutput body = request.getBody();
if (body == null || body instanceof TypedByteArray) {
return request;
}

String bodyMime = body.mimeType();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
body.writeTo(baos);
body = new TypedByteArray(bodyMime, baos.toByteArray());

return new Request(request.getMethod(), request.getUrl(), request.getHeaders(), body);
}

/**
* Conditionally replace a {@link Response} with an identical copy whose body is backed by a
* byte[] rather than an input stream.
Expand Down
Loading

0 comments on commit 5436368

Please sign in to comment.