web-dev-qa-db-ja.com

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

Retrofit 1で使用していたsetLog()setLogLevel()の削除を考えれば、どのようにして適切なロギングを行うべきですか?

263
Gabor

Retrofit 2では、 HttpLoggingInterceptor を使用する必要があります。

build.gradleに依存関係を追加する:

implementation 'com.squareup.okhttp3:logging-interceptor:3.12.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);

上記の解決策はあなたにlogcatメッセージを与えます。

setLogLevel(RestAdapter.LogLevel.FULL)

Java.lang.ClassNotFoundExceptionの場合

古いバージョンのRetrofitでは、古いバージョンのlogging-interceptorバージョンが必要になる場合があります。詳細についてはコメント欄をご覧ください。

595
klimat

私はあなたと同じことに出会い、私は本の作者に尋ねようとしました改装:Android上でのAPIの扱いが大好きです(これが link です)(いいえ!Iそれらのためにいくつかの広告を作っていません....しかし、彼らは本当にいい人です:)そして、著者は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メソッドに慣れていない場合は、さらに何か共有したいと思います。

また、あなたが選ぶことができるいくつかのロギングレベルがあることに注意するべきです。ほとんどの場合、 Level.BODY を使用します。これにより、次のようになります。

enter image description here

あなたは写真の中にほとんどすべてのhttpスタッフを見つけることができます:ヘッダー、内容と応答など。

そして、時にはあなたは本当にあなたのパーティーに出席するためにすべてのゲストを必要としない:私はちょうどそれがうまく接続されたかどうか、インターネット通話が私のActiviy&Fragmetnの中でうまくなされることを知りたい。そして、あなたは自由に Level.BASIC を使うことができ、これはこのような何かを返すでしょう:

enter image description here

ステータスコード 200 OK を見つけることができますか?それだ :)

また、ネットワークのヘッダーのみを返す、 Level.HEADERS というものもあります。もちろんここで別の写真:

enter image description here

これがすべてのLoggingトリックです。

そして、私が多くを学んだチュートリアルと共有したいと思います そこ 。彼らはRetrofitに関連するほぼすべてのことについて話しているたくさんの素晴らしい記事を持っています、そして彼らはRetrofit 2.0が来るのと同時に、その記事を更新し続けています。それらの作品を見てください。私はあなたに多くの時間を節約すると思います。

28
Anthonyeef

これはリクエスト本体とレスポンス本体の両方をログに記録するInterceptorです(OkHttpのドキュメントと他のいくつかのSOからの例に基づいてTimberを使用して)

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";
        }
    }
}
10
david.mihola

これを試して:

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

この後、bodyにあなたが興味を持っているJSONがあります。

6
Anton Ryabyh

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

Retrofit 2とokhttp 3を使用している場合は、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
NickUnuchek

私が直面した主な問題は、動的にヘッダを追加してそれらをdebug logcatにログインさせることでした。私は2つのインターセプターを追加しようとしました。 1つはロギング用で、もう1つは進行中にヘッダーを追加するためのもの(トークン認証)です。問題は、.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();
4
Yazon2006

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#

4
DGN

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
kenyee

これは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
Jay Dangar

コトリンコード

        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)
1
Jorge Casariego

ここでの答えの大部分は、ログを見るための最もクールな方法の1つである、このツール以外のほとんどすべてを網羅しています。

FacebookのStetho です。これは、 google chrome でアプリのネットワークトラフィックを監視/記録するための優れたツールです。 Githubにも here があります。

enter image description here

1
Nishant Shah

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
other Tall guy

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
Catluc

ZoomX — Android Logger Interceptor Tool は、Retrofit 2の優れたAndroidインターセプターです

0

まず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
        }
    }
0
Vinay John

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

0
pulp_fiction

私は後付けでPrint Logの方法を見つけました

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
Nilesh Senta