Вопрос-ответ

Logging with Retrofit 2

Ведение журнала с помощью 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?

Переведено автоматически
Ответ 1

В Retrofit 2 вам следует использовать HttpLoggingInterceptor.

Добавить зависимость в build.gradle. Последняя версия по состоянию на май 2023 года -:

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

Создайте 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:

Для более старой модифицированной версии может потребоваться более старая logging-interceptor версия. Ознакомьтесь с разделами комментариев для получения подробной информации.

Ответ 2

Я столкнулся с этим, когда мы с вами пытались спросить автора книги Retrofit: любите работать с API на Android (вот ссылка) (нет! Я не делаю для них рекламу .... но они действительно хорошие ребята :) И автор ответил мне очень скоро, используя оба метода ведения журнала в Retrofit 1.9 и 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. Также, если вы читаете ту книгу, о которой я упоминал выше, вы можете обнаружить, что в ней говорится, что метода log с Retrofit 2.0 больше не существует - что, как я спросил автора, неверно, и они обновят книгу в следующем году, рассказав об этом.

// На случай, если вы не очень хорошо знакомы с методом ведения журнала в Retrofit, я хотел бы поделиться кое-чем еще.

Также следует отметить, что вы можете выбрать несколько уровней ведения журнала. Большую часть времени я использую Level.BODY, что дает примерно следующее:

введите описание изображения здесь

Вы можете найти почти весь http-персонал внутри изображения: заголовок, содержимое и ответ и т.д.

И иногда вам действительно не нужно, чтобы все гости присутствовали на вашей вечеринке: я просто хочу знать, успешно ли она подключена, этот интернет-вызов успешно выполнен в рамках моей активности и фрагмента. Затем вы можете свободно использовать Level.BASIC, который вернет что-то вроде этого:

введите описание изображения здесь

Можете ли вы найти код состояния 200 OK внутри? Вот и все :)

Также есть еще один, Level.HEADERS, который будет возвращать только заголовок сети. Я, конечно, другая картинка здесь:

введите описание изображения здесь

Вот и весь трюк с ведением журнала ;)

И я хотел бы поделиться с вами руководством, из которого я многому научился. У них есть куча отличных постов, в которых рассказывается практически обо всем, что связано с Retrofit, и они продолжают обновлять пост, в то же время выходит Retrofit 2.0. Пожалуйста, взгляните на эти работы, которые, я думаю, сэкономят вам массу времени.

Ответ 3

Вот 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";
}
}
}
Ответ 4

Основная проблема, с которой я столкнулся, заключалась в динамическом добавлении заголовков и регистрации их в debug logcat. Я попытался добавить два перехватчика. Один для ведения журнала, а другой для добавления заголовков на ходу (авторизация токеном). Проблема заключалась в том, что мы можем .addInterceptor или .addNetworkInterceptor. Как сказал мне Джейк Уортон: "Сетевые перехватчики всегда следуют за перехватчиками приложений. Смотрите 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();
java