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

15

154

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.

Habakkuk answered 19/2, 2014 at 16:22 Comment(5)
Did you ever figure this out? The documentation says that FULL is supposed to give the body but it doesn't seem to.Weightless
@mattblang : I don't know what was wrong earlier, but this code is working now.Habakkuk
Possible duplicate of Logging with Retrofit 2Garlan
https://mcmap.net/q/159778/-logging-in-retrofit-2-0/…Paschasia
Probably instant run messed up smth if it didn't work earlierDaisydaitzman
B
95

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

Berty answered 26/3, 2014 at 8:29 Comment(5)
AndroidLog, what class is that?Weightless
It comes with Retrofit library.Berty
I see. Unfortunately this doesn't give you the response body, although it does state in the doc that LogLevel.FULL should give you the response body.Weightless
This can be seen with "YOUR_LOG_TAG" in android logcat under verbose tab.Ostracoderm
LogLevel.Full does not exist in retrofit 2Kyleekylen
D
158

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

Delius answered 25/10, 2015 at 10:16 Comment(6)
There is also a post specific for logging in Retrofit 2.0: futurestud.io/blog/retrofit-2-log-requests-and-responsesNablus
Great way to make everything more complicated than it should be. Reminds me of Jersey 1 vs Jersey 2 logging. More boilerplate code....Aguascalientes
Adding interceptors this way will now result in an UnsupportedOperationException in OkHttp v3. The new way is: OkHttpClient.Builder().addInterceptor(logging).build() github.com/square/okhttp/issues/2219Mildredmildrid
@JawadLeWywadi yes using this code you can print bodyDelius
For Retrofit 2, this is much easier.Underpinning
Link requires registration, possibly payment.Uninspired
B
95

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

Berty answered 26/3, 2014 at 8:29 Comment(5)
AndroidLog, what class is that?Weightless
It comes with Retrofit library.Berty
I see. Unfortunately this doesn't give you the response body, although it does state in the doc that LogLevel.FULL should give you the response body.Weightless
This can be seen with "YOUR_LOG_TAG" in android logcat under verbose tab.Ostracoderm
LogLevel.Full does not exist in retrofit 2Kyleekylen
M
33

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).

Marlborough answered 19/1, 2016 at 11:32 Comment(0)
P
9

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.

Pragmatics answered 25/2, 2015 at 17:52 Comment(0)
U
6

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();
Unemployed answered 26/9, 2016 at 13:39 Comment(0)
P
4

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"
        }
    }
}

And here is how to add Timber:

implementation "com.jakewharton.timber:timber:5.0.1"
Philae answered 13/8, 2021 at 13:28 Comment(0)
A
3

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(); 

Anglonorman answered 18/3, 2019 at 6:34 Comment(0)
D
2

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();
Dollydolman answered 20/9, 2016 at 8:43 Comment(0)
K
2

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

Kendo answered 31/8, 2019 at 13:54 Comment(0)
P
2
call.request().toString();

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

Paramo answered 16/12, 2020 at 7:8 Comment(0)
S
1

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()));

                    }
                });
Sixfold answered 14/1, 2021 at 1:45 Comment(0)
C
0

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

Calliper answered 29/4, 2018 at 17:50 Comment(0)
A
0

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;
}
Abrogate answered 24/3, 2021 at 12:39 Comment(0)
W
0

If anyone is looking to print everything except byte array while uploading images, you will need to create a custom interceptor for it.

And then add this custom interceptor to your client(Okhttp in my case).

class CustomHttpLoggerForImage @Inject constructor() : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()

        // Log request information excluding byte array for MultipartBody
        val requestBody = request.body
        if (requestBody is MultipartBody) {
            Log.i(OKHTTP_IMAGE_TAG, "Request: ${request.method} ${request.url}")
            Log.i(OKHTTP_IMAGE_TAG, "Form fields: ${requestBody.parts.map { it.body }}")
        } else {
            // Log complete request information for other request types
            Log.i(OKHTTP_IMAGE_TAG, "Request: $request")
        }

        val originalResponse = chain.proceed(request)

        Log.i(OKHTTP_IMAGE_TAG, "Response Code: ${originalResponse.code}")

        val responseBody = originalResponse.body
        if (responseBody != null) {
            val responseBodyString = responseBody.string()
            Log.i(OKHTTP_IMAGE_TAG, "Response Body: $responseBodyString")

            // reverse all the alterations to the response body and returned it
            return originalResponse.newBuilder().body(responseBodyString.toResponseBody(responseBody.contentType())).build()
        } else {
            Log.i(OKHTTP_IMAGE_TAG, "Response Body: (empty body)")
        }


        return originalResponse
    }

    companion object {
        private const val OKHTTP_IMAGE_TAG = "OkHttpImage"
    }
}
Weylin answered 22/1, 2024 at 5:14 Comment(0)
G
0

This library very helpful for checking and sharing Request and Response body with Retrofit.

Please note that you should add both the library and the library-no-op variant to isolate Chucker from release builds as follows:

dependencies {
  debugImplementation "com.github.chuckerteam.chucker:library:4.0.0"
  releaseImplementation "com.github.chuckerteam.chucker:library-no-op:4.0.0"
}

To start using Chucker, just plug in a new ChuckerInterceptor to your OkHttp Client Builder:

val client = OkHttpClient.Builder()
                    .addInterceptor(ChuckerInterceptor(context))
                    .build()

For complete description please check here: https://github.com/ChuckerTeam/chucker

enter image description here

Guizot answered 18/3, 2024 at 9:34 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.