使用翻新2进行记录


308

我正在尝试获取在请求中发送的确切JSON。这是我的代码:

OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor(){
   @Override public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
      Request request = chain.request();
      Log.e(String.format("\nrequest:\n%s\nheaders:\n%s",
                          request.body().toString(), request.headers()));
      com.squareup.okhttp.Response response = chain.proceed(request);
      return response;
   }
});
Retrofit retrofit = new Retrofit.Builder()
   .baseUrl(API_URL)
   .addConverterFactory(GsonConverterFactory.create())
   .client(client).build();

但是我只在日志中看到:

request:
com.squareup.okhttp.RequestBody$1@3ff4074d
headers:
Content-Type: application/vnd.ll.event.list+json

考虑到删除了Retrofit 1 setLog()以及setLogLevel()我们以前使用的Retrofit 1 ,我应该如何正确记录?

Answers:


697

在Retrofit 2中,您应该使用HttpLoggingInterceptor

将依赖项添加到build.gradle。截至2019年10月的最新版本是:

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

创建一个Retrofit如下所示的对象:

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://backend.example.com")
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
        .build();

return retrofit.create(ApiClient.class);

如果有弃用警告,只需更改setLevel为:

interceptor.level(HttpLoggingInterceptor.Level.BODY);

上面的解决方案为您提供了与logcat消息非常相似的logcat消息

setLogLevel(RestAdapter.LogLevel.FULL)

如果是java.lang.ClassNotFoundException

较旧的翻新版本可能需要较旧的logging-interceptor版本。查看注释部分以了解详细信息。


30
在我提出问题仅15天后,将其添加到OkHttp中,很高兴社区需求能产生如此快速的影响!
哈博2015年

1
并且您不再需要将sonatype快照存储库添加到build.gradle
James Goodwin

13
改造2.1.0使用此编译'com.squareup.okhttp3:logging-interceptor:
3.3.1'– jayellos

2
@jayellos谢谢你指出这一点。如果您使用的版本低于3.3.1,则不会出现此类方法异常。
guydemossyrock

2
我得到:找不到类“ okhttp3.internal.Platform”有什么想法吗?
corlaez

35

在您遇到问题时,我想问一本书的作者:Retrofit:喜欢在Android上使用API(这里是链接)(不!我没有为他们制作广告....但是它们确实很棒伙计们:)作者很快就对我进行了回复,其中包括Retrofit 1.9的Log方法和Retrofit 2.0-beta。

这是Retrofit 2.0-beta的代码:

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();  
// set your desired log level
logging.setLevel(Level.BODY);

OkHttpClient httpClient = new OkHttpClient();  
// add your other interceptors …

// add logging as last interceptor
httpClient.interceptors().add(logging);  // <-- this is the important line!

Retrofit retrofit = new Retrofit.Builder()  
   .baseUrl(API_BASE_URL)
   .addConverterFactory(GsonConverterFactory.create())
   .client(httpClient)
   .build();

这是在HttpLoggingInterceptor的帮助下添加日志记录方法的方法。另外,如果您是我上面提到的那本书的读者,您可能会发现它说Retrofit 2.0不再包含日志方法-我曾问过作者这是不正确的,他们将在明年讨论该书关于它。

//如果您对Retrofit中的Log方法不太熟悉,我想分享更多信息。

还应注意,您可以选择一些日志记录级别。我大多数时候都使用Level.BODY,它会给出以下信息:

在此处输入图片说明

您可以在图片中找到几乎所有的http职员:标题,内容和响应等。

有时您真的不需要所有客人参加您的聚会:我只是想知道它是否已成功连接,在Activiy&Fragmetn中成功进行了互联网通话。然后,您可以自由使用Level.BASIC,它将返回如下内容:

在此处输入图片说明

在里面可以找到状态码200 OK吗?这就对了 :)

另外还有一个Level.HEADERS,它将仅返回网络的头。雅当然还有另外一张图片:

在此处输入图片说明

这就是所有记录技巧;)

而且我想用我学到了很多的教程分享你那里。他们有一堆很棒的帖子,谈论与Retrofit相关的几乎所有内容,并且他们不断更新帖子,与此同时Retrofit 2.0即将到来。请看一下这些工作,我认为这可以为您节省很多时间。


HttpLoggingInterceptor来自哪里?
Radu

