How to log request and response body with Retrofit-Android?

AndroidLoggingRetrofitRetrofit2

Android Problem Overview


I can't find relevant methods in the Retrofit API for logging complete request/response bodies. I was expecting some help in the Profiler (but it only offers meta-data about response). I tried setting the log level in the Builder, but this doesn't help me either :

RestAdapter adapter = (new RestAdapter.Builder()).
				setEndpoint(baseUrl).
				setRequestInterceptor(interceptor).
				setProfiler(profiler).
				setClient(client).
				setExecutors(MyApplication.getWebServiceThreadPool()).
				setLogLevel(LogLevel.FULL).
				setLog(new RestAdapter.Log() {
					@Override
					public void log(String msg) {
						Log.i(TAG, msg);
					}
				}).
				build();

EDIT: This code is working now. I don't know why it wasn't working earlier. Possibly because I was using some older version of retrofit.

Android Solutions


Solution 1 - Android

Retrofit 2.0 :

UPDATE: @by Marcus Pöhls

Logging In Retrofit 2

Retrofit 2 completely relies on OkHttp for any network operation. Since OkHttp is a peer dependency of Retrofit 2, you won’t need to add an additional dependency once Retrofit 2 is released as a stable release.

OkHttp 2.6.0 ships with a logging interceptor as an internal dependency and you can directly use it for your Retrofit client. Retrofit 2.0.0-beta2 still uses OkHttp 2.5.0. Future releases will bump the dependency to higher OkHttp versions. That’s why you need to manually import the logging interceptor. Add the following line to your gradle imports within your build.gradle file to fetch the logging interceptor dependency.

compile 'com.squareup.okhttp3:logging-interceptor:3.9.0'

You can also visit Square's GitHub page about this interceptor

Add Logging to Retrofit 2

