4

I need to build a traffic monitor on my Android app, and I need to have stored the size of all json that I'm sending and receiving through retrofit. Using log I can see the actual size of it, but I haven't find a way to get this information so I could save it. I can't get the response.raw either since it's already been parsed to my classes. Is there any way to achieve that?

EDIT: Marked vadkou answer as the best one.

Instead of creating a new interceptor, I passed the lamda expression:

 httpClient.addInterceptor( chain -> {
        okhttp3.Request request = chain.request();
        okhttp3.Response response = chain.proceed(request);
        if(request.body()!=null) {
            long requestLength = request.body().contentLength();
            Log.e("SERVICE GENERATOR", " CONTENT LENGTH" + requestLength);

        }
        long responseLength = response.body().contentLength();
        Log.e("SERVICE GENERATOR", " RESPONSE LENGTH" + responseLength);

        return response;

    });
julioribeiro
  • 973
  • 1
  • 10
  • 20

3 Answers3

4

Retrofit 2 uses OkHttp internally, and you could configure OkHttp without having to resort to getting raw HTTP response as in Vaiden's answer by adding a custom Interceptor while building an adapter as follows:

private Retrofit createRetrofit() {
       return new Retrofit.Builder()
            .baseUrl(END_POINT)
       //     .addConverterFactory(...)
       //     .addCallAdapterFactory(...)
            .client(createClient())
            .build();
}

private OkHttpClient createClient() {
        OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
        okHttpClientBuilder.addInterceptor(createYourInterceptor());
        return okHttpClientBuilder.build();
}

The Interceptor interface among other things allows you to access request body for every request you make.

@Override
public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
            // do what you want with request.body().contentLength();
        return chain.proceed(request);
}
vadkou
  • 300
  • 2
  • 8
  • Niiiiiiiiiiiiice – Vaiden Jun 19 '17 at 12:00
  • I tried that, but the Request body is returning null and the contentLength() of the response always returns -1 everytime I log it. This is my lambda expression on the http interceptor. **httpClient.addInterceptor( chain -> { okhttp3.Request request = chain.request(); okhttp3.Response response = chain.proceed(request); long requestLength = request.body().contentLength(); long responseLength = response.body().contentLength(); return response; });** – julioribeiro Jun 19 '17 at 13:49
  • @julioribeiro what converter did you use? – vadkou Jun 19 '17 at 14:59
  • GsonConverterFactory. I don't use nothing special than this. Just build my RefrotiBuilder with the baseUrl, GsonConverterFactory, add loggin interceptor and now this lamda as a new interceptor. – julioribeiro Jun 19 '17 at 15:41
  • @julioribeiro could you check if the server actually receives any POST data? Perhaps a `@Body` annotation is missing on a method parameter. Also, as you are using Logging Interceptor, you should see the JSON body in logcat – vadkou Jun 19 '17 at 15:43
  • @vadkou Sorry for the delay, So on every POST that I make I'm able to get the Request Length with it's correct size. But response is always -1. When I perform a GET, my request is null and response is -1 as well. – julioribeiro Jun 19 '17 at 17:04
  • @julioribeiro Retrofit doesn't support request bodies with GET by default for reasons argued [in this topic](https://stackoverflow.com/questions/978061/http-get-with-request-body/983458). If you don't have any control over the API, you might work around it with a custom annotation `@Target(METHOD) @Retention(RUNTIME) @RestMethod(value = "GET", hasBody = true) public @interface GET { String value(); }` Also I think this conversation qualifies for being "an extended discussion", and we should rather open a chat room and have all comments moved there somehow. – vadkou Jun 19 '17 at 17:47
2

For this you need to create custom interecptor please reffere below example

import java.io.IOException; 
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;


public class CustomIntercepter implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();///
        Response response = chain.proceed(request);


        // for request size 

        long requestLength = request.body().contentLength();

        // for response size 
        long responseLength = response.body().contentLength();


        return response;
    }
}

`

Now Create Retrofit object

OkHttpClient provideOkHttpClient(CustomIntercepter customIntercepter) {
    OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
    okHttpClient.cache(cache);
    okHttpClient.addInterceptor(customIntercepter);
    return okHttpClient.build();
}


Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
    Retrofit retrofit = new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create(gson))
            .baseUrl(SERVER_URL)
            .client(okHttpClient)
            .build();
    return retrofit;
}
jaffar
  • 639
  • 8
  • 21
1

You should try accessing the raw HTTP response (Get raw HTTP response with Retrofit):

You begin with a Response object.

This object has a .raw() method that returns the actual HTTP layer's reponse, in the form of an okhttp3.Response object. Calling .body() would give you a ResponseBody object, which encapsulates the raw response.

You can get the length of the response by calling .contentLength().

Vaiden
  • 14,116
  • 6
  • 55
  • 86