Como registrar o corpo de solicitação e resposta com o Retrofit-Android?

129

Não consigo encontrar métodos relevantes na API Retrofit para registrar os organismos completos de solicitação / resposta. Eu estava esperando alguma ajuda no Profiler (mas ele oferece apenas metadados sobre resposta). Tentei definir o nível de log no Builder, mas isso também não me ajuda:

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: Este código está funcionando agora. Não sei por que não estava funcionando antes. Possivelmente porque eu estava usando uma versão mais antiga do retrofit.

Jaguar
fonte
Você já descobriu isso? A documentação diz que isso FULLdeve dar ao corpo, mas não parece.
theblang
1
@mattblang: Eu não sei o que estava errado antes, mas esse código está funcionando agora.
Jaguar
Possível duplicata do Log com Retrofit 2
bryant1410 25/11/2015
Provavelmente prazo instante confuso smth se não trabalhar mais cedo
deathangel908

Respostas:

91

Eu costumava setLogLevel(LogLevel.FULL).setLog(new AndroidLog("YOUR_LOG_TAG")), isso me ajudou.
ATUALIZAR.
Você também pode tentar usar para fins de depuração retrofit.client.Responsecomo modelo de resposta

Alex Dzeshko
fonte
2
AndroidLog, que classe é essa?
theblang
Ele vem com a biblioteca Retrofit.
AlexDzeshko
2
Entendo. Infelizmente, isso não fornece o response bodyarquivo, embora exista no documento que LogLevel.FULL deve fornecer o arquivo response body.
theblang
Isso pode ser visto com "YOUR_LOG_TAG" no logcat do Android, na guia detalhada.
Rajeesh
4
O LogLevel.Full não existe no retrofit 2
121

Retrofit 2.0 :

ATUALIZAÇÃO: @by Marcus Pöhls

Fazendo logon no Retrofit 2

O Retrofit 2 depende completamente do OkHttp para qualquer operação de rede. Como o OkHttp é uma dependência de pares do Retrofit 2, você não precisará adicionar uma dependência adicional depois que o Retrofit 2 for lançado como uma versão estável.

O OkHttp 2.6.0 é fornecido com um interceptor de registro como uma dependência interna e você pode usá-lo diretamente para o seu cliente Retrofit. O Retrofit 2.0.0-beta2 ainda usa o OkHttp 2.5.0. Versões futuras aumentarão a dependência para versões superiores do OkHttp. É por isso que você precisa importar manualmente o interceptador de log. Inclua a seguinte linha nas importações de gradle dentro do arquivo build.gradle para buscar a dependência do interceptador de criação de log.

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

Você também pode visitar a página do GitHub da Square sobre esse interceptador

Adicionar registro ao retrofit 2

Ao desenvolver seu aplicativo e para fins de depuração, é bom ter um recurso de log integrado para mostrar informações de solicitação e resposta. Como o log não está mais integrado por padrão no Retrofit 2, precisamos adicionar um interceptador de log para o OkHttp. Felizmente, o OkHttp já vem com esse interceptador e você só precisa ativá-lo para o seu 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();

Recomendamos adicionar o log como o último interceptador, pois isso também registrará as informações que você adicionou com interceptores anteriores à sua solicitação.

Níveis de log

Registrar muitas informações explodirá seu monitor Android; é por isso que o interceptador de log do OkHttp possui quatro níveis de log: NENHUM, BÁSICO, CABEÇALHOS, CORPO. Orientaremos você em cada um dos níveis de log e descreveremos sua saída.

Para obter mais informações, visite: Retrofit 2 - Solicitações e respostas de log

RESPOSTA ANTIGA:

não é mais necessário fazer login no Retrofit 2. A equipe de desenvolvimento removeu o recurso de log. Para ser sincero, o recurso de registro não era tão confiável assim mesmo. Jake Wharton afirmou explicitamente que as mensagens ou objetos registrados são os valores assumidos e não podem ser provados como verdadeiros. A solicitação real que chega ao servidor pode ter um corpo de solicitação alterado ou outra coisa.

Mesmo que não haja registro integrado por padrão, você pode aproveitar qualquer criador de logs Java e usá-lo em um interceptor OkHttp personalizado.

Para obter mais informações sobre o Retrofit 2, consulte: Retrofit - Introdução e crie um cliente Android

Dhaval Jivani
fonte
1
Há também um posto específico para registro em Retrofit 2.0: futurestud.io/blog/retrofit-2-log-requests-and-responses
peitek
Ótima maneira de tornar tudo mais complicado do que deveria ser. Lembra-me do registro Jersey 1 vs Jersey 2. Mais código clichê ....
breakline
Adicionar interceptores dessa maneira agora resultará em UnsupportedOperationException no OkHttp v3. A nova maneira é: OkHttpClient.Builder (). AddInterceptor (log) .build () github.com/square/okhttp/issues/2219
Amagi82
@JawadLeWywadi sim, usando este código, você pode imprimir o corpo
Dhaval Jivani
Para o Retrofit 2, isso é muito mais fácil.
precisa saber é o seguinte
31

Atualização para Retrofit 2.0.0-beta3

Agora você precisa usar o okhttp3 com o construtor. Além disso, o interceptador antigo não funcionará. Esta resposta é personalizada para Android.

Aqui está uma pasta de cópia rápida para você com as novidades.

1. Modifique seu arquivo gradle para

  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. Verifique este código de exemplo:

com as novas importações. Você pode remover o Rx se não o usar. Também remova o que não usa.

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

Bônus

Eu sei que é offtopic, mas acho legal.

Caso exista um código de erro http não autorizado , aqui está um interceptador. Eu uso o eventbus para transmitir o evento.

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

código é obtido em https://github.com/AndreiD/UltimateAndroidTemplateRx (meu projeto).

OWADVL
fonte
9

Não parece haver uma maneira de fazer body + básico, mas você pode usar CHEIO e filtrar os cabeçalhos que não deseja.

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

Parece que, ao substituir o log, o corpo é prefixado com uma tag semelhante a

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

portanto, deve ser fácil registrar o básico + corpo ajustando o filtro personalizado. Estou usando uma lista negra, mas uma lista de permissões também pode ser usada dependendo de suas necessidades.

Xeridea
fonte
4

o código abaixo está funcionando para cabeçalho e sem cabeçalho para imprimir solicitação e resposta de log. Nota: Apenas comente a linha .addHeader () se não estiver usando o cabeçalho.

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();
Mukesh Parmar
fonte
3

Espero que este código o ajude a fazer logon.
você só precisa adicionar interceptador no seu Build.Gradlemake RetrofitClient.

Primeiro passo

Adicione esta linha ao seu build.gradle

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

Segundo passo

Faça seu cliente Retrofit


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

Chamando

RetrofitClient.getInstance(context).getApiService().yourRequestCall(); 
Talha Bilal
fonte
2

Se você estiver usando Retrofit2 e okhttp3, precisará saber que o Interceptor funciona por fila. Portanto, adicione loggingInterceptor no final, após seus outros interceptadores:

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