Registrando com Retrofit 2

308

Estou tentando obter o JSON exato que está sendo enviado na solicitação. Aqui está o meu código:

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

Mas só vejo isso nos logs:

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

Como devo fazer o registro adequado, dada a remoção setLog()e setLogLevel()que costumávamos usar com o Retrofit 1?

Gabor
fonte

Respostas:

697

No Retrofit 2, você deve usar o HttpLoggingInterceptor .

Adicione dependência a build.gradle. A versão mais recente em outubro de 2019 é:

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

Crie um Retrofitobjeto como o seguinte:

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

Em caso de avisos de descontinuação, simplesmente mude setLevelpara:

interceptor.level(HttpLoggingInterceptor.Level.BODY);

A solução acima fornece mensagens de logcat muito semelhantes às antigas definidas por

setLogLevel(RestAdapter.LogLevel.FULL)

Em caso dejava.lang.ClassNotFoundException :

A versão mais antiga de atualização pode exigir uma logging-interceptorversão mais antiga. Dê uma olhada nas seções de comentários para obter detalhes.

klimat
fonte
30
Isso foi adicionado ao OkHttp apenas 15 dias após a minha pergunta, é bom que as necessidades da comunidade tenham um impacto tão rápido!
Gabor
1
e você já não precisa adicionar o Sonatype instantâneos repositório para sua build.gradle
James Goodwin
13
retrofit 2.1.0 use esta compilação 'com.squareup.okhttp3: logging-interceptor: 3.3.1'
jayellos
2
@ jayellos Obrigado por denotar isso. Se você usar uma versão inferior à 3.3.1, não obterá nenhuma exceção desse método.
precisa saber é o seguinte
2
Estou recebendo: Não achou a classe "okhttp3.internal.Platform" alguma idéia?
Corlaez # 6/16
35

Eu conheci o que você e eu tentei perguntar ao autor do livro Retrofit: Adoro trabalhar com APIs no Android (aqui está o link ) (não! Eu não estou fazendo alguns anúncios para eles .... mas eles são muito legais pessoal :) E o autor me respondeu muito em breve, com o método Log no Retrofit 1.9 e no Retrofit 2.0-beta.

E aqui está o código do 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();

É assim que se adiciona o método de log com a ajuda do HttpLoggingInterceptor . Além disso, se você é o leitor do livro que mencionei acima, pode achar que ele diz que não existe mais o método log com o Retrofit 2.0 - o qual, perguntei ao autor, não está correto e eles atualizarão o livro no próximo ano falando sobre isso.

// Caso você não esteja familiarizado com o método Log no Retrofit, gostaria de compartilhar algo mais.

Também deve ser observado que existem alguns níveis de log que você pode escolher. Eu uso o Level.BODY na maioria das vezes, o que dará algo assim:

insira a descrição da imagem aqui

Você pode encontrar quase toda a equipe http na imagem: o cabeçalho, o conteúdo e a resposta etc.

E, às vezes, você realmente não precisa de todos os convidados para comparecer à sua festa: eu só quero saber se a conexão foi bem-sucedida, que a chamada pela Internet foi feita com sucesso dentro da minha Activiy & Fragmetn. Então você está livre para usar o Level.BASIC , que retornará algo como isto:

insira a descrição da imagem aqui

Você pode encontrar o código de status 200 OK por dentro? É isso :)

Também há outro, Level.HEADERS , que retornará apenas o cabeçalho da rede. Ya, claro, outra foto aqui:

insira a descrição da imagem aqui

Esse é todo o truque do registro;)

E gostaria de compartilhar você com o tutorial que aprendi muito por . Eles têm um ótimo post falando sobre quase tudo relacionado ao Retrofit e continuam atualizando o post, ao mesmo tempo em que o Retrofit 2.0 está chegando. Por favor, dê uma olhada nesses trabalhos, o que acho que economizará muito tempo.

Anthonyeef
fonte
De onde o HttpLoggingInterceptor se origina?
Radu
5
Além disso, isso não funciona para mim. httpClient.interceptors.add quer um com.squareup.okhttp.Interceptor e não um okhttp3.logging.HttpLoggingInterceptor
Radu
@Radu Em qual versão do Retrofit você está? Seu gradle deve ter algo parecido com isto: compile 'com.squareup.retrofit2: retrofit: 2.0.0-beta4'
peitek
Não funcionaria para registrar cabeçalhos de solicitação, porque é necessário adicionar o Interceptor como o interceptador de rede! Veja: stackoverflow.com/a/36847027/2557258
Yazon2006
12

Aqui está um Interceptorque registra os corpos de solicitação e resposta (usando o Timber, com base em um exemplo dos documentos do OkHttp e em algumas outras respostas do 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";
        }
    }
}
david.mihola
fonte
6

Tente o seguinte:

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

Depois disso, no bodyJSON você está interessado.

Anton Ryabyh
fonte
1
como pode imprimir a resposta do corpo?
Gilberto Ibarra
3
Uso @GilbertoIbarra String bodyString = response.body().string(); log(bodyString); response = response.newBuilder().body(ResponseBody.create(response.body().contentType(), bodyString)).build(); (Você não pode ler o corpo de resposta mais de uma vez, então você vai ter que criar uma nova resposta com o construtor)
Anton Ryabyh
É uma muleta que não precisamos de mais. Aqui está um exemplo de log de trabalho: stackoverflow.com/a/36847027/2557258
Yazon2006:
6

