diff --git a/CHANGELOG.md b/CHANGELOG.md index db442c3..692f077 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 0.1.0 — Sin publicar +- Cambio incompatible: el cliente deja de registrar por defecto cada petición y + respuesta completas (`HttpLoggingInterceptor.Level.BODY`). El nuevo + `TuRuc.withLogLevel(Level)` activa el logging de OkHttp con el nivel indicado; + `logging-interceptor` pasa a ser dependencia `api`. - Compatibilidad verificada con Java 17, 21 y 25; JDK 25 para compilar por defecto y bytecode Java 17 para consumidores. - Gradle 9.8.1 con wrapper regenerado y SHA-256 de distribución verificado. diff --git a/README.md b/README.md index c399751..870c34f 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,6 @@ var page = client.searchContribuyentes("NUÑEZ", 0).execute(); síncrona o `enqueue()` para una asíncrona. - Crea el cliente una vez y reutilízalo; cada llamada a `getClient()` crea un cliente HTTP nuevo. -- El cliente registra cada petición y respuesta completas, con su cuerpo, en el - log de OkHttp. ### Respuestas @@ -97,6 +95,24 @@ completa. Para cambiarlos, indica los valores en segundos: TuRucClient client = new TuRuc("https://turuc.com.py/", 30, 10, 10, 5).getClient(); ``` +### Logging + +Por defecto, el cliente no registra el tráfico HTTP. Para depurar, indica un +nivel de `HttpLoggingInterceptor` de OkHttp: + +```java +import okhttp3.logging.HttpLoggingInterceptor; + +TuRucClient client = new TuRuc("https://turuc.com.py/") + .withLogLevel(HttpLoggingInterceptor.Level.BODY) + .getClient(); +``` + +`BASIC` registra la petición y el estado de la respuesta; `HEADERS` agrega las +cabeceras; `BODY` también registra los cuerpos, con los datos de los +contribuyentes consultados. Los mensajes van al log de OkHttp +(`java.util.logging`, logger `okhttp3.OkHttpClient`). + ## Migración desde 0.0.1-beta La versión 0.1.0 cambia el modelo `Contribuyente` para reflejar la respuesta @@ -122,6 +138,9 @@ si tu proyecto lo usa, decláralo por tu cuenta. Las dependencias transitivas pasan a Retrofit 3.0.0 y OkHttp 5.5.0. +El cliente ya no registra las peticiones y respuestas completas. Si dependías de +esos logs, actívalos con `withLogLevel(HttpLoggingInterceptor.Level.BODY)`. + ## Cambios Consulta [CHANGELOG.md](CHANGELOG.md) para conocer los cambios de cada versión. diff --git a/build.gradle b/build.gradle index f0e682b..f65be9e 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,8 @@ dependencies { api(platform("com.squareup.okhttp3:okhttp-bom:5.5.0")) implementation("com.squareup.okhttp3:okhttp") - implementation("com.squareup.okhttp3:logging-interceptor") + // HttpLoggingInterceptor.Level forma parte de la API pública (TuRuc.withLogLevel). + api("com.squareup.okhttp3:logging-interceptor") testImplementation(platform("org.junit:junit-bom:6.1.3")) testImplementation("org.junit.jupiter:junit-jupiter") diff --git a/src/main/java/org/ith/client/TuRuc.java b/src/main/java/org/ith/client/TuRuc.java index 7649846..b04c781 100644 --- a/src/main/java/org/ith/client/TuRuc.java +++ b/src/main/java/org/ith/client/TuRuc.java @@ -1,6 +1,7 @@ package org.ith.client; import com.alibaba.fastjson2.support.retrofit.Retrofit2ConverterFactory; +import java.util.Objects; import java.util.concurrent.TimeUnit; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; @@ -15,6 +16,7 @@ public class TuRuc { private final int writeTimeout; private final int readTimeout; private final int connectTimeout; + private HttpLoggingInterceptor.Level logLevel = HttpLoggingInterceptor.Level.NONE; public TuRuc(String apiUrl) { this.apiUrl = apiUrl; @@ -32,17 +34,28 @@ public TuRuc(String apiUrl, int callTimeout, int writeTimeout, int readTimeout, this.connectTimeout = connectTimeout; } + /** + * Registra el tráfico HTTP en el log de OkHttp. Por defecto no se registra nada; {@code BODY} incluye los + * datos de los contribuyentes consultados. + */ + public TuRuc withLogLevel(HttpLoggingInterceptor.Level logLevel) { + this.logLevel = Objects.requireNonNull(logLevel, "logLevel"); + return this; + } + public TuRucClient getClient() { - HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); - interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); // Http Client - OkHttpClient client = new OkHttpClient.Builder() - .addInterceptor(interceptor) + OkHttpClient.Builder builder = new OkHttpClient.Builder() .callTimeout(callTimeout, TimeUnit.SECONDS) .writeTimeout(writeTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) - .connectTimeout(connectTimeout, TimeUnit.SECONDS) - .build(); + .connectTimeout(connectTimeout, TimeUnit.SECONDS); + if (logLevel != HttpLoggingInterceptor.Level.NONE) { + HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); + interceptor.setLevel(logLevel); + builder.addInterceptor(interceptor); + } + OkHttpClient client = builder.build(); // Retrofit Retrofit retrofit = new Retrofit.Builder() .baseUrl(apiUrl) diff --git a/src/test/java/org/ith/client/TuRucClientTest.java b/src/test/java/org/ith/client/TuRucClientTest.java index 053152e..580409f 100644 --- a/src/test/java/org/ith/client/TuRucClientTest.java +++ b/src/test/java/org/ith/client/TuRucClientTest.java @@ -14,11 +14,18 @@ import java.net.URI; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; import java.util.stream.Collectors; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; import org.ith.model.Contribuyente; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -35,7 +42,7 @@ class TuRucClientTest { @BeforeEach void startServer() throws IOException { server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0); - client = new TuRuc("http://127.0.0.1:" + server.getAddress().getPort() + "/", 5, 5, 5, 5).getClient(); + client = new TuRuc(baseUrl(), 5, 5, 5, 5).getClient(); } @AfterEach @@ -43,6 +50,37 @@ void stopServer() { server.stop(0); } + @Test + void doesNotLogRequestsByDefault() throws Exception { + respond(200, """ + {"data":{"doc":80024191,"ruc":"80024191-6"},"message":"OK"} + """); + + var logs = captureOkHttpLogs(() -> client.getContribuyente("80024191-6").execute()); + + assertEquals(List.of(), logs); + } + + @Test + void logsResponseBodyWhenRequested() throws Exception { + respond(200, """ + {"data":{"doc":80024191,"ruc":"80024191-6"},"message":"OK"} + """); + var loggingClient = new TuRuc(baseUrl(), 5, 5, 5, 5) + .withLogLevel(HttpLoggingInterceptor.Level.BODY) + .getClient(); + + var logs = captureOkHttpLogs( + () -> loggingClient.getContribuyente("80024191-6").execute()); + + assertTrue(logs.stream().anyMatch(line -> line.contains("\"ruc\":\"80024191-6\"")), logs.toString()); + } + + @Test + void rejectsNullLogLevel() { + assertThrows(NullPointerException.class, () -> new TuRuc(baseUrl()).withLogLevel(null)); + } + @Test void looksUpContributorWithFullRuc() throws Exception { respond(200, """ @@ -156,6 +194,38 @@ private Map queryParameters(URI uri) { pair -> URLDecoder.decode(pair[1], StandardCharsets.UTF_8))); } + private String baseUrl() { + return "http://127.0.0.1:" + server.getAddress().getPort() + "/"; + } + + private interface Call { + void run() throws IOException; + } + + private static List captureOkHttpLogs(Call call) throws IOException { + var logger = Logger.getLogger(OkHttpClient.class.getName()); + var lines = new ArrayList(); + var handler = new Handler() { + @Override + public void publish(LogRecord logRecord) { + lines.add(logRecord.getMessage()); + } + + @Override + public void flush() {} + + @Override + public void close() {} + }; + logger.addHandler(handler); + try { + call.run(); + } finally { + logger.removeHandler(handler); + } + return lines; + } + private void respond(int status, String json) { server.createContext("/", exchange -> { requests.add(exchange.getRequestURI());