Spring. Hacer que HttpLogginInterceptor muestre mensajes en el log con nivel DEBUG en lugar de INFO

Si usas okhttp en alugna aplicación Spring (o Java) hay una clase HttpLoggingInterceptor que nos permite, en tiempo de desarrollo, volcar toda la información acerca de las peticiones que hace el cliente http en el log de la aplicación.

Por defecto, HttpLoggingInterceptor muestra los mensajes en nivel de INFO, en mi caso, prefería que se mostrasen con nivel de debug.

@Configuration
public class HttpClientModule {
    
    private static final Logger logger = LoggerFactory.getLogger(HttpClientModule.class);

    @Bean
    public OkHttpClient okHttpClient(@Value("${debug.requests}") boolean debug) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        if (debug) {
            // La siguiente línea es la importante
            HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(logger::debug); 
            interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            builder.addInterceptor(interceptor);
        }
        return builder.build();
    }
}

Forzar que una petición HTTP se envíe por la WiFi seleccionada

En uno de los proyectos en los que trabajo, nos conectamos a un pequeño dispositivo para leer / escribir datos en el.

La primera vez que se arrranca el dispositivo, este lo hace en un modo “Access Point” que crea una WiFi virtual, desde la que nos podemos conectar al dispositivo directamente para configurarle la red WiFi a la que se tiene que conectar. Este punto de acceso, evidentemente no da salida a Internet.

En Android Marshmallow, cuando el dispositivo está en punto de acceso y, al no ofrecer una conexión que el sistema Android considere de “calidad”, este decide enviar las peticiones siempre por la red 4g/3g. Haciendo imposible la configuración del dispositivo desde esta versión del sistema.

El siguiente código inicializa OkHttpClient para que siempre envie la petición por la primera wifi que tiene configurada (la que tienes seleccionada) en lugar de la que ofrezca más calidad.

Pongo aquí el código por si a alguien le sirviese de utilidad. Básicamente consiste en sobreescribir la clase OkHttpClient añadiéndole un interceptor.

public class DeviceHttpClient extends OkHttpClient {

    private static final String TAG = "DeviceHttpClient";

    public DeviceHttpClient(final Context context) {

        // Configure Timeouts
        setConnectTimeout(Constants.CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);

        try {
            // Configure Retry policy and Prioritize Wifi
            interceptors().add(
            new Interceptor() {
                   @Override
                   public Response intercept(Chain chain) throws IOException {
                       try {
                           boundRequestToWifi(context);
                           Request request = chain.request();
                           return chain.proceed(request);
                       } finally {
                           unBoundRequestToWifi(context);
                       }
                   }
               }
            );
        } catch (Exception e) {
            Log.e(TAG, "Error while initializing http client", e);
        }
    }

    @SuppressWarnings("deprecation")
    private void boundRequestToWifi(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

            Network[] networks = connectivityManager.getAllNetworks();
            if (networks != null && networks.length > 0) {
                for (Network network : networks) {
                    NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);

                    if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                            connectivityManager.bindProcessToNetwork(network);
                        }
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
                            Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                            ConnectivityManager.setProcessDefaultNetwork(network);
                        }
                        break;
                    }
                }
            }
        }
    }

    @SuppressWarnings("deprecation")
    private void unBoundRequestToWifi(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                connectivityManager.bindProcessToNetwork(null);
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
                Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                ConnectivityManager.setProcessDefaultNetwork(null);
            }
        }
    }
}

Actualización OkHttpClient 3 Se debe utilizar este interceptor:

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.os.Build;

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.Response;

public class BoundWifiInterceptor implements Interceptor {

    private final ConnectivityManager connectivityManager;

    public BoundWifiInterceptor(Context context) {
        this.connectivityManager = (ConnectivityManager) context.getSystemService(
                Context.CONNECTIVITY_SERVICE);
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        try {
            bindProcessToFirstWifiNetwork();
            return chain.proceed(chain.request());
        } finally {
            unbindProcessFromFirstWifiNetwork();
        }
    }

    @SuppressWarnings("deprecation")
    private void bindProcessToFirstWifiNetwork() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Network[] networks = connectivityManager.getAllNetworks();
            if (networks != null && networks.length > 0) {
                for (Network network : networks) {
                    NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
                    if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                            connectivityManager.bindProcessToNetwork(network);
                        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            ConnectivityManager.setProcessDefaultNetwork(network);
                        }
                        break;
                    }
                }
            }
        }
    }

    @SuppressWarnings("deprecation")
    private void unbindProcessFromFirstWifiNetwork() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                connectivityManager.bindProcessToNetwork(null);
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                ConnectivityManager.setProcessDefaultNetwork(null);
            }
        }
    }
}