使用Retrofit进行日志记录2

我试图获得在请求中发送的确切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

我应该如何做适当的日志记录,鉴于删除setLog()setLogLevel(),我们曾经使用的Retrofit 1?

235118 次浏览

嘿,伙计们,我已经找到解决方案了:

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

我不知道setLogLevel()是否会在最终2.0版本的Retrofit中返回,但现在你可以使用一个拦截器来记录日志。

一个很好的例子可以在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();

试试这个:

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

在这之后,在body中有你感兴趣的JSON。

下面是一个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";
}
}
}

对于那些需要在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#

在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消息非常类似于

setLogLevel(RestAdapter.LogLevel.FULL)

如果java.lang.ClassNotFoundException:

旧的Retrofit版本可能需要旧的logging-interceptor版本。详情请看评论部分。

我遇到了你和我试图问这本书的作者Retrofit:喜欢在Android上使用api(这里是链接) (不!)我不会为他们做广告....但他们真的是好人:) 作者很快就回复了我,在Retrofit 1.9和Retrofit 2.0-beta上都使用了Log方法

下面是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方法,我想分享更多的东西。

还应该注意,您可以选择一些日志级别。我大部分时间使用的水平。身体,它会给出类似这样的东西:

enter image description here

你可以在图片中找到几乎所有的http人员:头,内容和响应,等等。

有时你真的不需要所有的客人都来参加你的派对:我只想知道它是否成功连接,在我的活动&Fragmetn。然后你可以自由地使用的水平。基本,它将返回类似这样的东西:

enter image description here

你能在里面找到状态代码200好了吗?就是这样:)

还有另一个的水平。头,它只返回网络的头文件。当然,这是另一张图:

enter image description here

这就是所有的日志技巧;)

我想和你分享我学到很多的教程在那里。他们有一堆很棒的帖子,谈论几乎所有与改造有关的事情,他们还在继续更新帖子,与此同时,改造2.0即将到来。请看一下这些工作,我想这会节省你很多时间。

我面临的主要问题是动态添加头文件并将它们记录到调试日志中。我试着增加两个拦截器。一个用于日志记录,一个用于添加动态报头(令牌授权)。问题是我们可以。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();
你也可以添加Facebook的Stetho,在Chrome中查看网络痕迹: http://facebook.github.io/stetho/ < / p >
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
builder.networkInterceptors().add(new StethoInterceptor());
}

然后打开“chrome://inspect”在chrome…

我找到了打印登录改造的方法

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

对我有用。

如果您正在使用Retrofit2和okhttp3,那么您需要知道Interceptor是通过队列工作的。所以在你的其他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();

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

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

它是Facebook的Stetho。这是在谷歌chrome上监控/记录应用程序网络流量的绝佳工具。你也可以在Github上找到在这里

enter image description here

对于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();
}

芬兰湾的科特林代码

        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)

这将创建一个带有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();

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

实现“com.squareup.okhttp3:日志记录拦截器:3.12.1”

在使用Kotlin时,你可以像这样添加日志拦截器:

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

下面是一个使用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

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

Gradle

// 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标签来验证结果,然后点击+号开始一个新的会话,然后在“网络”中选择所需的峰值。在那里你可以得到所有的东西,但是又麻烦又慢。请看下图。

enter image description here

更新日志

Retrofit的拦截器是一个伟大的功能,它允许您处理http请求。 它们有两种类型:applicationnetwork拦截器

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

[Charles Proxy change response]

我也陷入了类似的情况,setLevel()方法没有到来,当我试图用HttpLoggingInterceptor的实例调用它时, 这样的:< / p >

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)

这里他们也解释了如何添加。

我创建了一个名为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;
}
}

然后,在我们实例化我们的Retrofit时,

 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作为过滤过程。这对我很管用。如果有任何问题,你可以给我发短信。

如果java.lang.ClassNotFoundException与匕首

我删除了

implementation("com.squareup.okhttp3:okhttp:4.9.0")

一切都很正常。