5
另外,这对我不起作用。httpClient.interceptors.add想要一个com.squareup.okhttp.Interceptor而不是okhttp3.logging.HttpLoggingInterceptor
Radu

@Radu您正在使用哪个版本的Retrofit?您应该的gradle有这样的事情:编译'2.0.0-BETA4 com.squareup.retrofit2:改造'
peitek

因为必须像网络拦截器一样添加拦截器,所以无法记录请求标头!请参阅:stackoverflow.com/a/36847027/2557258
Yazon2006年

12

这是一个Interceptor记录请求和响应正文的日志(使用Timber,基于OkHttp文档的示例以及其他一些SO答案):

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

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

        Response response = chain.proceed(request);

        ResponseBody responseBody = response.body();
        String responseBodyString = response.body().string();

        // now we have extracted the response body but in the process
        // we have consumed the original reponse and can't read it again
        // so we need to build a new one to return from this method

        Response newResponse = response.newBuilder().body(ResponseBody.create(responseBody.contentType(), responseBodyString.getBytes())).build();

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

        return newResponse;
    }

    private static String bodyToString(final Request request){

        try {
            final Request copy = request.newBuilder().build();
            final Buffer buffer = new Buffer();
            copy.body().writeTo(buffer);
            return buffer.readUtf8();
        } catch (final IOException e) {
            return "did not work";
        }
    }
}

6

尝试这个:

Request request = chain.request();
Buffer buffer = new Buffer();
request.body().writeTo(buffer);
String body = buffer.readUtf8();

之后,在其中body有您感兴趣的JSON。


1
如何打印身体反应?
Gilberto Ibarra 2015年

3
@GilbertoIbarra使用String bodyString = response.body().string(); log(bodyString); response = response.newBuilder().body(ResponseBody.create(response.body().contentType(), bodyString)).build(); (您不能多次 读取响应的正文,因此您必须与构建器一起创建新的响应)
Anton Ryabyh 2015年

这是我们不需要的拐杖。这是工作日志记录的示例:stackoverflow.com/a/36847027/2557258
Yazon2006年

6

我面临的主要问题是动态添加标头并将它们记录到调试logcat中。我试图添加两个拦截器。一种用于记录日志,另一种用于在运行时添加标头(令牌授权)。问题在于我们可能使用.addInterceptor或.addNetworkInterceptor。正如Jake Wharton对我说的:“网络拦截器总是排在应用拦截器之后。请参阅https://github.com/square/okhttp/wiki/Interceptors ”。因此,这里是带有标题和日志的工作示例:

OkHttpClient httpClient = new OkHttpClient.Builder()
            //here we can add Interceptor for dynamical adding headers
            .addNetworkInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request request = chain.request().newBuilder().addHeader("test", "test").build();
                    return chain.proceed(request);
                }
            })
            //here we adding Interceptor for full level logging
            .addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
            .build();

    Retrofit retrofit = new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create(gsonBuilder.create()))
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .client(httpClient)
            .baseUrl(AppConstants.SERVER_ADDRESS)
            .build();

5

我不知道setLogLevel()是否会在Retrofit的最终2.0版本中返回,但是现在您可以使用拦截器进行记录了。

可以在OkHttp Wiki中找到一个很好的例子:https : //github.com/square/okhttp/wiki/Interceptors

OkHttpClient client = new OkHttpClient();
client.interceptors().add(new LoggingInterceptor());

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://www.yourjsonapi.com")
        .addConverterFactory(GsonConverterFactory.create())
        .client(client)
        .build();

您或者没有阅读我的问题或没有阅读您链接的页面...因为LoggingInterceptor不会尝试记录请求正文(因此无法解决我的问题)
Gabor

我得到'UnsupportedOperationException异常'
Choletski

5

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

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))//first
                .addInterceptor(new OAuthInterceptor(context))//second
                .authenticator(new BearerTokenAuthenticator(context))
                .addInterceptor(loggingInterceptor)//third, log at the end
                .build();

4

对于那些需要在Retrofit中进行高级日志记录的人,请使用像这样的拦截器

public static class LoggingInterceptor implements Interceptor {
    @Override public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        long t1 = System.nanoTime();
        String requestLog = String.format("Sending request %s on %s%n%s",
                request.url(), chain.connection(), request.headers());
        //YLog.d(String.format("Sending request %s on %s%n%s",
        //        request.url(), chain.connection(), request.headers()));
        if(request.method().compareToIgnoreCase("post")==0){
            requestLog ="\n"+requestLog+"\n"+bodyToString(request);
        }
        Log.d("TAG","request"+"\n"+requestLog);

