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

Add headers-only logging level. #269

Merged
merged 1 commit into from
Jul 12, 2013
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
137 changes: 74 additions & 63 deletions retrofit/src/main/java/retrofit/RestAdapter.java
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
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) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: could be one line.

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