While developing your app and for debugging purposes it’s nice to have a log feature integrated to show request and response information. Since logging isn’t integrated by default anymore in Retrofit 2, we need to add a logging interceptor for OkHttp. Luckily OkHttp already ships with this interceptor and you only need to activate it for your OkHttpClient.

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();  
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();   
// add your other interceptors …
// add logging as last interceptor
httpClient.addInterceptor(logging);  // <-- this is the important line!
Retrofit retrofit = new Retrofit.Builder()  
        .baseUrl(API_BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .client(httpClient.build())
        .build();

We recommend to add logging as the last interceptor, because this will also log the information which you added with previous interceptors to your request.

Log Levels

Logging too much information will blow up your Android monitor, that’s why OkHttp’s logging interceptor has four log levels: NONE, BASIC, HEADERS, BODY. We’ll walk you through each of the log levels and describe their output.

further information please visit : Retrofit 2 — Log Requests and Responses

OLD ANSWER:

no logging in Retrofit 2 anymore. The development team removed the logging feature. To be honest, the logging feature wasn’t that reliable anyway. Jake Wharton explicitly stated that the logged messages or objects are the assumed values and they couldn’t be proofed to be true. The actual request which arrives at the server may have a changed request body or something else.

Even though there is no integrated logging by default, you can leverage any Java logger and use it within a customized OkHttp interceptor.

further information about Retrofit 2 please refer : Retrofit — Getting Started and Create an Android Client

Solution 2 - Android

I used setLogLevel(LogLevel.FULL).setLog(new AndroidLog("YOUR_LOG_TAG")), it helped me.
UPDATE.
You can also try for debug purpose use retrofit.client.Response as response model

Solution 3 - Android

Update for Retrofit 2.0.0-beta3

Now you have to use okhttp3 with builder. Also the old interceptor will not work. This response is tailored for Android.

Here's a quick copy paste for you with the new stuff.

1. Modify your gradle file to

  compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3'
  compile "com.squareup.retrofit2:converter-gson:2.0.0-beta3"
  compile "com.squareup.retrofit2:adapter-rxjava:2.0.0-beta3"
  compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'

2. Check this sample code:

with the new imports. You can remove Rx if you don't use it, also remove what you don't use.

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.GsonConverterFactory;
import retrofit2.Retrofit;
import retrofit2.RxJavaCallAdapterFactory;
import retrofit2.http.GET;
import retrofit2.http.Query;
import rx.Observable;

public interface APIService {

  String ENDPOINT = "http://api.openweathermap.org";
  String API_KEY = "2de143494c0b2xxxx0e0";

  @GET("/data/2.5/weather?appid=" + API_KEY) Observable<WeatherPojo> getWeatherForLatLon(@Query("lat") double lat, @Query("lng") double lng, @Query("units") String units);


  class Factory {

    public static APIService create(Context context) {

      OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
      builder.readTimeout(10, TimeUnit.SECONDS);
      builder.connectTimeout(5, TimeUnit.SECONDS);

      if (BuildConfig.DEBUG) {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
        builder.addInterceptor(interceptor);
      }

      //Extra Headers

      //builder.addNetworkInterceptor().add(chain -> {
      //  Request request = chain.request().newBuilder().addHeader("Authorization", authToken).build();
      //  return chain.proceed(request);
      //});

      builder.addInterceptor(new UnauthorisedInterceptor(context));
      OkHttpClient client = builder.build();

      Retrofit retrofit =
          new Retrofit.Builder().baseUrl(APIService.ENDPOINT).client(client).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();

      return retrofit.create(APIService.class);
    }
  }
}

Bonus

I know it's offtopic but I find it cool.

In case there's an http error code of unauthorized, here is an interceptor. I use eventbus for transmitting the event.

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import com.androidadvance.ultimateandroidtemplaterx.BaseApplication;
import com.androidadvance.ultimateandroidtemplaterx.events.AuthenticationErrorEvent;

import de.greenrobot.event.EventBus;
import java.io.IOException;
import javax.inject.Inject;
import okhttp3.Interceptor;
import okhttp3.Response;

public class UnauthorisedInterceptor implements Interceptor {

  @Inject EventBus eventBus;

  public UnauthorisedInterceptor(Context context) {
    BaseApplication.get(context).getApplicationComponent().inject(this);
  }

  @Override public Response intercept(Chain chain) throws IOException {
    Response response = chain.proceed(chain.request());
    if (response.code() == 401) {
      new Handler(Looper.getMainLooper()).post(() -> eventBus.post(new AuthenticationErrorEvent()));
    }
    return response;
  }
}

code take from https://github.com/AndreiD/UltimateAndroidTemplateRx (my project).

Solution 4 - Android

There doesn't appear to be a way to do basic + body, but you can use FULL and filter the headers you don't want.

RestAdapter adapter = new RestAdapter.Builder()
                          .setEndpoint(syncServer)
                          .setErrorHandler(err)
                          .setConverter(new GsonConverter(gson))
                          .setLogLevel(logLevel)
                          .setLog(new RestAdapter.Log() {
                              @Override
                              public void log(String msg) {
                                  String[] blacklist = {"Access-Control", "Cache-Control", "Connection", "Content-Type", "Keep-Alive", "Pragma", "Server", "Vary", "X-Powered-By"};
                                  for (String bString : blacklist) {
                                      if (msg.startsWith(bString)) {
                                          return;
                                      }
                                  }
                                  Log.d("Retrofit", msg);
                              }
                          }).build();

It appears that when overriding the log, the body is prefixed with a tag similar to

[ 02-25 10:42:30.317 25645:26335 D/Retrofit ]

so it should be easy to log basic + body by adjusting the custom filter. I am using a blacklist, but a whitelist could also be used depending on your needs.

Solution 5 - Android

below code is working for both with header and without header to print log request & response. Note: Just comment .addHeader() line if are not using header.

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                //.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
                .addNetworkInterceptor(new Interceptor() {

                    @Override

                    public okhttp3.Response intercept(Chain chain) throws IOException {
                        Request request = chain.request().newBuilder()
                                // .addHeader(Constant.Header, authToken)
                                   .build();
                        return chain.proceed(request);
                    }
                }).build();

        final Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.baseUrl)
                .client(client) // This line is important
                .addConverterFactory(GsonConverterFactory.create())
                .build();

