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 support of logging in object level #3501

Open
wants to merge 12 commits into
base: trunk
Choose a base branch
from
Open
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
13 changes: 13 additions & 0 deletions retrofit-logger/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Retrofit Logger
===================

Retrofit ships with support for object level logging to increase readability for case like response is binary so we can't log in OkHttp layer.

To use, supply an instance of your desired logger when building your `Retrofit` instance.

```java
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com")
.setObjectLogger(GsonLogger.create())
.build();
```
1 change: 1 addition & 0 deletions retrofit-logger/gson/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
6 changes: 6 additions & 0 deletions retrofit-logger/gson/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apply plugin: 'java-library'

dependencies {
implementation project(':retrofit')
api deps.gson
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package retrofit2.logger.gson;

import com.google.gson.Gson;
import okhttp3.Request;
import retrofit2.ObjectLogger;

public class GsonLogger implements ObjectLogger {
private final Gson gson;

public static GsonLogger create() {
return create(new Gson());
}

@SuppressWarnings("ConstantConditions") // Guarding public API nullability.
public static GsonLogger create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
return new GsonLogger(gson);
}

private GsonLogger(Gson gson) {
this.gson = gson;
}

@Override
public void log(Request request, Object obj) {
System.out.println("Request = ");
System.out.println(request.url().toString());
System.out.println("Response = ");
System.out.println(gson.toJson(obj));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@retrofit2.internal.EverythingIsNonNull
package retrofit.logger;
9 changes: 9 additions & 0 deletions retrofit/src/main/java/retrofit2/EmptyLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package retrofit2;

import okhttp3.Request;

public class EmptyLogger implements ObjectLogger {

@Override
public void log(Request request, Object obj) {}
}
32 changes: 21 additions & 11 deletions retrofit/src/main/java/retrofit2/HttpServiceMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,19 @@ static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotatio

Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);

ObjectLogger logger = retrofit.logger;
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter, logger);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
logger);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
Expand All @@ -103,6 +104,7 @@ static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotatio
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
logger,
continuationBodyNullable);
}
}
Expand Down Expand Up @@ -130,20 +132,25 @@ private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConv
private final RequestFactory requestFactory;
private final okhttp3.Call.Factory callFactory;
private final Converter<ResponseBody, ResponseT> responseConverter;
private final ObjectLogger logger;

HttpServiceMethod(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter) {
Converter<ResponseBody, ResponseT> responseConverter,
ObjectLogger logger) {
this.requestFactory = requestFactory;
this.callFactory = callFactory;
this.responseConverter = responseConverter;
this.logger = logger;
}

@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
Call<ResponseT> call =
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter, logger);
ReturnT result = adapt(call, args);
return result;
}

protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
Expand All @@ -155,8 +162,9 @@ static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<Res
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
CallAdapter<ResponseT, ReturnT> callAdapter,
ObjectLogger logger) {
super(requestFactory, callFactory, responseConverter, logger);
this.callAdapter = callAdapter;
}

Expand All @@ -173,8 +181,9 @@ static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<Respo
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, Call<ResponseT>> callAdapter) {
super(requestFactory, callFactory, responseConverter);
CallAdapter<ResponseT, Call<ResponseT>> callAdapter,
ObjectLogger logger) {
super(requestFactory, callFactory, responseConverter, logger);
this.callAdapter = callAdapter;
}

Expand Down Expand Up @@ -204,8 +213,9 @@ static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, Call<ResponseT>> callAdapter,
ObjectLogger logger,
boolean isNullable) {
super(requestFactory, callFactory, responseConverter);
super(requestFactory, callFactory, responseConverter, logger);
this.callAdapter = callAdapter;
this.isNullable = isNullable;
}
Expand Down
8 changes: 8 additions & 0 deletions retrofit/src/main/java/retrofit2/ObjectLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package retrofit2;

import okhttp3.Request;