        Response response = chain.proceed(request);
        long t2 = System.nanoTime();

        String responseLog = String.format("Received response for %s in %.1fms%n%s",
                response.request().url(), (t2 - t1) / 1e6d, response.headers());

        String bodyString = response.body().string();

        Log.d("TAG","response"+"\n"+responseLog+"\n"+bodyString);

        return response.newBuilder()
                .body(ResponseBody.create(response.body().contentType(), bodyString))
                .build();
        //return response;
    }
}

public static String bodyToString(final Request request) {
    try {
        final Request copy = request.newBuilder().build();
        final Buffer buffer = new Buffer();
        copy.body().writeTo(buffer);
        return buffer.readUtf8();
    } catch (final IOException e) {
        return "did not work";
    }
}`

礼貌https : //github.com/square/retrofit/issues/1072#


您应该提到您是从github.com/square/retrofit/issues/1072#复制的(以感谢您的出处)
Gabor

这是我们不需要的拐杖。这是工作日志记录的示例:stackoverflow.com/a/36847027/2557258
Yazon2006年

4

科特林密码

        val interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY
        val client = OkHttpClient.Builder().addInterceptor(interceptor).build()
        val retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()

        return retrofit.create(PointApi::class.java)

2

您还可以添加Facebook的Stetho并查看Chrome中的网络跟踪:http ://facebook.github.io/stetho/

final OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
    builder.networkInterceptors().add(new StethoInterceptor());
}

然后在Chrome中打开“ chrome:// inspect” ...


2

这将使用Logging创建一个改造对象。而不创建单独的对象。

 private static final Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(new OkHttpClient().newBuilder()
                    .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
                    .readTimeout(READ_TIMEOUT_SECONDS, TimeUnit.SECONDS)
                    .writeTimeout(WRITE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
                    .connectTimeout(CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)
                    .build())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

2

首先向build.gradle添加依赖项:

实现'com.squareup.okhttp3:logging-interceptor:3.12.1'

使用Kotlin时,您可以像这样添加Logging Interceptor:

companion object {
    val okHttpClient = OkHttpClient().newBuilder()
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
            .build()


    fun getRetrofitInstance(): Retrofit {
        val retrofit = Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(ScanNShopConstants.BASE_URL)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build()

        return retrofit
    }
}

2

以下代码对我来说没有任何问题

摇篮

// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.1'

RetrofitClient

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);

OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(logging)
        .build();

retrofit = new Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .client(client)
        .build();

您还可以通过进入Android Studio底部的Profiler选项卡,然后单击+号以开始新会话,然后在“网络”中选择所需的峰值来验证结果。在那里您可以得到所有东西,但是它既麻烦又缓慢。请参见下图。

在此处输入图片说明


1

在Retrofit 2中正确执行此操作的最佳方法是将记录器拦截器添加为networkInterceptor,这也会打印出网络标头和您的自定义标头。重要的是要记住拦截器是作为堆栈工作的,并确保在所有末尾添加记录器。

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(new MyCustomInterceptor());
builder.connectTimeout(60, TimeUnit.SECONDS);
builder.readTimeout(60, TimeUnit.SECONDS);
builder.writeTimeout(60, TimeUnit.SECONDS);
// important line here
builder.addNetworkInterceptor(LoggerInterceptor());

1

这里的大多数答案几乎涵盖了除此工具以外的所有内容,这是查看日志的最酷的方法之一。

Facebook的Stetho。这是在google chrome上监视/记录应用程序网络流量的绝佳工具。您还可以找到这里在Github上。

在此处输入图片说明


1

对于Retrofit 2.0.2,代码就像

   **HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient.Builder httpClient=new OkHttpClient.Builder();
        httpClient.addInterceptor(logging);**


        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    **.client(httpClient.build())**
                    .build();
        }

1

这是使用以下方法从日志中过滤所有请求/响应参数的简单方法HttpLoggingInterceptor

// Request patterns to filter
private static final String[] REQUEST_PATTERNS = {
    "Content-Type",
};
// Response patterns to filter
private static final String[] RESPONSE_PATTERNS = {"Server", "server", "X-Powered-By", "Set-Cookie", "Expires", "Cache-Control", "Pragma", "Content-Length", "access-control-allow-origin"};

// Log requests and response
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
    @Override
    public void log(String message) {

        // Blacklist the elements not required
        for (String pattern: REQUEST_PATTERNS) {
            if (message.startsWith(pattern)) {
                return;
            }
        }
        // Any response patterns as well...
        for (String pattern: RESPONSE_PATTERNS) {
            if (message.startsWith(pattern)) {
                return;
            }
        }
        Log.d("RETROFIT", message);
    }
});
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

这是全部要点:

https://gist.github.com/mankum93/179c2d5378f27e95742c3f2434de7168


1

setLevel()当我尝试使用HttpLoggingInterceptor实例调用它时,我也陷入了类似的情况,方法来了,就像这样:

HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

这是我解决该问题的方法,以生成Retrofit2的日志,

我想你增加了依赖性,

implementation "com.squareup.okhttp3:logging-interceptor:4.7.2"

您可以通过以下链接获取最新版本的链接:

https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor

在这里,他们还解释了如何添加。

我创建了一个名为name的类AddLoggingInterceptor,这是我的代码,

public class AddLoggingInterceptor {

    public static OkHttpClient setLogging(){
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(loggingInterceptor)
                .build();

        return okHttpClient;
    }
}

然后,在我们实例化改造的地方,

 public static Retrofit getRetrofitInstance() {
    if (retrofit == null) {
        retrofit = new retrofit2.Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(AddLoggingInterceptor.setLogging()) // here the method is called inside client() method, with the name of class, since it is a static method.
                .build();
    }
    return retrofit;
}

现在,您可以查看在Android Studio中生成的日志,您可能需要进行搜索okHttp以进行过滤过程。它为我工作。如果有任何问题,您可以在这里给我发短信。


0

我在翻新中找到了打印日志的方法

OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .addInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    if (BuildConfig.DEBUG) {
                        Log.e(getClass().getName(), request.method() + " " + request.url());
                        Log.e(getClass().getName(), "" + request.header("Cookie"));
                        RequestBody rb = request.body();
                        Buffer buffer = new Buffer();
                        if (rb != null)
                            rb.writeTo(buffer);
                        LogUtils.LOGE(getClass().getName(), "Payload- " + buffer.readUtf8());
                    }
                    return chain.proceed(request);
                }
            })
            .readTimeout(60, TimeUnit.SECONDS)
            .connectTimeout(60, TimeUnit.SECONDS)
            .build();

            iServices = new Retrofit.Builder()
                    .baseUrl("Your Base URL")
                    .client(okHttpClient)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
                    .create(Your Service Interface .class);

为我工作。


0

Retrofit的拦截器是一项很棒的功能,可让您处理http请求。它们有两种类型:应用程序拦截器和网络拦截器。

Charles Web Debugging Proxy Application如果您需要记录请求/响应,我建议使用。输出与Stetho非常相似,但是它是更强大的工具,您无需将其添加为应用程序的依赖项


-11

大家好,我已经找到解决方法了:

  public static <T> T createApi(Context context, Class<T> clazz, String host, boolean debug) {
    if (singleton == null) {
        synchronized (RetrofitUtils.class) {
            if (singleton == null) {
                RestAdapter.Builder builder = new RestAdapter.Builder();
                builder
                        .setEndpoint(host)
                        .setClient(new OkClient(OkHttpUtils.getInstance(context)))
                        .setRequestInterceptor(RequestIntercepts.newInstance())
                        .setConverter(new GsonConverter(GsonUtils.newInstance()))
                        .setErrorHandler(new ErrorHandlers())
                        .setLogLevel(debug ? RestAdapter.LogLevel.FULL : RestAdapter.LogLevel.NONE)/*LogLevel.BASIC will cause response.getBody().in() close*/
                        .setLog(new RestAdapter.Log() {
                            @Override
                            public void log(String message) {
                                if (message.startsWith("{") || message.startsWith("["))
                                    Logger.json(message);
                                else {
                                    Logger.i(message);
                                }
                            }
                        });
                singleton = builder.build();
            }
        }
    }
    return singleton.create(clazz);
}

setLog的回调可以输入每个日志
Vihuela Yao

1
这是使用改装版v1,而不是v2
Gabor 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.