Solution 6 - Android

I hope this code will help you to logging .
you just need to add interceptor in your Build.Gradle then make RetrofitClient .

First Step

Add this line to your build.gradle

 implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1' 

Second Step

Make your Retrofit Client


   public class RetrofitClient {

    private Retrofit retrofit;
    private static OkHttpClient.Builder httpClient =
            new OkHttpClient.Builder();
    private static RetrofitClient instance = null;
    private static ApiServices service = null;
    private static HttpLoggingInterceptor logging =
            new HttpLoggingInterceptor();

    private RetrofitClient(final Context context) {
        httpClient.interceptors().add(new Interceptor() {
            @Override
            public okhttp3.Response intercept(Interceptor.Chain chain) throws IOException {
                Request originalRequest = chain.request();
                Request.Builder builder = originalRequest.newBuilder().
                        method(originalRequest.method(), originalRequest.body());
                okhttp3.Response response = chain.proceed(builder.build());
                /*
                Do what you want
                 */
                return response;
            }
        });
   
        if (BuildConfig.DEBUG) {
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            // add logging as last interceptor
            httpClient.addInterceptor(logging);
        }

        retrofit = new Retrofit.Builder().client(httpClient.build()).
                baseUrl(Constants.BASE_URL).
                addConverterFactory(GsonConverterFactory.create()).build();
        service = retrofit.create(ApiServices.class);
    }


    public static RetrofitClient getInstance(Context context) {
        if (instance == null) {
            instance = new RetrofitClient(context);
        }
        return instance;
    }

    public ApiServices getApiService() {
        return service;
    }
}

Calling

RetrofitClient.getInstance(context).getApiService().yourRequestCall(); 

Solution 7 - Android

Ideally, if you work with Timber it is better, as you can also do whatever you want with the log messages in your app globally, such as saving them to a file. Here's how to make the Httplogginginterceptor work with timber:

val loggingInterceptor = HttpLoggingInterceptor { message -> 
Timber.d(message) 
}.apply {
     level = HttpLoggingInterceptor.Level.BODY
}

val client = OkHttpClient.Builder()
            .addInterceptor(loggingInterceptor)
            .build()

return Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build()
            .create(RetrofitApiService::class.java)

You can also create your own implementation of the logger interceptor this way:

class HttpLoggingInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request: Request = chain.request()

        val t1 = System.nanoTime()
        Timber.i(
            "Sending request %s on %s%n%s",
            request.url,
            chain.connection(),
            request.headers
        )
        Timber.v("REQUEST BODY BEGIN\n%s\nREQUEST BODY END", bodyToString(request))

        val response = chain.proceed(request)

        val responseBody: ResponseBody? = response.body
        val responseBodyString = response.body!!.string()

        val newResponse = response.newBuilder()
            .body(responseBodyString.toResponseBody(responseBody?.contentType()))
            .build()

        val t2 = System.nanoTime()
        Timber.i(
            "Received response for %s in %.1fms%n%s",
            response.request.url,
            (t2 - t1) / 1e6,
            response.headers
        )
        Timber.v("RESPONSE BODY BEGIN:\n%s\nRESPONSE BODY END", responseBodyString)

        return newResponse
    }

    private fun bodyToString(request: Request): String? {
        return try {
            val copy = request.newBuilder().build()
            val buffer = Buffer()
            copy.body!!.writeTo(buffer)
            buffer.readUtf8()
        } catch (e: Exception) {
            "did not work"
        }
    }
}

Solution 8 - Android

If you are using Retrofit2 and okhttp3 then you need to know that Interceptor works by queue. So add loggingInterceptor at the end, after your other Interceptors:

HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        if (BuildConfig.DEBUG)
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);

 new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .addInterceptor(new CatalogInterceptor(context))
                .addInterceptor(new OAuthInterceptor(context))
                .authenticator(new BearerTokenAuthenticator(context))
                .addInterceptor(loggingInterceptor)//at the end
                .build();

Solution 9 - Android

ZoomX — Android Logger Interceptor is a great interceptor can help you to solve your problem.

Solution 10 - Android

call.request().toString();

Screenshot request which is being sent to server: enter image description here

Solution 11 - Android

For android studio before 3.0 (using android motinor)
https://futurestud.io/tutorials/retrofit-2-log-requests-and-responses
https://www.youtube.com/watch?v=vazLpzE5y9M

And for android studio from 3.0 and above (using android profiler as android monitor is replaced by android profiler)
https://futurestud.io/tutorials/retrofit-2-analyze-network-traffic-with-android-studio-profiler

Solution 12 - Android

This is not the best way to do it the better answers are above. This is just another way to check it by using Android Logs. Put them all in this helps to catch parsing errors.

 call.enqueue(new Callback<JsonObject>() {
                    @Override
                    public void onResponse(Call<JsonObject> call,
                                           Response<JsonObject> response) {

    // Catching Responses From Retrofit
    Log.d("TAG", "onResponseisSuccessful: "+response.isSuccessful());
    Log.d("TAG", "onResponsebody: "+response.body());
    Log.d("TAG", "onResponseerrorBody: "+response.errorBody());
    Log.d("TAG", "onResponsemessage: "+response.message());
    Log.d("TAG", "onResponsecode: "+response.code());
    Log.d("TAG", "onResponseheaders: "+response.headers());
    Log.d("TAG", "onResponseraw: "+response.raw());
    Log.d("TAG", "onResponsetoString: "+response.toString());

                    }

                    @Override
                    public void onFailure(Call<JsonObject> call,
                                          Throwable t) {

Log.d("TAG", "onFailuregetLocalizedMessage: " +t.getLocalizedMessage());
Log.d("TAG", "onFailuregetMessage: " +t.getMessage());
Log.d("TAG", "onFailuretoString: " +t.toString());
Log.d("TAG", "onFailurefillInStackTrace: " +t.fillInStackTrace());
Log.d("TAG", "onFailuregetCause: " +t.getCause());
Log.d("TAG", "onFailuregetStackTrace: " + Arrays.toString(t.getStackTrace()));
Log.d("TAG", "getSuppressed: " + Arrays.toString(t.getSuppressed()));

                    }
                });

Solution 13 - Android

Please add Interceptor in okHttpClient so you can get request and response log when calling API in retrofit android

 private static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .readTimeout(180, TimeUnit.SECONDS)
        .writeTimeout(180, TimeUnit.SECONDS)
        .connectTimeout(180, TimeUnit.SECONDS)
        .addInterceptor(getLoggin())
        .build();




 public static HttpLoggingInterceptor getLoggin(){
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    return logging;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondevView Question on Stackoverflow
Solution 1 - AndroidDhaval JivaniView Answer on Stackoverflow
Solution 2 - AndroidAlex DzeshkoView Answer on Stackoverflow
Solution 3 - AndroidOWADVLView Answer on Stackoverflow
Solution 4 - AndroidXerideaView Answer on Stackoverflow
Solution 5 - AndroidMukesh ParmarView Answer on Stackoverflow
Solution 6 - AndroidTalha BilalView Answer on Stackoverflow
Solution 7 - AndroidAmin KeshavarzianView Answer on Stackoverflow
Solution 8 - AndroidNickUnuchekView Answer on Stackoverflow
Solution 9 - AndroidIbrahim AbdelGawadView Answer on Stackoverflow
Solution 10 - AndroidApoorv PandeyView Answer on Stackoverflow
Solution 11 - AndroidshehzyView Answer on Stackoverflow
Solution 12 - AndroidDragonFireView Answer on Stackoverflow
Solution 13 - AndroidDeepak parmarView Answer on Stackoverflow