O principal problema que enfrentei foi adicionar dinamicamente cabeçalhos e registrá-los no logcat de depuração. Eu tentei adicionar dois interceptores. Um para registro e outro para adicionar cabeçalhos em movimento (autorização de token). O problema era que poderíamos .addInterceptor ou .addNetworkInterceptor. Como Jake Wharton me disse: "Os interceptores de rede sempre vêm depois dos interceptadores de aplicativos. Consulte https://github.com/square/okhttp/wiki/Interceptors ". Então, aqui está um exemplo de trabalho com cabeçalhos e logs:

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

Não sei se setLogLevel () retornará na versão final 2.0 do Retrofit, mas por enquanto você pode usar um interceptador para o log.

Um bom exemplo pode ser encontrado no wiki do OkHttp: 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();
sentimento do oceano
fonte
você ou não leu minha pergunta ou não ler a página que você está ligando ... porque LoggingInterceptor não tenta registrar o corpo da solicitação (e por isso não resolve o meu problema)
Gabor
Eu recebo 'UnsupportedOperationException'
Choletski
5

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

Para aqueles que precisam de registro de alto nível no Retrofit, use o interceptador como este

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

Cortesia : https://github.com/square/retrofit/issues/1072#

DGN
fonte
você deveria ter mencionado que você copiou do github.com/square/retrofit/issues/1072# (para dar crédito à sua fonte)
Gabor
É uma muleta que não precisamos de mais. Aqui está um exemplo de log de trabalho: stackoverflow.com/a/36847027/2557258
Yazon2006:
4

Código Kotlin

        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)
Jorge Casariego
fonte
2

Você também pode adicionar o Stetho do Facebook e ver os rastreamentos de rede no Chrome: http://facebook.github.io/stetho/

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

Em seguida, abra "chrome: // inspecionar" no Chrome ...

kenyee
fonte
2

isso criará um objeto de atualização com o log. sem criar objetos separados.

 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();
Jay Dangar
fonte
2

Primeiro adicione dependência ao build.gradle:

implementação 'com.squareup.okhttp3: logging-interceptor: 3.12.1'

Enquanto estiver usando o Kotlin, você pode adicionar o Logging Interceptor assim:

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
    }
}
Vinay John
fonte
2

O seguinte conjunto de códigos está funcionando sem problemas para mim

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

Também é possível verificar os resultados acessando a guia Profiler na parte inferior do Android Studio, clicando em + sinal para Iniciar uma nova sessão e selecione o pico desejado em "Rede". Lá você pode obter tudo, mas é complicado e lento. Por favor, veja a imagem abaixo.

insira a descrição da imagem aqui

Fogo de dragão
fonte
1

A melhor maneira de fazer isso corretamente no Retrofit 2 é adicionar o interceptor do criador de logs como um networkInterceptor, que também imprimirá os cabeçalhos da rede e os cabeçalhos personalizados. O importante é lembrar que o interceptador funciona como uma pilha e certifique-se de adicionar o logger no final de tudo.

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

A maioria das respostas aqui abrange quase tudo, exceto esta ferramenta, uma das maneiras mais legais de ver o log.

É o Stetho do Facebook . Essa é a excelente ferramenta para monitorar / registrar o tráfego de rede do seu aplicativo no google chrome . Você também pode encontrar aqui no Github.

insira a descrição da imagem aqui

Nishant Shah
fonte
1

para o Retrofit 2.0.2, o código é como

   **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();
        }
outro cara alto
fonte
1

Aqui está uma maneira simples de filtrar qualquer parâmetro de solicitação / resposta dos logs usando 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);

Aqui está a essência completa:

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

Pulp Fiction
fonte
1

Eu também estava preso em um tipo semelhante de situação, o setLevel()método não estava chegando, quando eu estava tentando chamá-lo com a instância do HttpLoggingInterceptor, assim:

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

Aqui está como eu resolvi isso, para gerar log para o Retrofit2,

Suponho que você adicionou a dependência,

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

Para a versão mais recente, você pode conferir este link:

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

Aqui eles também explicaram sobre como adicionar.

Eu criei uma classe com o nome AddLoggingInterceptor, aqui está o meu código,

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

Então, onde estamos instanciando nosso 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;
}

Agora você pode ver o log gerado no seu Android Studio, pode ser necessário pesquisar o okHttpprocesso de filtragem. Funcionou para mim. Se houver algum problema, você pode me enviar uma mensagem aqui.

Jwala Kumar
fonte
0

Encontrei caminho para o Print Log in Retrofit

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

Funciona para mim.

Nilesh Senta
fonte
0

O interceptador do Retrofit é um ótimo recurso que permite trabalhar com solicitações http. Existem dois tipos deles: aplicativo e interceptores de rede.

Eu recomendaria usar Charles Web Debugging Proxy Applicationse você precisar registrar suas solicitações / respostas. A saída é muito semelhante ao Stetho, mas é um instrumento mais poderoso que você não precisa adicionar como dependência a um aplicativo

yoAlex5
fonte
-11

ei pessoal, eu já acho solução:

  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);
}
Vihuela Yao
fonte
setlog de retorno de chamada de entrada pode cada log
Vihuela Yao
1
isto é usando retroajuste v1, v2 não
Gabor