public interface ObjectLogger {

void log(Request request, Object obj);
}
16 changes: 13 additions & 3 deletions retrofit/src/main/java/retrofit2/OkHttpCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ final class OkHttpCall<T> implements Call<T> {
private final Object[] args;
private final okhttp3.Call.Factory callFactory;
private final Converter<ResponseBody, T> responseConverter;
private final ObjectLogger logger;

private volatile boolean canceled;

Expand All @@ -51,17 +52,19 @@ final class OkHttpCall<T> implements Call<T> {
RequestFactory requestFactory,
Object[] args,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, T> responseConverter) {
Converter<ResponseBody, T> responseConverter,
ObjectLogger logger) {
this.requestFactory = requestFactory;
this.args = args;
this.callFactory = callFactory;
this.responseConverter = responseConverter;
this.logger = logger;
}

@SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
@Override
public OkHttpCall<T> clone() {
return new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return new OkHttpCall<>(requestFactory, args, callFactory, responseConverter, logger);
}

@Override
Expand Down Expand Up @@ -151,6 +154,9 @@ public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
if (response.body() != null) {
logger.log(call.request(), response.body());
}
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
Expand Down Expand Up @@ -201,7 +207,11 @@ public Response<T> execute() throws IOException {
call.cancel();
}

return parseResponse(call.execute());
Response<T> response = parseResponse(call.execute());
if (response.body() != null) {
logger.log(call.request(), response.body());
}
return response;
}

private okhttp3.Call createRawCall() throws IOException {
Expand Down
15 changes: 15 additions & 0 deletions retrofit/src/main/java/retrofit2/Retrofit.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,22 @@ public final class Retrofit {
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
final ObjectLogger logger;

Retrofit(
okhttp3.Call.Factory callFactory,
HttpUrl baseUrl,
List<Converter.Factory> converterFactories,
List<CallAdapter.Factory> callAdapterFactories,
@Nullable Executor callbackExecutor,
ObjectLogger logger,
boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
this.callbackExecutor = callbackExecutor;
this.logger = logger;
this.validateEagerly = validateEagerly;
}

Expand Down Expand Up @@ -431,6 +434,7 @@ public static final class Builder {
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private @Nullable ObjectLogger logger;
private boolean validateEagerly;

Builder(Platform platform) {
Expand Down Expand Up @@ -581,6 +585,11 @@ public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
return this;
}

public Builder setObjectLogger(ObjectLogger logger) {
this.logger = logger;
return this;
}

/**
* The executor on which {@link Callback} methods are invoked when returning {@link Call} from
* your service method.
Expand Down Expand Up @@ -648,12 +657,18 @@ public Retrofit build() {
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());

ObjectLogger logger = this.logger;
if (logger == null) {
logger = new EmptyLogger();
}

return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
logger,
validateEagerly);
}
}
Expand Down
1 change: 1 addition & 0 deletions samples/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dependencies {
implementation project(':retrofit-converters:gson')
implementation project(':retrofit-converters:simplexml')
implementation project(':retrofit-adapters:rxjava')
implementation project(':retrofit-logger:gson')
implementation deps.mockwebserver
implementation deps.guava
implementation deps.jsoup
Expand Down
2 changes: 2 additions & 0 deletions samples/src/main/java/com/example/retrofit/SimpleService.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.logger.gson.GsonLogger;

public final class SimpleService {
public static final String API_URL = "https://api.github.com";
Expand All @@ -46,6 +47,7 @@ public static void main(String... args) throws IOException {
Retrofit retrofit =
new Retrofit.Builder()
.baseUrl(API_URL)
.setObjectLogger(GsonLogger.create())
.addConverterFactory(GsonConverterFactory.create())
.build();

Expand Down
3 changes: 3 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ include ':retrofit-converters:scalars'
include ':retrofit-converters:simplexml'
include ':retrofit-converters:wire'

include ':retrofit-logger:gson'

include ':samples'