Wie protokolliere ich den Anforderungs- und Antworttext mit Retrofit-Android?

129

Ich kann in der Retrofit-API keine relevanten Methoden zum Protokollieren vollständiger Anforderungs- / Antwortkörper finden. Ich hatte Hilfe im Profiler erwartet (aber er bietet nur Metadaten zur Antwort). Ich habe versucht, die Protokollebene im Builder festzulegen, aber das hilft mir auch nicht:

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: Dieser Code funktioniert jetzt. Ich weiß nicht, warum es früher nicht funktioniert hat. Möglicherweise, weil ich eine ältere Version der Nachrüstung verwendet habe.

Jaguar
quelle
Hast du das jemals herausgefunden? Die Dokumentation sagt, dass FULLdas den Körper geben soll, aber es scheint nicht.
Theblang
1
@mattblang: Ich weiß nicht, was früher falsch war, aber dieser Code funktioniert jetzt.
Jaguar
Mögliches Duplikat der Protokollierung mit Nachrüstung 2
bryant1410
Wahrscheinlich hat der Sofortlauf etwas durcheinander gebracht, wenn es nicht früher funktioniert hat
deathangel908

Antworten:

91

Ich habe es benutzt setLogLevel(LogLevel.FULL).setLog(new AndroidLog("YOUR_LOG_TAG")), es hat mir geholfen.
AKTUALISIEREN.
Sie können auch versuchen, Debug-Zwecke retrofit.client.Responseals Antwortmodell zu verwenden

Alex Dzeshko
quelle
2
AndroidLog, welche Klasse ist das?
Theblang
Es kommt mit Nachrüstbibliothek.
Alex Dzeshko
2
Aha. Leider gibt Ihnen dies nicht das response body, obwohl es in dem Dokument angegeben ist, das Ihnen das geben LogLevel.FULL sollteresponse body .
Theblang
Dies kann mit "YOUR_LOG_TAG" in Android Logcat unter ausführlicher Registerkarte gesehen werden.
Rajeesh
4
LogLevel.Full existiert nicht in Nachrüstung 2
121

Nachrüstung 2.0 :

UPDATE: @von Marcus Pöhls

Anmelden Nachrüstung 2

Retrofit 2 ist für jeden Netzwerkbetrieb vollständig auf OkHttp angewiesen. Da OkHttp eine Peer-Abhängigkeit von Retrofit 2 ist, müssen Sie keine zusätzliche Abhängigkeit hinzufügen, sobald Retrofit 2 als stabile Version veröffentlicht wird.

OkHttp 2.6.0 wird mit einem Protokollierungs-Interceptor als interne Abhängigkeit geliefert und kann direkt für Ihren Retrofit-Client verwendet werden. Retrofit 2.0.0-beta2 verwendet weiterhin OkHttp 2.5.0. Zukünftige Versionen werden die Abhängigkeit von höheren OkHttp-Versionen erhöhen. Aus diesem Grund müssen Sie den Protokollierungs-Interceptor manuell importieren. Fügen Sie Ihren Gradle-Importen in Ihrer build.gradle-Datei die folgende Zeile hinzu, um die Abhängigkeit des Protokollierungs-Interceptors abzurufen.

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

Sie können auch die GitHub-Seite von Square zu diesem Interceptor besuchen

Hinzufügen der Protokollierung zur Nachrüstung 2

Während der Entwicklung Ihrer App und zu Debugging-Zwecken ist es hilfreich, eine Protokollfunktion zu integrieren, um Anforderungs- und Antwortinformationen anzuzeigen. Da die Protokollierung in Retrofit 2 nicht mehr standardmäßig integriert ist, müssen wir einen Protokollierungs-Interceptor für OkHttp hinzufügen. Glücklicherweise wird OkHttp bereits mit diesem Interceptor ausgeliefert und Sie müssen ihn nur für Ihren OkHttpClient aktivieren.

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

Wir empfehlen, die Protokollierung als letzten Interceptor hinzuzufügen, da hierdurch auch die Informationen protokolliert werden, die Sie mit früheren Interceptors zu Ihrer Anfrage hinzugefügt haben.

Protokollebenen

Wenn Sie zu viele Informationen protokollieren, wird Ihr Android-Monitor in die Luft gesprengt. Aus diesem Grund verfügt der Protokollierungs-Interceptor von OkHttp über vier Protokollierungsstufen: NONE, BASIC, HEADERS, BODY. Wir führen Sie durch die einzelnen Protokollebenen und beschreiben deren Ausgabe.

