From d37612ef0026d4dab9ab007212ba9b42ab80e809 Mon Sep 17 00:00:00 2001 From: Eric Deandrea Date: Thu, 4 Dec 2025 14:40:33 -0500 Subject: [PATCH 1/2] feat: Migrate to SLF4J for logging and update dependencies Replaced `java.util.logging` with SLF4J. Updated Gradle configurations to include `slf4j-api` and `slf4j-simple`. Adjusted tests and container logging to reflect new logging framework. Fixes #128 Signed-off-by: Eric Deandrea --- .../docling-serve-client/build.gradle.kts | 2 + .../serve/client/DoclingServeClient.java | 15 ++++--- docling-testcontainers/build.gradle.kts | 2 + .../docling/testcontainers/package-info.java | 4 -- .../serve/DoclingServeContainer.java | 17 ++++--- .../DoclingServeContainerAvailableTests.java | 44 ++++++++++++++++--- gradle/libs.versions.toml | 5 +++ 7 files changed, 66 insertions(+), 23 deletions(-) delete mode 100644 docling-testcontainers/src/main/java/ai/docling/testcontainers/package-info.java diff --git a/docling-serve/docling-serve-client/build.gradle.kts b/docling-serve/docling-serve-client/build.gradle.kts index f944b69..0774f71 100644 --- a/docling-serve/docling-serve-client/build.gradle.kts +++ b/docling-serve/docling-serve-client/build.gradle.kts @@ -7,6 +7,7 @@ description = "Docling Serve Client" dependencies { api(project(":docling-serve-api")) + api(libs.slf4j.api) implementation(platform(libs.jackson.bom)) implementation(libs.jackson.databind) implementation(libs.jackson2.databind) @@ -14,4 +15,5 @@ dependencies { testImplementation(platform(libs.testcontainers.bom)) testImplementation(libs.testcontainers.junit.jupiter) testImplementation(project(":docling-testcontainers")) + testImplementation(libs.slf4j.simple) } diff --git a/docling-serve/docling-serve-client/src/main/java/ai/docling/serve/client/DoclingServeClient.java b/docling-serve/docling-serve-client/src/main/java/ai/docling/serve/client/DoclingServeClient.java index dae21ab..245e7d2 100644 --- a/docling-serve/docling-serve-client/src/main/java/ai/docling/serve/client/DoclingServeClient.java +++ b/docling-serve/docling-serve-client/src/main/java/ai/docling/serve/client/DoclingServeClient.java @@ -14,8 +14,9 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.Flow.Subscriber; -import java.util.logging.Level; -import java.util.logging.Logger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import ai.docling.serve.api.DoclingServeApi; import ai.docling.serve.api.chunk.request.HierarchicalChunkDocumentRequest; @@ -37,7 +38,7 @@ * {@link #writeValueAsString(Object)} for serialization and deserialization behavior. */ public abstract class DoclingServeClient implements DoclingServeApi { - private static final Logger LOG = Logger.getLogger(DoclingServeClient.class.getName()); + private static final Logger LOG = LoggerFactory.getLogger(DoclingServeClient.class); protected static final URI DEFAULT_BASE_URL = URI.create("http://localhost:5001"); private final URI baseUrl; @@ -82,7 +83,7 @@ protected DoclingServeClient(DoclingServeClientBuilder builder) { protected abstract String writeValueAsString(T value); protected void logRequest(HttpRequest request) { - if (LOG.isLoggable(Level.INFO)) { + if (LOG.isInfoEnabled()) { var stringBuilder = new StringBuilder(); stringBuilder.append("\n→ REQUEST: %s %s\n".formatted(request.method(), request.uri())); stringBuilder.append(" HEADERS:\n"); @@ -96,7 +97,7 @@ protected void logRequest(HttpRequest request) { } protected void logResponse(HttpResponse response, Optional responseBody) { - if (LOG.isLoggable(Level.INFO)) { + if (LOG.isInfoEnabled()) { var stringBuilder = new StringBuilder(); stringBuilder.append("\n← RESPONSE: %s\n".formatted(response.statusCode())); stringBuilder.append(" HEADERS:\n"); @@ -124,7 +125,7 @@ protected T execute(HttpRequest request, Class expectedValueType) { } finally { long duration = System.currentTimeMillis() - startTime; - LOG.info(() -> "Request [%s %s] took %d ms".formatted(request.method(), request.uri(), duration)); + LOG.info("Request [{} {}] took {}ms", request.method(), request.uri(), duration); } } @@ -198,7 +199,7 @@ public long contentLength() { @Override public void subscribe(Subscriber subscriber) { if (logRequests) { - LOG.info(() -> "→ REQUEST BODY: %s".formatted(this.stringContent)); + LOG.info("→ REQUEST BODY: {}", this.stringContent); } this.delegate.subscribe(subscriber); diff --git a/docling-testcontainers/build.gradle.kts b/docling-testcontainers/build.gradle.kts index d198b88..354bf54 100644 --- a/docling-testcontainers/build.gradle.kts +++ b/docling-testcontainers/build.gradle.kts @@ -8,7 +8,9 @@ description = "Testcontainers for Docling services" dependencies { api(platform(libs.testcontainers.bom)) api("org.testcontainers:testcontainers") + api(libs.slf4j.api) testImplementation(platform(libs.jackson.bom)) testImplementation(libs.jackson.databind) testImplementation(libs.testcontainers.junit.jupiter) + testImplementation(libs.slf4j.simple) } diff --git a/docling-testcontainers/src/main/java/ai/docling/testcontainers/package-info.java b/docling-testcontainers/src/main/java/ai/docling/testcontainers/package-info.java deleted file mode 100644 index 7dc41fb..0000000 --- a/docling-testcontainers/src/main/java/ai/docling/testcontainers/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package ai.docling.testcontainers; - -import org.jspecify.annotations.NullMarked; diff --git a/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/DoclingServeContainer.java b/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/DoclingServeContainer.java index 634af57..67a90b6 100644 --- a/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/DoclingServeContainer.java +++ b/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/DoclingServeContainer.java @@ -1,7 +1,9 @@ package ai.docling.testcontainers.serve; -import java.util.logging.Logger; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.DockerImageName; @@ -18,7 +20,7 @@ * health checks for the container. */ public class DoclingServeContainer extends GenericContainer { - private static final Logger LOG = Logger.getLogger(DoclingServeContainer.class.getName()); + private static final Logger LOG = LoggerFactory.getLogger(DoclingServeContainer.class); /** * The default container port that docling runs on @@ -66,21 +68,22 @@ public int getPort() { * The URL where to access the Docling Serve API. */ public String getApiUrl() { - return "http://" + getHost() + ":" + getPort(); + return "http://%s:%d".formatted(getHost(), getPort()); } /** * The URL where to access the Docling Serve UI, if enabled. */ - public String getUiUrl() { - return getApiUrl() + "/ui"; + public Optional getUiUrl() { + return this.config.enableUi() ? + Optional.of("%s/ui".formatted(getApiUrl())) : + Optional.empty(); } @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { if (config.enableUi()) { - LOG.info(() -> "Docling Serve UI: %s".formatted(getUiUrl())); + LOG.info("Docling Serve UI: {}", getUiUrl()); } } - } diff --git a/docling-testcontainers/src/test/java/ai/docling/testcontainers/serve/DoclingServeContainerAvailableTests.java b/docling-testcontainers/src/test/java/ai/docling/testcontainers/serve/DoclingServeContainerAvailableTests.java index aa9059d..0ec0072 100644 --- a/docling-testcontainers/src/test/java/ai/docling/testcontainers/serve/DoclingServeContainerAvailableTests.java +++ b/docling-testcontainers/src/test/java/ai/docling/testcontainers/serve/DoclingServeContainerAvailableTests.java @@ -30,11 +30,22 @@ private record HealthResponse(String status) {} .build() ); + @Container + private final DoclingServeContainer noUiDoclingContainer = new DoclingServeContainer( + DoclingServeContainerConfig.builder() + .image(DoclingServeContainerConfig.DOCLING_IMAGE) + .enableUi(false) + .build() + ); + @Test - void containerAvailable() throws IOException, InterruptedException { - var healthRequest = HttpRequest.newBuilder( - URI.create("%s/health".formatted(this.doclingContainer.getApiUrl())) - ) + void containerNoUI() throws IOException, InterruptedException { + var config = DoclingServeContainerConfig.builder() + .image(DoclingServeContainerConfig.DOCLING_IMAGE) + .enableUi(false) + .build(); + + var healthRequest = HttpRequest.newBuilder(URI.create("%s/health".formatted(this.noUiDoclingContainer.getApiUrl()))) .header("Accept", "application/json") .timeout(Duration.ofSeconds(10)) .GET() @@ -50,7 +61,30 @@ void containerAvailable() throws IOException, InterruptedException { .isEqualTo(new HealthResponse("ok")); assertThat(this.doclingContainer.getUiUrl()) - .isEqualTo(this.doclingContainer.getApiUrl() + "/ui"); + .isNotNull() + .isEmpty(); + } + + @Test + void containerAvailable() throws IOException, InterruptedException { + var healthRequest = HttpRequest.newBuilder(URI.create("%s/health".formatted(this.doclingContainer.getApiUrl()))) + .header("Accept", "application/json") + .timeout(Duration.ofSeconds(10)) + .GET() + .build(); + + var response = HttpClient.newHttpClient() + .send(healthRequest, jsonBodyHandler(DoclingServeContainerAvailableTests.HealthResponse.class)) + .body(); + + assertThat(response) + .isNotNull() + .usingRecursiveComparison() + .isEqualTo(new HealthResponse("ok")); + + assertThat(this.doclingContainer.getUiUrl()) + .get() + .isEqualTo("%s/ui".formatted(this.doclingContainer.getApiUrl())); } private static HttpResponse.BodyHandler jsonBodyHandler(Class type) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4dbc7a0..55ba0c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ junit = "6.0.1" lombok = "1.18.42" lombok-gradle = "9.1.0" semver4j = "6.0.0" +slf4j = "2.0.17" testcontainers = "2.0.2" quarkus = "3.30.2" quarkus-github-api = "1.330.0" @@ -35,6 +36,10 @@ junit-bom = { group = "org.junit", name = "junit-bom", version.ref = "junit" } junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter" } junit-platform = { group = "org.junit.platform", name = "junit-platform-launcher" } +# SLF4j +slf4j-api = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" } +slf4j-simple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" } + # Testcontainers testcontainers-bom = { group = "org.testcontainers", name = "testcontainers-bom", version.ref = "testcontainers"} testcontainers-junit-jupiter = { group = "org.testcontainers", name = "testcontainers-junit-jupiter" } From e43c64c7e85ad06b67f8f36e737f0c4bf0f078d2 Mon Sep 17 00:00:00 2001 From: Eric Deandrea Date: Thu, 4 Dec 2025 14:51:04 -0500 Subject: [PATCH 2/2] feat: Migrate to SLF4J for logging and update dependencies Replaced `java.util.logging` with SLF4J. Updated Gradle configurations to include `slf4j-api` and `slf4j-simple`. Adjusted tests and container logging to reflect new logging framework. Fixes #128 Signed-off-by: Eric Deandrea --- .../testcontainers/serve/DoclingServeContainer.java | 4 +--- .../serve/DoclingServeContainerAvailableTests.java | 7 +------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/DoclingServeContainer.java b/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/DoclingServeContainer.java index 67a90b6..7fa3b3e 100644 --- a/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/DoclingServeContainer.java +++ b/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/DoclingServeContainer.java @@ -82,8 +82,6 @@ public Optional getUiUrl() { @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { - if (config.enableUi()) { - LOG.info("Docling Serve UI: {}", getUiUrl()); - } + getUiUrl().ifPresent(url -> LOG.info("Docling Serve UI: {}", url)); } } diff --git a/docling-testcontainers/src/test/java/ai/docling/testcontainers/serve/DoclingServeContainerAvailableTests.java b/docling-testcontainers/src/test/java/ai/docling/testcontainers/serve/DoclingServeContainerAvailableTests.java index 0ec0072..4a75977 100644 --- a/docling-testcontainers/src/test/java/ai/docling/testcontainers/serve/DoclingServeContainerAvailableTests.java +++ b/docling-testcontainers/src/test/java/ai/docling/testcontainers/serve/DoclingServeContainerAvailableTests.java @@ -40,11 +40,6 @@ private record HealthResponse(String status) {} @Test void containerNoUI() throws IOException, InterruptedException { - var config = DoclingServeContainerConfig.builder() - .image(DoclingServeContainerConfig.DOCLING_IMAGE) - .enableUi(false) - .build(); - var healthRequest = HttpRequest.newBuilder(URI.create("%s/health".formatted(this.noUiDoclingContainer.getApiUrl()))) .header("Accept", "application/json") .timeout(Duration.ofSeconds(10)) @@ -60,7 +55,7 @@ void containerNoUI() throws IOException, InterruptedException { .usingRecursiveComparison() .isEqualTo(new HealthResponse("ok")); - assertThat(this.doclingContainer.getUiUrl()) + assertThat(this.noUiDoclingContainer.getUiUrl()) .isNotNull() .isEmpty(); }