关于日志记录:如何使用Retrofit-Android记录请求和响应正文?

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

我在Retrofit API中找不到用于记录完整的请求/响应正文的相关方法。 一世
在Profiler中期待一些帮助(但它仅提供有关响应的元数据)。 我尝试在Builder中设置日志级别,但这也无济于事:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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();

编辑:此代码现在正在工作。 我不知道为什么它不起作用。 可能是因为我使用的是旧版本的改造。


改造2.0:

更新:@by Marcus P?hls

登录改造2

Retrofit 2完全依赖OkHttp进行任何网络操作。由于OkHttp是Retrofit 2的对等依赖项,因此,在Retrofit 2作为稳定版本发布后,您无需添加其他依赖项。

OkHttp 2.6.0附带日志拦截器作为内部依赖项,您可以将其直接用于Retrofit客户端。改造2.0.0-beta2仍使用OkHttp 2.5.0。将来的发行版将使对更高的OkHttp版本的依赖性增加。因此,您需要手动导入日志记录拦截器。将以下行添加到build.gradle文件中的gradle导入中,以获取日志记录拦截器依赖项。

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

您还可以访问Square的有关此拦截器的GitHub页面

将日志记录添加到改造2

在开发应用程序和进行调试时,最好集成日志功能以显示请求和响应信息。由于Retrofit 2中不再默认集成日志记录,因此我们需要为OkHttp添加日志记录拦截器。幸运的是,OkHttp已经附带了此拦截器,您只需要为OkHttpClient激活它即可。

1
2
3
4
5
6
7
8
9
10
11
12
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();

我们建议将日志记录添加为最后一个拦截器,因为这还将记录您与以前的拦截器一起添加到您的请求中的信息。

日志级别

记录太多信息将使您的Android显示器崩溃,这就是OkHttp的记录拦截器具有四个日志级别的原因:NONE,BASIC,HEADERS,BODY。我们将引导您遍历每个日志级别并描述其输出。

更多信息,请访问:改造2-日志请求和响应

旧答案:

不再登录Retrofit 2。开发团队删除了日志记录功能。老实说,日志记录功能并不是那么可靠。杰克·沃顿(Jake Wharton)明确表示,记录的消息或对象是假定的值,无法证明它们是真实的。到达服务器的实际请求可能具有更改的请求正文或其他内容。

即使默认情况下没有集成日志记录,您也可以利用任何Java记录器并在自定义的OkHttp拦截器中使用它。

有关翻新2的更多信息,请参考:
改造-入门和创建Android客户端


我使用了setLogLevel(LogLevel.FULL).setLog(new AndroidLog("YOUR_LOG_TAG")),它对我有帮助。
更新。您也可以尝试将retrofit.client.Response用作响应模型以进行调试


Retrofit 2.0.0-beta3的更新

现在,您必须将okhttp3与builder一起使用。同样,旧的拦截器将无法工作。此响应是针对Android量身定制的。

这是为您提供新内容的快速复制粘贴。

1.将gradle文件修改为

1
2
3
4
  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.检查以下示例代码:

与新的进口。您可以删除不使用的Rx,也可以删除不使用的Rx。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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);
    }
  }
}

奖金

我知道这是题外话,但我觉得它很酷。

如果有未经授权的http错误代码,这里是一个拦截器。我使用事件总线来传输事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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;
  }
}

代码来自https://github.com/AndreiD/UltimateAndroidTemplateRx(我的项目)。


似乎没有一种执行基本+正文的方法,但是您可以使用FULL并过滤不需要的标头。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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();

似乎在覆盖日志时,主体的前缀类似于

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

因此通过调整自定义过滤器,可以轻松记录基本+正文。我正在使用黑名单,但是根据您的需要也可以使用白名单。


下面的代码适用于带头和不带头的情况,以打印日志请求和响应。注意:如果不使用标头,则只需注释.addHeader()行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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();

我希望这段代码可以帮助您登录。
您只需要在Build.Gradle中添加拦截器,然后使RetrofitClient即可。

第一步

将此行添加到您的Build.Gradle

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

第二步

使您的改造客户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
   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;
    }
}

呼唤

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


如果您正在使用Retrofit2和okhttp3,则需要知道Interceptor按队列工作。因此,在其他拦截器之后,最后添加loggingInterceptor:

1
2
3
4
5
6
7
8
9
10
11
12
13
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();

ZoomX-Android Logger拦截器是一款出色的拦截器,可以帮助您解决问题。


适用于3.0之前的android studio(使用android motinor)
https://futurestud.io/tutorials/retrofit-2-log-requests-and-responses

对于3.0及以上版本的android studio(使用android profiler作为android monitor替换为android profiler)
https://futurestud.io/tutorials/retrofit-2-analyze-network-traffic-with-android-studio-profiler