Weitere Informationen finden Sie unter: Nachrüstung 2 - Protokollanfragen und -antworten

ALTE ANTWORT:

Keine Anmeldung mehr in Retrofit 2. Das Entwicklungsteam hat die Protokollierungsfunktion entfernt. Um ehrlich zu sein, war die Protokollierungsfunktion sowieso nicht so zuverlässig. Jake Wharton erklärte ausdrücklich, dass die protokollierten Nachrichten oder Objekte die angenommenen Werte sind und nicht als wahr nachgewiesen werden konnten. Die tatsächliche Anforderung, die am Server eintrifft, hat möglicherweise einen geänderten Anforderungshauptteil oder etwas anderes.

Obwohl standardmäßig keine integrierte Protokollierung vorhanden ist, können Sie jeden Java-Protokollierer nutzen und in einem angepassten OkHttp-Interceptor verwenden.

Weitere Informationen zu Retrofit 2 finden Sie unter: Retrofit - Erste Schritte und Erstellen eines Android-Clients

Dhaval Jivani
quelle
1
Es gibt auch einen Beitrag speziell für die Anmeldung in Retrofit 2.0: futurestud.io/blog/retrofit-2-log-requests-and-responses
peitek
Tolle Möglichkeit, alles komplizierter zu machen, als es sein sollte. Erinnert mich an die Protokollierung von Jersey 1 gegen Jersey 2. Mehr Boilerplate-Code ....
Bruchlinie
Das Hinzufügen von Interceptors auf diese Weise führt nun zu einer UnsupportedOperationException in OkHttp v3. Der neue Weg ist: OkHttpClient.Builder (). AddInterceptor (Protokollierung) .build () github.com/square/okhttp/issues/2219
Amagi82
@JawadLeWywadi ja mit diesem Code können Sie Körper drucken
Dhaval Jivani
Für Retrofit 2 ist dies viel einfacher.
Gary99
31

Update für Retrofit 2.0.0-beta3

Jetzt müssen Sie okhttp3 mit Builder verwenden. Auch der alte Abfangjäger wird nicht funktionieren. Diese Antwort ist auf Android zugeschnitten.

Hier ist eine schnelle Kopie zum Einfügen mit den neuen Sachen.

1. Ändern Sie Ihre Gradle-Datei in

  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. Überprüfen Sie diesen Beispielcode:

mit den neuen Importen. Sie können Rx entfernen, wenn Sie es nicht verwenden, und auch entfernen, was Sie nicht verwenden.

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

Bonus

Ich weiß, dass es offtopisch ist, aber ich finde es cool.

Falls es einen http-Fehlercode von nicht autorisiert gibt , ist hier ein Abfangjäger. Ich benutze Eventbus zur Übertragung des Events.

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

Code aus https://github.com/AndreiD/UltimateAndroidTemplateRx (mein Projekt).

OWADVL
quelle
9

Es scheint keine Möglichkeit zu geben, Basic + Body auszuführen, aber Sie können FULL verwenden und die nicht gewünschten Header filtern.

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

Es scheint, dass dem Text beim Überschreiben des Protokolls ein ähnliches Tag vorangestellt wird

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

Daher sollte es einfach sein, basic + body durch Anpassen des benutzerdefinierten Filters zu protokollieren. Ich verwende eine schwarze Liste, aber je nach Ihren Anforderungen kann auch eine Whitelist verwendet werden.

Xeridea
quelle
4

Der folgende Code funktioniert sowohl mit als auch ohne Header, um die Protokollanforderung und -antwort zu drucken. Hinweis: Kommentieren Sie einfach die Zeile .addHeader (), wenn Sie keinen Header verwenden.

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
quelle
3

Ich hoffe, dieser Code hilft Ihnen bei der Protokollierung.
Sie müssen nur Interceptor in Ihrem Build.Gradledann machen hinzufügen RetrofitClient.

Erster Schritt

Fügen Sie diese Zeile zu Ihrem hinzu build.gradle

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

Zweiter Schritt

Machen Sie Ihren Retrofit-Client


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

Berufung

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

Wenn Sie Retrofit2 und okhttp3 verwenden, müssen Sie wissen, dass Interceptor nach Warteschlange arbeitet. Fügen Sie also am Ende nach Ihren anderen Interceptors loggingInterceptor hinzu:

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
quelle
1

ZoomX - Android Logger Interceptor ist ein großartiger Interceptor, der Ihnen bei der Lösung Ihres Problems helfen kann.

Ibrahim AbdelGawad
quelle