From b6b5205b1a769498f9a48cb956d56760a25a39a3 Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Thu, 1 Aug 2024 09:31:49 +0200 Subject: [PATCH 01/14] feat: Add RecentLogs support --- .../cloudfoundry/doppler/DopplerClient.java | 3 ++ .../logcache/v1/LogCacheClient.java | 8 ++++ .../applications/DefaultApplications.java | 41 +++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java index a9c03441cf..4e2c869b32 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java @@ -39,12 +39,15 @@ public interface DopplerClient { */ Flux firehose(FirehoseRequest request); + //TODO Adapt the message /** * Makes the Recent Logs request * + * @deprecated Do not use this type directly, it exists only for the Jackson-binding infrastructure * @param request the Recent Logs request * @return the events from the recent logs */ + @Deprecated Flux recentLogs(RecentLogsRequest request); /** diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/logcache/v1/LogCacheClient.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/logcache/v1/LogCacheClient.java index e455db220a..8a9b08505c 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/logcache/v1/LogCacheClient.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/logcache/v1/LogCacheClient.java @@ -46,4 +46,12 @@ public interface LogCacheClient { * @return the read response */ Mono read(ReadRequest request); + + /** + * Makes the Log Cache RecentLogs /api/v1/read request + * + * @param request the Recent Logs request + * @return the events from the recent logs + */ + Mono recentLogs(ReadRequest request); } diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java index e51ddbb472..718ab25245 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java @@ -40,6 +40,7 @@ import java.util.function.Predicate; import java.util.function.UnaryOperator; import java.util.stream.Collectors; + import org.cloudfoundry.client.CloudFoundryClient; import org.cloudfoundry.client.v2.OrderDirection; import org.cloudfoundry.client.v2.applications.AbstractApplicationResource; @@ -154,6 +155,9 @@ import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.doppler.RecentLogsRequest; import org.cloudfoundry.doppler.StreamRequest; +import org.cloudfoundry.logcache.v1.EnvelopeType; +import org.cloudfoundry.logcache.v1.LogCacheClient; +import org.cloudfoundry.logcache.v1.ReadRequest; import org.cloudfoundry.operations.util.OperationsLogging; import org.cloudfoundry.util.DateUtils; import org.cloudfoundry.util.DelayTimeoutException; @@ -200,6 +204,9 @@ public final class DefaultApplications implements Applications { private static final Comparator LOG_MESSAGE_COMPARATOR = Comparator.comparing(LogMessage::getTimestamp); + private static final Comparator LOG_MESSAGE_COMPARATOR_LOG_CACHE = + Comparator.comparing(org.cloudfoundry.logcache.v1.Envelope::getTimestamp); + private static final Duration LOG_MESSAGE_TIMESPAN = Duration.ofMillis(500); private static final int MAX_NUMBER_OF_RECENT_EVENTS = 50; @@ -1617,6 +1624,14 @@ private static Flux getLogs( } } + private static Flux getRecentLogs(Mono logCacheClient, String applicationId) { + return requestLogsRecentLogCache(logCacheClient, applicationId) + .filter(e -> EnvelopeType.LOG.getValue().equals(e.getLog().getType().getValue())) + .map(org.cloudfoundry.logcache.v1.Envelope::getLog) + .collectSortedList(LOG_MESSAGE_COMPARATOR_LOG_CACHE) + .flatMapIterable(d -> d); + } + @SuppressWarnings("unchecked") private static Map getMetadataRequest(EventEntity entity) { Map> metadata = @@ -2509,6 +2524,32 @@ private static Flux requestLogsRecent( RecentLogsRequest.builder().applicationId(applicationId).build())); } + private static Flux requestLogsRecentLogCache( + Mono logCacheClient, String applicationId) { + return logCacheClient.flatMapMany( + client -> + client.recentLogs( + ReadRequest.builder() + .sourceId(applicationId) + .envelopeType(EnvelopeType.LOG) + .limit(100) + .build() + ) + .flatMap( + response -> + Mono.justOrEmpty( + response.getEnvelopes().getBatch().stream().findFirst() + ) + ) + .repeatWhenEmpty( + exponentialBackOff( + Duration.ofSeconds(1), + Duration.ofSeconds(5), + Duration.ofMinutes(1)) + ) + ); + } + private static Flux requestLogsStream( Mono dopplerClient, String applicationId) { return dopplerClient.flatMapMany( From 1afe7df7bdedd834cd1414dbab051eeec30d741c Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Mon, 19 Aug 2024 12:28:00 +0200 Subject: [PATCH 02/14] fix: The Reactor part --- .../reactor/logcache/v1/ReactorLogCacheEndpoints.java | 4 ++++ .../reactor/logcache/v1/_ReactorLogCacheClient.java | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/logcache/v1/ReactorLogCacheEndpoints.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/logcache/v1/ReactorLogCacheEndpoints.java index 2e68c52538..f0b610d0c3 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/logcache/v1/ReactorLogCacheEndpoints.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/logcache/v1/ReactorLogCacheEndpoints.java @@ -48,4 +48,8 @@ Mono meta(MetaRequest request) { Mono read(ReadRequest request) { return get(request, ReadResponse.class, "read", request.getSourceId()).checkpoint(); } + + Mono recentLogs(ReadRequest request) { + return get(request, ReadResponse.class, "read", request.getSourceId()).checkpoint(); + } } diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/logcache/v1/_ReactorLogCacheClient.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/logcache/v1/_ReactorLogCacheClient.java index d9460476ea..286f4c787c 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/logcache/v1/_ReactorLogCacheClient.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/logcache/v1/_ReactorLogCacheClient.java @@ -53,6 +53,11 @@ public Mono read(ReadRequest request) { return getReactorLogCacheEndpoints().read(request); } + @Override + public Mono recentLogs(ReadRequest request) { + return getReactorLogCacheEndpoints().recentLogs(request); + } + /** * The connection context */ From 65a4f28107a2fe34f95a7f22f0f21b6b9c07b292 Mon Sep 17 00:00:00 2001 From: David O'Sullivan Date: Wed, 4 Sep 2024 16:48:48 +0100 Subject: [PATCH 03/14] logcache fix --- .../_DefaultCloudFoundryOperations.java | 16 ++++++- .../operations/applications/Applications.java | 3 +- .../applications/DefaultApplications.java | 47 ++++++++++--------- .../operations/AbstractOperationsTest.java | 3 ++ .../applications/DefaultApplicationsTest.java | 27 +++++------ .../operations/ApplicationsTest.java | 4 +- 6 files changed, 61 insertions(+), 39 deletions(-) diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java index 1d21f29b2b..7413a0a7fc 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java @@ -23,6 +23,7 @@ import org.cloudfoundry.client.v3.spaces.ListSpacesRequest; import org.cloudfoundry.client.v3.spaces.SpaceResource; import org.cloudfoundry.doppler.DopplerClient; +import org.cloudfoundry.logcache.v1.LogCacheClient; import org.cloudfoundry.networking.NetworkingClient; import org.cloudfoundry.operations.advanced.Advanced; import org.cloudfoundry.operations.advanced.DefaultAdvanced; @@ -79,7 +80,7 @@ public Advanced advanced() { @Override @Value.Derived public Applications applications() { - return new DefaultApplications(getCloudFoundryClientPublisher(), getDopplerClientPublisher(), getSpaceId()); + return new DefaultApplications(getCloudFoundryClientPublisher(), getDopplerClientPublisher(), getLogCacheClientPublisher(), getSpaceId()); } @Override @@ -190,6 +191,12 @@ Mono getCloudFoundryClientPublisher() { @Nullable abstract DopplerClient getDopplerClient(); + /** + * The {@link LogCacheClient} to use for operations functionality + */ + @Nullable + abstract LogCacheClient getLogCacheClient(); + @Value.Derived Mono getDopplerClientPublisher() { return Optional.ofNullable(getDopplerClient()) @@ -197,6 +204,13 @@ Mono getDopplerClientPublisher() { .orElse(Mono.error(new IllegalStateException("DopplerClient must be set"))); } + @Value.Derived + Mono getLogCacheClientPublisher() { + return Optional.ofNullable(getLogCacheClient()) + .map(Mono::just) + .orElse(Mono.error(new IllegalStateException("LogCacheClient must be set"))); + } + /** * The {@link NetworkingClient} to use for operations functionality */ diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java index 5196fef6c8..2f0750523e 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java @@ -17,6 +17,7 @@ package org.cloudfoundry.operations.applications; import org.cloudfoundry.doppler.LogMessage; +import org.cloudfoundry.logcache.v1.Log; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -124,7 +125,7 @@ public interface Applications { * @deprecated Use {@link #logs(ApplicationLogsRequest)} instead. */ @Deprecated - Flux logs(LogsRequest request); + Flux logs(LogsRequest request); /** * List the applications logs. diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java index 718ab25245..be6f0cf1bf 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java @@ -156,6 +156,7 @@ import org.cloudfoundry.doppler.RecentLogsRequest; import org.cloudfoundry.doppler.StreamRequest; import org.cloudfoundry.logcache.v1.EnvelopeType; +import org.cloudfoundry.logcache.v1.Log; import org.cloudfoundry.logcache.v1.LogCacheClient; import org.cloudfoundry.logcache.v1.ReadRequest; import org.cloudfoundry.operations.util.OperationsLogging; @@ -221,6 +222,8 @@ public final class DefaultApplications implements Applications { private final Mono dopplerClient; + private final Mono logCacheClient; + private final RandomWords randomWords; private final Mono spaceId; @@ -228,22 +231,25 @@ public final class DefaultApplications implements Applications { public DefaultApplications( Mono cloudFoundryClient, Mono dopplerClient, + Mono logCacheClient, Mono spaceId) { - this(cloudFoundryClient, dopplerClient, new WordListRandomWords(), spaceId); + this(cloudFoundryClient, dopplerClient, logCacheClient, new WordListRandomWords(), spaceId); } DefaultApplications( Mono cloudFoundryClient, Mono dopplerClient, + Mono logCacheClient, RandomWords randomWords, Mono spaceId) { this.cloudFoundryClient = cloudFoundryClient; this.dopplerClient = dopplerClient; + this.logCacheClient = logCacheClient; this.randomWords = randomWords; this.spaceId = spaceId; } - @Override +@Override public Mono copySource(CopySourceApplicationRequest request) { return Mono.zip(this.cloudFoundryClient, this.spaceId) .flatMap( @@ -537,7 +543,7 @@ public Flux listTasks(ListApplicationTasksRequest request) { } @Override - public Flux logs(LogsRequest request) { + public Flux logs(LogsRequest request) { return Mono.zip(this.cloudFoundryClient, this.spaceId) .flatMap( function( @@ -546,7 +552,7 @@ public Flux logs(LogsRequest request) { cloudFoundryClient, request.getName(), spaceId))) .flatMapMany( applicationId -> - getLogs(this.dopplerClient, applicationId, request.getRecent())) + getRecentLogs(this.logCacheClient, applicationId)) .transform(OperationsLogging.log("Get Application Logs")) .checkpoint(); } @@ -1607,30 +1613,29 @@ private static int getInstances(AbstractApplicationResource resource) { .orElse(0); } - private static Flux getLogs( - Mono dopplerClient, String applicationId, Boolean recent) { + /* private static Flux getLogs( + Mono logCacheClient, String applicationId, Boolean recent) { if (Optional.ofNullable(recent).orElse(false)) { - return requestLogsRecent(dopplerClient, applicationId) - .filter(e -> EventType.LOG_MESSAGE == e.getEventType()) - .map(Envelope::getLogMessage) - .collectSortedList(LOG_MESSAGE_COMPARATOR) - .flatMapIterable(d -> d); - } else { - return requestLogsStream(dopplerClient, applicationId) - .filter(e -> EventType.LOG_MESSAGE == e.getEventType()) - .map(Envelope::getLogMessage) - .transformDeferred( - SortingUtils.timespan(LOG_MESSAGE_COMPARATOR, LOG_MESSAGE_TIMESPAN)); + return getRecentLogs(logCacheClient, applicationId); } + }*/ + + private static Flux getRecentLogs(Mono logCacheClient, String applicationId) { + return requestLogsRecentLogCache(logCacheClient, applicationId) + .filter(e -> EnvelopeType.LOG.getValue().equals(e.getLog().getType().getValue())) + // .collectSortedList(LOG_MESSAGE_COMPARATOR_LOG_CACHE) + .sort(LOG_MESSAGE_COMPARATOR_LOG_CACHE) + .map(org.cloudfoundry.logcache.v1.Envelope::getLog); } - private static Flux getRecentLogs(Mono logCacheClient, String applicationId) { +/* private static Flux getRecentLogs(Mono logCacheClient, String applicationId) { return requestLogsRecentLogCache(logCacheClient, applicationId) .filter(e -> EnvelopeType.LOG.getValue().equals(e.getLog().getType().getValue())) + .sort(LOG_MESSAGE_COMPARATOR_LOG_CACHE) .map(org.cloudfoundry.logcache.v1.Envelope::getLog) - .collectSortedList(LOG_MESSAGE_COMPARATOR_LOG_CACHE) - .flatMapIterable(d -> d); - } + .collectList() + .flatMapIterable(d1 -> d1).cast(org.cloudfoundry.logcache.v1.Log.class); + } */ @SuppressWarnings("unchecked") private static Map getMetadataRequest(EventEntity entity) { diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java index ab1250658a..9dd97126e8 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java @@ -53,6 +53,7 @@ import org.cloudfoundry.client.v3.stacks.StacksV3; import org.cloudfoundry.client.v3.tasks.Tasks; import org.cloudfoundry.doppler.DopplerClient; +import org.cloudfoundry.logcache.v1.LogCacheClient; import org.cloudfoundry.routing.RoutingClient; import org.cloudfoundry.routing.v1.routergroups.RouterGroups; import org.cloudfoundry.uaa.UaaClient; @@ -104,6 +105,8 @@ public abstract class AbstractOperationsTest { protected final DopplerClient dopplerClient = mock(DopplerClient.class, RETURNS_SMART_NULLS); + protected final LogCacheClient logCacheClient = mock(LogCacheClient.class, RETURNS_SMART_NULLS); + protected final Events events = mock(Events.class, RETURNS_SMART_NULLS); protected final FeatureFlags featureFlags = mock(FeatureFlags.class, RETURNS_SMART_NULLS); diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java index cdc9619d2d..685c572717 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java @@ -144,6 +144,10 @@ import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.doppler.RecentLogsRequest; import org.cloudfoundry.doppler.StreamRequest; +import org.cloudfoundry.logcache.v1.Log; +import org.cloudfoundry.logcache.v1.LogCacheClient; +import org.cloudfoundry.logcache.v1.ReadRequest; +import org.cloudfoundry.logcache.v1.ReadResponse; import org.cloudfoundry.operations.AbstractOperationsTest; import org.cloudfoundry.util.DateUtils; import org.cloudfoundry.util.FluentMap; @@ -163,6 +167,7 @@ final class DefaultApplicationsTest extends AbstractOperationsTest { new DefaultApplications( Mono.just(this.cloudFoundryClient), Mono.just(this.dopplerClient), + Mono.just(this.logCacheClient), this.randomWords, Mono.just(TEST_SPACE_ID)); @@ -1318,7 +1323,7 @@ void logs() { this.applications .logs(LogsRequest.builder().name("test-application-name").recent(false).build()) .as(StepVerifier::create) - .expectNext(fill(LogMessage.builder(), "log-message-").build()) + .expectNext(fill(Log.builder(), "log-message-").build()) .expectComplete() .verify(Duration.ofSeconds(5)); } @@ -1346,12 +1351,12 @@ void logsRecent() { "test-application-name", TEST_SPACE_ID, "test-metadata-id"); - requestLogsRecent(this.dopplerClient, "test-metadata-id"); + requestLogsRecentLogCache(this.logCacheClient, "test-metadata-id"); this.applications .logs(LogsRequest.builder().name("test-application-name").recent(true).build()) .as(StepVerifier::create) - .expectNext(fill(LogMessage.builder(), "log-message-").build()) + .expectNext(fill(Log.builder(), "log-message-").build()) .expectComplete() .verify(Duration.ofSeconds(5)); } @@ -1368,7 +1373,7 @@ void logsRecentNotSet() { this.applications .logs(LogsRequest.builder().name("test-application-name").build()) .as(StepVerifier::create) - .expectNext(fill(LogMessage.builder(), "log-message-").build()) + .expectNext(fill(Log.builder(), "log-message-").build()) .expectComplete() .verify(Duration.ofSeconds(5)); } @@ -5317,17 +5322,11 @@ private static void requestListTasksEmpty( .build())); } - private static void requestLogsRecent(DopplerClient dopplerClient, String applicationId) { - when(dopplerClient.recentLogs( - RecentLogsRequest.builder().applicationId(applicationId).build())) + private static void requestLogsRecentLogCache(LogCacheClient logCacheClient, String applicationId) { + when(logCacheClient.recentLogs( + ReadRequest.builder().sourceId(applicationId).build())) .thenReturn( - Flux.just( - Envelope.builder() - .eventType(EventType.LOG_MESSAGE) - .logMessage( - fill(LogMessage.builder(), "log-message-").build()) - .origin("rsp") - .build())); + Mono.just(ReadResponse.builder().envelopes(fill(org.cloudfoundry.logcache.v1.EnvelopeBatch.builder()).build()).build())); } private static void requestLogsStream(DopplerClient dopplerClient, String applicationId) { diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java index 36e1bd9456..cf2cde4aa6 100644 --- a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java +++ b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java @@ -529,10 +529,10 @@ public void logs() throws IOException { .name(applicationName) .recent(true) .build())) - .map(ApplicationLog::getLogType) + .map(org.cloudfoundry.logcache.v1.Log::getType) .next() .as(StepVerifier::create) - .expectNext(ApplicationLogType.OUT) + .expectNext(org.cloudfoundry.logcache.v1.LogType.OUT) .expectComplete() .verify(Duration.ofMinutes(5)); } From bdc5ce3e29ded8f34fdcc723c2f5f620faecb118 Mon Sep 17 00:00:00 2001 From: David O'Sullivan Date: Wed, 30 Oct 2024 16:36:05 +0000 Subject: [PATCH 04/14] logcache client impl --- .../ReactorServiceInstancesV3Test.java | 1 + .../_DefaultCloudFoundryOperations.java | 12 +++---- .../operations/applications/Applications.java | 4 ++- .../applications/DefaultApplications.java | 35 +++++++++---------- .../applications/DefaultApplicationsTest.java | 29 ++++++++++----- .../IntegrationTestConfiguration.java | 3 ++ .../operations/ApplicationsTest.java | 3 +- 7 files changed, 51 insertions(+), 36 deletions(-) diff --git a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceinstances/ReactorServiceInstancesV3Test.java b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceinstances/ReactorServiceInstancesV3Test.java index 1e6df1f258..1745aa7285 100644 --- a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceinstances/ReactorServiceInstancesV3Test.java +++ b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceinstances/ReactorServiceInstancesV3Test.java @@ -62,6 +62,7 @@ import org.cloudfoundry.reactor.TestRequest; import org.cloudfoundry.reactor.TestResponse; import org.cloudfoundry.reactor.client.AbstractClientApiTest; +import org.cloudfoundry.reactor.client.v3.serviceinstances.ReactorServiceInstancesV3; import org.junit.jupiter.api.Test; import reactor.test.StepVerifier; diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java index 7413a0a7fc..4db0bd8489 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java @@ -191,12 +191,6 @@ Mono getCloudFoundryClientPublisher() { @Nullable abstract DopplerClient getDopplerClient(); - /** - * The {@link LogCacheClient} to use for operations functionality - */ - @Nullable - abstract LogCacheClient getLogCacheClient(); - @Value.Derived Mono getDopplerClientPublisher() { return Optional.ofNullable(getDopplerClient()) @@ -204,6 +198,12 @@ Mono getDopplerClientPublisher() { .orElse(Mono.error(new IllegalStateException("DopplerClient must be set"))); } + /** + * The {@link LogCacheClient} to use for operations functionality + */ + @Nullable + abstract LogCacheClient getLogCacheClient(); + @Value.Derived Mono getLogCacheClientPublisher() { return Optional.ofNullable(getLogCacheClient()) diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java index 2f0750523e..31a4ad510c 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java @@ -18,6 +18,8 @@ import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.logcache.v1.Log; +import org.cloudfoundry.logcache.v1.ReadRequest; +import org.cloudfoundry.logcache.v1.ReadResponse; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -125,7 +127,7 @@ public interface Applications { * @deprecated Use {@link #logs(ApplicationLogsRequest)} instead. */ @Deprecated - Flux logs(LogsRequest request); + Flux logs(ReadRequest request); /** * List the applications logs. diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java index be6f0cf1bf..62d76d5c08 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java @@ -159,6 +159,7 @@ import org.cloudfoundry.logcache.v1.Log; import org.cloudfoundry.logcache.v1.LogCacheClient; import org.cloudfoundry.logcache.v1.ReadRequest; +import org.cloudfoundry.logcache.v1.ReadResponse; import org.cloudfoundry.operations.util.OperationsLogging; import org.cloudfoundry.util.DateUtils; import org.cloudfoundry.util.DelayTimeoutException; @@ -543,13 +544,13 @@ public Flux listTasks(ListApplicationTasksRequest request) { } @Override - public Flux logs(LogsRequest request) { + public Flux logs(ReadRequest request) { return Mono.zip(this.cloudFoundryClient, this.spaceId) .flatMap( function( (cloudFoundryClient, spaceId) -> getApplicationId( - cloudFoundryClient, request.getName(), spaceId))) + cloudFoundryClient, request.getSourceId(), spaceId))) .flatMapMany( applicationId -> getRecentLogs(this.logCacheClient, applicationId)) @@ -686,7 +687,6 @@ public Mono pushManifestV3(PushManifestV3Request request) { } catch (IOException e) { throw new RuntimeException("Could not serialize manifest", e); } - return Mono.zip(this.cloudFoundryClient, this.spaceId) .flatMap( function( @@ -1613,30 +1613,29 @@ private static int getInstances(AbstractApplicationResource resource) { .orElse(0); } - /* private static Flux getLogs( - Mono logCacheClient, String applicationId, Boolean recent) { + private static Flux getLogs( + Mono dopplerClient, String applicationId, Boolean recent) { if (Optional.ofNullable(recent).orElse(false)) { - return getRecentLogs(logCacheClient, applicationId); + return requestLogsRecent(dopplerClient, applicationId) + .filter(e -> EventType.LOG_MESSAGE == e.getEventType()) + .map(Envelope::getLogMessage) + .collectSortedList(LOG_MESSAGE_COMPARATOR) + .flatMapIterable(d -> d); + } else { + return requestLogsStream(dopplerClient, applicationId) + .filter(e -> EventType.LOG_MESSAGE == e.getEventType()) + .map(Envelope::getLogMessage) + .transformDeferred( + SortingUtils.timespan(LOG_MESSAGE_COMPARATOR, LOG_MESSAGE_TIMESPAN)); } - }*/ + } private static Flux getRecentLogs(Mono logCacheClient, String applicationId) { return requestLogsRecentLogCache(logCacheClient, applicationId) - .filter(e -> EnvelopeType.LOG.getValue().equals(e.getLog().getType().getValue())) - // .collectSortedList(LOG_MESSAGE_COMPARATOR_LOG_CACHE) .sort(LOG_MESSAGE_COMPARATOR_LOG_CACHE) .map(org.cloudfoundry.logcache.v1.Envelope::getLog); } -/* private static Flux getRecentLogs(Mono logCacheClient, String applicationId) { - return requestLogsRecentLogCache(logCacheClient, applicationId) - .filter(e -> EnvelopeType.LOG.getValue().equals(e.getLog().getType().getValue())) - .sort(LOG_MESSAGE_COMPARATOR_LOG_CACHE) - .map(org.cloudfoundry.logcache.v1.Envelope::getLog) - .collectList() - .flatMapIterable(d1 -> d1).cast(org.cloudfoundry.logcache.v1.Log.class); - } */ - @SuppressWarnings("unchecked") private static Map getMetadataRequest(EventEntity entity) { Map> metadata = diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java index 685c572717..e10e673a2d 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java @@ -144,8 +144,11 @@ import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.doppler.RecentLogsRequest; import org.cloudfoundry.doppler.StreamRequest; +import org.cloudfoundry.logcache.v1.EnvelopeBatch; +import org.cloudfoundry.logcache.v1.EnvelopeType; import org.cloudfoundry.logcache.v1.Log; import org.cloudfoundry.logcache.v1.LogCacheClient; +import org.cloudfoundry.logcache.v1.LogType; import org.cloudfoundry.logcache.v1.ReadRequest; import org.cloudfoundry.logcache.v1.ReadResponse; import org.cloudfoundry.operations.AbstractOperationsTest; @@ -1318,10 +1321,10 @@ void logs() { "test-application-name", TEST_SPACE_ID, "test-metadata-id"); - requestLogsStream(this.dopplerClient, "test-metadata-id"); + requestLogsRecentLogCache(this.logCacheClient, "test-application-name"); this.applications - .logs(LogsRequest.builder().name("test-application-name").recent(false).build()) + .logs(ReadRequest.builder().sourceId("test-application-name").build()) .as(StepVerifier::create) .expectNext(fill(Log.builder(), "log-message-").build()) .expectComplete() @@ -1333,7 +1336,7 @@ void logsNoApp() { requestApplicationsEmpty(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); this.applications - .logs(LogsRequest.builder().name("test-application-name").build()) + .logs(ReadRequest.builder().sourceId("test-application-name").build()) .as(StepVerifier::create) .consumeErrorWith( t -> @@ -1354,7 +1357,7 @@ void logsRecent() { requestLogsRecentLogCache(this.logCacheClient, "test-metadata-id"); this.applications - .logs(LogsRequest.builder().name("test-application-name").recent(true).build()) + .logs(ReadRequest.builder().sourceId("test-application-name").build()) .as(StepVerifier::create) .expectNext(fill(Log.builder(), "log-message-").build()) .expectComplete() @@ -1371,7 +1374,7 @@ void logsRecentNotSet() { requestLogsStream(this.dopplerClient, "test-metadata-id"); this.applications - .logs(LogsRequest.builder().name("test-application-name").build()) + .logs(ReadRequest.builder().sourceId("test-application-name").build()) .as(StepVerifier::create) .expectNext(fill(Log.builder(), "log-message-").build()) .expectComplete() @@ -5323,10 +5326,18 @@ private static void requestListTasksEmpty( } private static void requestLogsRecentLogCache(LogCacheClient logCacheClient, String applicationId) { - when(logCacheClient.recentLogs( - ReadRequest.builder().sourceId(applicationId).build())) - .thenReturn( - Mono.just(ReadResponse.builder().envelopes(fill(org.cloudfoundry.logcache.v1.EnvelopeBatch.builder()).build()).build())); + when(logCacheClient.recentLogs( + ReadRequest.builder().sourceId(applicationId).build())) + .thenReturn( + Mono.just(fill(ReadResponse.builder()) + .envelopes(fill(EnvelopeBatch.builder()) + .batch(fill(org.cloudfoundry.logcache.v1.Envelope.builder()) + .log(fill(Log.builder()) + .payload("test-payload") + .type(LogType.OUT).build()) + .build()) + .build()) + .build())); } private static void requestLogsStream(DopplerClient dopplerClient, String applicationId) { diff --git a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java index 36c30c3578..58b01252f0 100644 --- a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java +++ b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java @@ -48,6 +48,7 @@ import org.cloudfoundry.client.v2.stacks.StackResource; import org.cloudfoundry.client.v2.userprovidedserviceinstances.CreateUserProvidedServiceInstanceRequest; import org.cloudfoundry.doppler.DopplerClient; +import org.cloudfoundry.logcache.v1.LogCacheClient; import org.cloudfoundry.logcache.v1.TestLogCacheEndpoints; import org.cloudfoundry.networking.NetworkingClient; import org.cloudfoundry.operations.DefaultCloudFoundryOperations; @@ -273,6 +274,7 @@ ReactorCloudFoundryClient cloudFoundryClient( DefaultCloudFoundryOperations cloudFoundryOperations( CloudFoundryClient cloudFoundryClient, DopplerClient dopplerClient, + LogCacheClient logCacheClient, NetworkingClient networkingClient, RoutingClient routingClient, UaaClient uaaClient, @@ -281,6 +283,7 @@ DefaultCloudFoundryOperations cloudFoundryOperations( return DefaultCloudFoundryOperations.builder() .cloudFoundryClient(cloudFoundryClient) .dopplerClient(dopplerClient) + .logCacheClient(logCacheClient) .networkingClient(networkingClient) .routingClient(routingClient) .uaaClient(uaaClient) diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java index cf2cde4aa6..a70e276875 100644 --- a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java +++ b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java @@ -526,8 +526,7 @@ public void logs() throws IOException { .applications() .logs( ApplicationLogsRequest.builder() - .name(applicationName) - .recent(true) + .sourceId(applicationName) .build())) .map(org.cloudfoundry.logcache.v1.Log::getType) .next() From 94f022203d37ba2e0eacba0de158cf7d68945029 Mon Sep 17 00:00:00 2001 From: Anthony Dahanne Date: Thu, 31 Oct 2024 12:37:08 -0400 Subject: [PATCH 05/14] Fix expectations * because of the findFirst() on the envelopes, it could be type OUT or ERR, so we don't really care, as long as the payload is the same. Also, we don't care about the precise argument to the recentLogs call --- .../applications/DefaultApplicationsTest.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java index e10e673a2d..bfb4c28d39 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java @@ -20,6 +20,7 @@ import static org.cloudfoundry.client.v3.LifecycleType.BUILDPACK; import static org.cloudfoundry.client.v3.LifecycleType.DOCKER; import static org.cloudfoundry.operations.TestObjects.fill; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.RETURNS_SMART_NULLS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -1326,7 +1327,7 @@ void logs() { this.applications .logs(ReadRequest.builder().sourceId("test-application-name").build()) .as(StepVerifier::create) - .expectNext(fill(Log.builder(), "log-message-").build()) + .expectNextMatches(log -> log.getPayload().equals("test-payload")) .expectComplete() .verify(Duration.ofSeconds(5)); } @@ -5327,16 +5328,16 @@ private static void requestListTasksEmpty( private static void requestLogsRecentLogCache(LogCacheClient logCacheClient, String applicationId) { when(logCacheClient.recentLogs( - ReadRequest.builder().sourceId(applicationId).build())) + any())) .thenReturn( Mono.just(fill(ReadResponse.builder()) - .envelopes(fill(EnvelopeBatch.builder()) - .batch(fill(org.cloudfoundry.logcache.v1.Envelope.builder()) - .log(fill(Log.builder()) - .payload("test-payload") - .type(LogType.OUT).build()) - .build()) - .build()) + .envelopes(fill(EnvelopeBatch.builder()) + .batch(fill(org.cloudfoundry.logcache.v1.Envelope.builder()) + .log(fill(Log.builder()) + .payload("test-payload") + .type(LogType.OUT).build()) + .build()) + .build()) .build())); } From c04c38345e09aea3f142fd2e20d711b0a68baac2 Mon Sep 17 00:00:00 2001 From: David O'Sullivan Date: Fri, 1 Nov 2024 12:46:50 +0000 Subject: [PATCH 06/14] test only recent logs request --- .../operations/applications/Applications.java | 2 +- .../applications/DefaultApplications.java | 4 +- .../applications/DefaultApplicationsTest.java | 90 ++++++++++--------- 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java index 31a4ad510c..9c4c68ca3d 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java @@ -127,7 +127,7 @@ public interface Applications { * @deprecated Use {@link #logs(ApplicationLogsRequest)} instead. */ @Deprecated - Flux logs(ReadRequest request); + Flux logs(LogsRequest request); /** * List the applications logs. diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java index 62d76d5c08..9e8dfc8c95 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java @@ -544,13 +544,13 @@ public Flux listTasks(ListApplicationTasksRequest request) { } @Override - public Flux logs(ReadRequest request) { + public Flux logs(LogsRequest request) { return Mono.zip(this.cloudFoundryClient, this.spaceId) .flatMap( function( (cloudFoundryClient, spaceId) -> getApplicationId( - cloudFoundryClient, request.getSourceId(), spaceId))) + cloudFoundryClient, request.getName(), spaceId))) .flatMapMany( applicationId -> getRecentLogs(this.logCacheClient, applicationId)) diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java index bfb4c28d39..79914016d4 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java @@ -156,6 +156,7 @@ import org.cloudfoundry.util.DateUtils; import org.cloudfoundry.util.FluentMap; import org.cloudfoundry.util.ResourceMatchingUtils; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.core.io.ClassPathResource; import reactor.core.publisher.Flux; @@ -1325,7 +1326,7 @@ void logs() { requestLogsRecentLogCache(this.logCacheClient, "test-application-name"); this.applications - .logs(ReadRequest.builder().sourceId("test-application-name").build()) + .logs(LogsRequest.builder().name("test-application-name").recent(true).build()) .as(StepVerifier::create) .expectNextMatches(log -> log.getPayload().equals("test-payload")) .expectComplete() @@ -1337,7 +1338,7 @@ void logsNoApp() { requestApplicationsEmpty(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); this.applications - .logs(ReadRequest.builder().sourceId("test-application-name").build()) + .logs(LogsRequest.builder().name("test-application-name").build()) .as(StepVerifier::create) .consumeErrorWith( t -> @@ -1348,39 +1349,40 @@ void logsNoApp() { .verify(Duration.ofSeconds(5)); } - @Test - void logsRecent() { - requestApplications( - this.cloudFoundryClient, - "test-application-name", - TEST_SPACE_ID, - "test-metadata-id"); - requestLogsRecentLogCache(this.logCacheClient, "test-metadata-id"); - - this.applications - .logs(ReadRequest.builder().sourceId("test-application-name").build()) - .as(StepVerifier::create) - .expectNext(fill(Log.builder(), "log-message-").build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - void logsRecentNotSet() { - requestApplications( - this.cloudFoundryClient, - "test-application-name", - TEST_SPACE_ID, - "test-metadata-id"); - requestLogsStream(this.dopplerClient, "test-metadata-id"); - - this.applications - .logs(ReadRequest.builder().sourceId("test-application-name").build()) - .as(StepVerifier::create) - .expectNext(fill(Log.builder(), "log-message-").build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } + // TODO: it's not passing since recentLogs is not properly implemented yet with logcacheclient + @Test + void logsRecent() { + requestApplications( + this.cloudFoundryClient, + "test-application-name", + TEST_SPACE_ID, + "test-metadata-id"); + requestLogsRecentLogCache(this.logCacheClient, "test-metadata-id"); + + this.applications + .logs(LogsRequest.builder().name("test-application-name").build()) + .as(StepVerifier::create) + .expectNext(fill(Log.builder(), "log-message-").build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + // TODO: it's not passing since recentLogs is not properly implemented yet with logcacheclient + @Test + void logsRecentNotSet() { + requestApplications( + this.cloudFoundryClient, + "test-application-name", + TEST_SPACE_ID, + "test-metadata-id"); + requestLogsStream(this.dopplerClient, "test-metadata-id"); + + this.applications + .logs(LogsRequest.builder().name("test-application-name").build()) + .as(StepVerifier::create) + .expectNext(fill(Log.builder(), "log-message-").build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } @Test void pushDocker() { @@ -5331,14 +5333,16 @@ private static void requestLogsRecentLogCache(LogCacheClient logCacheClient, Str any())) .thenReturn( Mono.just(fill(ReadResponse.builder()) - .envelopes(fill(EnvelopeBatch.builder()) - .batch(fill(org.cloudfoundry.logcache.v1.Envelope.builder()) - .log(fill(Log.builder()) - .payload("test-payload") - .type(LogType.OUT).build()) - .build()) - .build()) - .build())); + .envelopes(fill(EnvelopeBatch.builder()) + .batch(fill(org.cloudfoundry.logcache.v1.Envelope + .builder()) + .log(fill(Log.builder()) + .payload("test-payload") + .type(LogType.OUT) + .build()) + .build()) + .build()) + .build())); } private static void requestLogsStream(DopplerClient dopplerClient, String applicationId) { From 46f69f40b1411e3685c543834fb1683d200d8f3f Mon Sep 17 00:00:00 2001 From: Georg Lokowandt Date: Wed, 23 Apr 2025 18:29:45 +0200 Subject: [PATCH 07/14] Fix JUnit tests for logCache The old "Applications.logs" method is keept for compatibility and when a log stream is needed. Adding new "logsRecent" method to access the logCache. integration-tests "ApplicationTest.logs" and "ApplicationTest.logsRecent" work. Minor changes in DefaultApplicationsTest in other JUnit tests to make them execute in Eclipse. --- .../operations/applications/Applications.java | 11 +- .../applications/DefaultApplications.java | 130 ++++++++++++++- .../applications/DefaultApplicationsTest.java | 155 +++++++++++------- .../operations/ApplicationsTest.java | 62 ++++++- 4 files changed, 293 insertions(+), 65 deletions(-) diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java index 9c4c68ca3d..6549f0a84c 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java @@ -19,7 +19,7 @@ import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.logcache.v1.Log; import org.cloudfoundry.logcache.v1.ReadRequest; -import org.cloudfoundry.logcache.v1.ReadResponse; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -129,6 +129,15 @@ public interface Applications { @Deprecated Flux logs(LogsRequest request); + /** + * List the applications logs from logCacheClient. + * If no messages are available, an empty Flux is returned. + * + * @param request the application logs request + * @return the applications logs + */ + Flux logsRecent(ReadRequest request); + /** * List the applications logs. * Only works with {@code Loggregator < 107.0}, shipped in {@code CFD < 24.3} diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java index 9e8dfc8c95..1121e739fc 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java @@ -150,12 +150,10 @@ import org.cloudfoundry.client.v3.tasks.CreateTaskResponse; import org.cloudfoundry.client.v3.tasks.TaskResource; import org.cloudfoundry.doppler.DopplerClient; -import org.cloudfoundry.doppler.Envelope; import org.cloudfoundry.doppler.EventType; import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.doppler.RecentLogsRequest; import org.cloudfoundry.doppler.StreamRequest; -import org.cloudfoundry.logcache.v1.EnvelopeType; import org.cloudfoundry.logcache.v1.Log; import org.cloudfoundry.logcache.v1.LogCacheClient; import org.cloudfoundry.logcache.v1.ReadRequest; @@ -578,6 +576,83 @@ public Flux logs(ApplicationLogsRequest request) { .build()); } + @SuppressWarnings("deprecation") + @Test + void logsRecent_doppler() { + requestApplications( + this.cloudFoundryClient, + "test-application-name", + TEST_SPACE_ID, + "test-metadata-id"); + requestLogsRecent(this.dopplerClient, "test-metadata-id"); + this.applications + .logs(LogsRequest.builder().name("test-application-name").recent(true).build()) + .as(StepVerifier::create) + .expectNextMatches(log -> log.getMessage().equals("test-log-message-message")) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @SuppressWarnings("deprecation") + @Test + void logsNoApp_doppler() { + requestApplicationsEmpty(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); + + this.applications + .verify(Duration.ofSeconds(5)); + } + + @SuppressWarnings("deprecation") + @Test + void logs_doppler() { + requestApplications( + this.cloudFoundryClient, + "test-application-name", + TEST_SPACE_ID, + "test-metadata-id"); + requestLogsStream(this.dopplerClient, "test-metadata-id"); + this.applications + .logs(LogsRequest.builder().name("test-application-name").recent(false).build()) + .as(StepVerifier::create) + .expectNextMatches(log -> log.getMessage().equals("test-log-message-message")) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @Test + void logsRecent_LogCache() { + requestApplications( + this.cloudFoundryClient, + "test-application-name", + TEST_SPACE_ID, + "test-metadata-id"); + requestLogsRecentLogCache(this.logCacheClient, "test-metadata-id", "test-payload"); + this.applications + .logsRecent(ReadRequest.builder().sourceId("test-application-name").build()) + .as(StepVerifier::create) + .expectNext(fill(Log.builder()).type(LogType.OUT).build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @SuppressWarnings("deprecation") + @Test + void logsRecentNotSet_doppler() { + requestApplications( + this.cloudFoundryClient, + "test-application-name", + TEST_SPACE_ID, + "test-metadata-id"); + requestLogsStream(this.dopplerClient, "test-metadata-id"); + + this.applications + .logs(LogsRequest.builder().name("test-application-name").build()) + .as(StepVerifier::create) + .expectNext(fill(LogMessage.builder(), "log-message-").build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + @Override @SuppressWarnings("deprecation") public Mono push(PushApplicationRequest request) { @@ -2432,6 +2507,57 @@ private static Mono requestGetApplication( .cast(AbstractApplicationResource.class); } + private static void requestInstancesApplicationFailing( + CloudFoundryClient cloudFoundryClient, String applicationId) { + when(cloudFoundryClient + .applicationsV2() + .instances( + ApplicationInstancesRequest.builder() + .applicationId(applicationId) + .build())) + .thenReturn( + Mono.just( + fill( + ApplicationInstancesResponse.builder(), + "application-instances-") + .instance( + "instance-0", + fill( + ApplicationInstanceInfo.builder(), + "application-instance-info-") + .state("FAILED") + .build()) + .build())); + } + + private static void requestLogsRecentLogCache( + LogCacheClient logCacheClient, String applicationName, String payload) { + when(logCacheClient.recentLogs(any())) + .thenReturn( + Mono.just( + fill(ReadResponse.builder()) + .envelopes( + fill(EnvelopeBatch.builder()) + .batch( + Arrays.asList( + fill(org.cloudfoundry + .logcache.v1 + .Envelope + .builder()) + .log( + Log + .builder() + .payload( + payload) + .type( + LogType + .OUT) + .build()) + .build())) + .build()) + .build())); + } + private static Flux requestListDomains( CloudFoundryClient cloudFoundryClient, String organizationId) { return PaginationUtils.requestClientV3Resources( diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java index 79914016d4..08effafac7 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java @@ -140,13 +140,11 @@ import org.cloudfoundry.client.v3.tasks.CreateTaskResponse; import org.cloudfoundry.client.v3.tasks.TaskResource; import org.cloudfoundry.doppler.DopplerClient; -import org.cloudfoundry.doppler.Envelope; import org.cloudfoundry.doppler.EventType; import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.doppler.RecentLogsRequest; import org.cloudfoundry.doppler.StreamRequest; import org.cloudfoundry.logcache.v1.EnvelopeBatch; -import org.cloudfoundry.logcache.v1.EnvelopeType; import org.cloudfoundry.logcache.v1.Log; import org.cloudfoundry.logcache.v1.LogCacheClient; import org.cloudfoundry.logcache.v1.LogType; @@ -156,7 +154,6 @@ import org.cloudfoundry.util.DateUtils; import org.cloudfoundry.util.FluentMap; import org.cloudfoundry.util.ResourceMatchingUtils; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.core.io.ClassPathResource; import reactor.core.publisher.Flux; @@ -1316,25 +1313,26 @@ void listTasks() { .verify(Duration.ofSeconds(5)); } + @SuppressWarnings("deprecation") @Test - void logs() { + void logsRecent_doppler() { requestApplications( this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID, "test-metadata-id"); - requestLogsRecentLogCache(this.logCacheClient, "test-application-name"); - + requestLogsRecent(this.dopplerClient, "test-metadata-id"); this.applications .logs(LogsRequest.builder().name("test-application-name").recent(true).build()) .as(StepVerifier::create) - .expectNextMatches(log -> log.getPayload().equals("test-payload")) + .expectNextMatches(log -> log.getMessage().equals("test-log-message-message")) .expectComplete() .verify(Duration.ofSeconds(5)); } + @SuppressWarnings("deprecation") @Test - void logsNoApp() { + void logsNoApp_doppler() { requestApplicationsEmpty(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); this.applications @@ -1349,40 +1347,56 @@ void logsNoApp() { .verify(Duration.ofSeconds(5)); } - // TODO: it's not passing since recentLogs is not properly implemented yet with logcacheclient - @Test - void logsRecent() { - requestApplications( - this.cloudFoundryClient, - "test-application-name", - TEST_SPACE_ID, - "test-metadata-id"); - requestLogsRecentLogCache(this.logCacheClient, "test-metadata-id"); - - this.applications - .logs(LogsRequest.builder().name("test-application-name").build()) - .as(StepVerifier::create) - .expectNext(fill(Log.builder(), "log-message-").build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - // TODO: it's not passing since recentLogs is not properly implemented yet with logcacheclient - @Test - void logsRecentNotSet() { - requestApplications( - this.cloudFoundryClient, - "test-application-name", - TEST_SPACE_ID, - "test-metadata-id"); - requestLogsStream(this.dopplerClient, "test-metadata-id"); - - this.applications - .logs(LogsRequest.builder().name("test-application-name").build()) - .as(StepVerifier::create) - .expectNext(fill(Log.builder(), "log-message-").build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } + @SuppressWarnings("deprecation") + @Test + void logs_doppler() { + requestApplications( + this.cloudFoundryClient, + "test-application-name", + TEST_SPACE_ID, + "test-metadata-id"); + requestLogsStream(this.dopplerClient, "test-metadata-id"); + this.applications + .logs(LogsRequest.builder().name("test-application-name").recent(false).build()) + .as(StepVerifier::create) + .expectNextMatches(log -> log.getMessage().equals("test-log-message-message")) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @Test + void logsRecent_LogCache() { + requestApplications( + this.cloudFoundryClient, + "test-application-name", + TEST_SPACE_ID, + "test-metadata-id"); + requestLogsRecentLogCache(this.logCacheClient, "test-metadata-id", "test-payload"); + this.applications + .logsRecent(ReadRequest.builder().sourceId("test-application-name").build()) + .as(StepVerifier::create) + .expectNext(fill(Log.builder()).type(LogType.OUT).build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @SuppressWarnings("deprecation") + @Test + void logsRecentNotSet_doppler() { + requestApplications( + this.cloudFoundryClient, + "test-application-name", + TEST_SPACE_ID, + "test-metadata-id"); + requestLogsStream(this.dopplerClient, "test-metadata-id"); + + this.applications + .logs(LogsRequest.builder().name("test-application-name").build()) + .as(StepVerifier::create) + .expectNext(fill(LogMessage.builder(), "log-message-").build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } @Test void pushDocker() { @@ -5328,28 +5342,53 @@ private static void requestListTasksEmpty( .build())); } - private static void requestLogsRecentLogCache(LogCacheClient logCacheClient, String applicationId) { - when(logCacheClient.recentLogs( - any())) - .thenReturn( - Mono.just(fill(ReadResponse.builder()) - .envelopes(fill(EnvelopeBatch.builder()) - .batch(fill(org.cloudfoundry.logcache.v1.Envelope - .builder()) - .log(fill(Log.builder()) - .payload("test-payload") - .type(LogType.OUT) - .build()) - .build()) - .build()) - .build())); + private static void requestLogsRecentLogCache( + LogCacheClient logCacheClient, String applicationName, String payload) { + when(logCacheClient.recentLogs(any())) + .thenReturn( + Mono.just( + fill(ReadResponse.builder()) + .envelopes( + fill(EnvelopeBatch.builder()) + .batch( + Arrays.asList( + fill(org.cloudfoundry + .logcache.v1 + .Envelope + .builder()) + .log( + Log + .builder() + .payload( + payload) + .type( + LogType + .OUT) + .build()) + .build())) + .build()) + .build())); } private static void requestLogsStream(DopplerClient dopplerClient, String applicationId) { when(dopplerClient.stream(StreamRequest.builder().applicationId(applicationId).build())) .thenReturn( Flux.just( - Envelope.builder() + org.cloudfoundry.doppler.Envelope.builder() + .eventType(EventType.LOG_MESSAGE) + .logMessage( + fill(LogMessage.builder(), "log-message-").build()) + .origin("rsp") + .build())); + } + + @SuppressWarnings("deprecation") + private static void requestLogsRecent(DopplerClient dopplerClient, String applicationId) { + when(dopplerClient.recentLogs( + RecentLogsRequest.builder().applicationId(applicationId).build())) + .thenReturn( + Flux.just( + org.cloudfoundry.doppler.Envelope.builder() .eventType(EventType.LOG_MESSAGE) .logMessage( fill(LogMessage.builder(), "log-message-").build()) diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java index a70e276875..19d784cb16 100644 --- a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java +++ b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.logging.Level; import org.cloudfoundry.AbstractIntegrationTest; import org.cloudfoundry.CleanupCloudFoundryAfterClass; import org.cloudfoundry.CloudFoundryVersion; @@ -86,6 +87,7 @@ import org.cloudfoundry.operations.services.CreateUserProvidedServiceInstanceRequest; import org.cloudfoundry.operations.services.GetServiceInstanceRequest; import org.cloudfoundry.operations.services.ServiceInstance; +import org.cloudfoundry.operations.util.OperationsLogging; import org.cloudfoundry.util.FluentMap; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -93,6 +95,7 @@ import org.springframework.core.io.ClassPathResource; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.core.publisher.SignalType; import reactor.test.StepVerifier; @CleanupCloudFoundryAfterClass @@ -511,6 +514,7 @@ public void listTasks() throws IOException { * Doppler was dropped in PCF 4.x in favor of logcache. This test does not work * on TAS 4.x. */ + @Deprecated @Test @IfCloudFoundryVersion(lessThan = CloudFoundryVersion.PCF_4_v2) public void logs() throws IOException { @@ -525,13 +529,40 @@ public void logs() throws IOException { this.cloudFoundryOperations .applications() .logs( - ApplicationLogsRequest.builder() - .sourceId(applicationName) + LogsRequest.builder() + .name(applicationName) + .recent(true) .build())) - .map(org.cloudfoundry.logcache.v1.Log::getType) + .map(LogMessage::getMessageType) .next() .as(StepVerifier::create) - .expectNext(org.cloudfoundry.logcache.v1.LogType.OUT) + .expectNext(MessageType.OUT) + .expectComplete() + .verify(Duration.ofMinutes(5)); + } + + @Test + public void logsRecent() throws IOException { + String applicationName = this.nameFactory.getApplicationName(); + Mono applicationGuid = + getAppGuidFromAppName(cloudFoundryOperations, applicationName); + createApplication( + this.cloudFoundryOperations, + new ClassPathResource("test-application.zip").getFile().toPath(), + applicationName, + false) + .then( + applicationGuid + .map(ApplicationsTest::getReadRequest) + .flatMapMany( + readRequest -> + callLogsRecent( + this.cloudFoundryOperations, + readRequest) + .log(null, Level.ALL, SignalType.ON_NEXT)) + .map(ApplicationsTest::checkOneLogEntry) + .then()) + .as(StepVerifier::create) .expectComplete() .verify(Duration.ofMinutes(5)); } @@ -2155,4 +2186,27 @@ private static Mono requestSshEnabled( .applications() .sshEnabled(ApplicationSshEnabledRequest.builder().name(applicationName).build()); } + + private static ReadRequest getReadRequest(String applicationId) { + return ReadRequest.builder().sourceId(applicationId).build(); + } + + private static Flux callLogsRecent( + CloudFoundryOperations cloudFoundryOperations, ReadRequest readRequest) { + return cloudFoundryOperations.applications().logsRecent(readRequest); + } + + private static Mono getAppGuidFromAppName( + CloudFoundryOperations cloudFoundryOperations, String applicationName) { + return cloudFoundryOperations + .applications() + .get(GetApplicationRequest.builder().name(applicationName).build()) + .map(ApplicationDetail::getId); + } + + private static Log checkOneLogEntry(Log log) { + assertThat(log.getType().equals(LogType.OUT)); + OperationsLogging.log("one log entry: " + log.getType() + " " + log.getPayloadAsText()); + return log; + } } From 62f01151907b65455d095ffaffc3ca574c5d1df8 Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Thu, 26 Feb 2026 08:01:21 +0100 Subject: [PATCH 08/14] fix: Adjust the merge conflicts --- .../operations/applications/Applications.java | 8 + .../applications/DefaultApplications.java | 163 +++++------------- 2 files changed, 50 insertions(+), 121 deletions(-) diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java index 6549f0a84c..b484e7f586 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java @@ -117,6 +117,14 @@ public interface Applications { */ Flux listTasks(ListApplicationTasksRequest request); + /** + * List the applications logs from dopplerClient + * @deprecated Only for compatibility. Switch to logCacheClient method below. + * @param request the application logs request + * @return the applications logs + */ + Flux logs(LogsRequest request); + /** * List the applications logs. Uses Doppler under the hood. * Only works with {@code Loggregator < 107.0}, shipped in {@code CFD < 24.3} diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java index 1121e739fc..880bcdc339 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java @@ -158,6 +158,8 @@ import org.cloudfoundry.logcache.v1.LogCacheClient; import org.cloudfoundry.logcache.v1.ReadRequest; import org.cloudfoundry.logcache.v1.ReadResponse; +import org.cloudfoundry.logcache.v1.EnvelopeBatch; +import org.cloudfoundry.logcache.v1.Envelope; import org.cloudfoundry.operations.util.OperationsLogging; import org.cloudfoundry.util.DateUtils; import org.cloudfoundry.util.DelayTimeoutException; @@ -248,7 +250,7 @@ public DefaultApplications( this.spaceId = spaceId; } -@Override + @Override public Mono copySource(CopySourceApplicationRequest request) { return Mono.zip(this.cloudFoundryClient, this.spaceId) .flatMap( @@ -541,8 +543,9 @@ public Flux listTasks(ListApplicationTasksRequest request) { .checkpoint(); } + @Deprecated @Override - public Flux logs(LogsRequest request) { + public Flux logs(LogsRequest request) { return Mono.zip(this.cloudFoundryClient, this.spaceId) .flatMap( function( @@ -551,107 +554,37 @@ public Flux logs(LogsRequest request) { cloudFoundryClient, request.getName(), spaceId))) .flatMapMany( applicationId -> - getRecentLogs(this.logCacheClient, applicationId)) + getLogs(this.dopplerClient, applicationId, request.getRecent())) .transform(OperationsLogging.log("Get Application Logs")) .checkpoint(); } @Override - public Flux logs(ApplicationLogsRequest request) { - return logs(LogsRequest.builder() - .name(request.getName()) - .recent(request.getRecent()) - .build()) - .map( - logMessage -> - ApplicationLog.builder() - .sourceId(logMessage.getApplicationId()) - .sourceType(logMessage.getSourceType()) - .instanceId(logMessage.getSourceInstance()) - .message(logMessage.getMessage()) - .timestamp(logMessage.getTimestamp()) - .logType( - ApplicationLogType.from( - logMessage.getMessageType().name())) - .build()); - } - - @SuppressWarnings("deprecation") - @Test - void logsRecent_doppler() { - requestApplications( - this.cloudFoundryClient, - "test-application-name", - TEST_SPACE_ID, - "test-metadata-id"); - requestLogsRecent(this.dopplerClient, "test-metadata-id"); - this.applications - .logs(LogsRequest.builder().name("test-application-name").recent(true).build()) - .as(StepVerifier::create) - .expectNextMatches(log -> log.getMessage().equals("test-log-message-message")) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @SuppressWarnings("deprecation") - @Test - void logsNoApp_doppler() { - requestApplicationsEmpty(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); - - this.applications - .verify(Duration.ofSeconds(5)); - } - - @SuppressWarnings("deprecation") - @Test - void logs_doppler() { - requestApplications( - this.cloudFoundryClient, - "test-application-name", - TEST_SPACE_ID, - "test-metadata-id"); - requestLogsStream(this.dopplerClient, "test-metadata-id"); - this.applications - .logs(LogsRequest.builder().name("test-application-name").recent(false).build()) - .as(StepVerifier::create) - .expectNextMatches(log -> log.getMessage().equals("test-log-message-message")) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - void logsRecent_LogCache() { - requestApplications( - this.cloudFoundryClient, - "test-application-name", - TEST_SPACE_ID, - "test-metadata-id"); - requestLogsRecentLogCache(this.logCacheClient, "test-metadata-id", "test-payload"); - this.applications - .logsRecent(ReadRequest.builder().sourceId("test-application-name").build()) - .as(StepVerifier::create) - .expectNext(fill(Log.builder()).type(LogType.OUT).build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); + public Flux logsRecent(ReadRequest request) { + return getRecentLogsLogCache(this.logCacheClient, request) + .transform(OperationsLogging.log("Get Application Logs")) + .checkpoint(); } - @SuppressWarnings("deprecation") - @Test - void logsRecentNotSet_doppler() { - requestApplications( - this.cloudFoundryClient, - "test-application-name", - TEST_SPACE_ID, - "test-metadata-id"); - requestLogsStream(this.dopplerClient, "test-metadata-id"); - - this.applications - .logs(LogsRequest.builder().name("test-application-name").build()) - .as(StepVerifier::create) - .expectNext(fill(LogMessage.builder(), "log-message-").build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } +// @Override +// public Flux logs(ApplicationLogsRequest request) { +// return logs(LogsRequest.builder() +// .name(request.getName()) +// .recent(request.getRecent()) +// .build()) +// .map( +// logMessage -> +// ApplicationLog.builder() +// .sourceId(logMessage.getApplicationId()) +// .sourceType(logMessage.getSourceType()) +// .instanceId(logMessage.getSourceInstance()) +// .message(logMessage.getMessage()) +// .timestamp(logMessage.getTimestamp()) +// .logType( +// ApplicationLogType.from( +// logMessage.getMessageType().name())) +// .build()); +// } @Override @SuppressWarnings("deprecation") @@ -1705,8 +1638,13 @@ private static Flux getLogs( } } - private static Flux getRecentLogs(Mono logCacheClient, String applicationId) { - return requestLogsRecentLogCache(logCacheClient, applicationId) + private static Flux getRecentLogsLogCache( + Mono logCacheClient, ReadRequest readRequest) { + return requestLogsRecentLogCache(logCacheClient, readRequest) + .map(EnvelopeBatch::getBatch) + .map(List::stream) + .flatMapIterable(envelopeStream -> envelopeStream.collect(Collectors.toList())) + .filter(e -> e.getLog() != null) .sort(LOG_MESSAGE_COMPARATOR_LOG_CACHE) .map(org.cloudfoundry.logcache.v1.Envelope::getLog); } @@ -2646,6 +2584,7 @@ private static Flux requestListTasks( .build())); } + @Deprecated private static Flux requestLogsRecent( Mono dopplerClient, String applicationId) { return dopplerClient.flatMapMany( @@ -2654,30 +2593,12 @@ private static Flux requestLogsRecent( RecentLogsRequest.builder().applicationId(applicationId).build())); } - private static Flux requestLogsRecentLogCache( - Mono logCacheClient, String applicationId) { - return logCacheClient.flatMapMany( + private static Mono requestLogsRecentLogCache( + Mono logCacheClient, ReadRequest readRequest) { + return logCacheClient.flatMap( client -> - client.recentLogs( - ReadRequest.builder() - .sourceId(applicationId) - .envelopeType(EnvelopeType.LOG) - .limit(100) - .build() - ) - .flatMap( - response -> - Mono.justOrEmpty( - response.getEnvelopes().getBatch().stream().findFirst() - ) - ) - .repeatWhenEmpty( - exponentialBackOff( - Duration.ofSeconds(1), - Duration.ofSeconds(5), - Duration.ofMinutes(1)) - ) - ); + client.recentLogs(readRequest) + .flatMap(response -> Mono.justOrEmpty(response.getEnvelopes()))); } private static Flux requestLogsStream( From d917da486e045b8f7bd5f176c4af13980106e8de Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Thu, 26 Feb 2026 08:52:07 +0100 Subject: [PATCH 09/14] fix: Adjust the code and tests --- .../operations/applications/Applications.java | 10 +- .../applications/DefaultApplications.java | 92 ++++-------------- .../applications/DefaultApplicationsTest.java | 96 +++++++++---------- 3 files changed, 69 insertions(+), 129 deletions(-) diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java index b484e7f586..38ffb6251e 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java @@ -117,14 +117,6 @@ public interface Applications { */ Flux listTasks(ListApplicationTasksRequest request); - /** - * List the applications logs from dopplerClient - * @deprecated Only for compatibility. Switch to logCacheClient method below. - * @param request the application logs request - * @return the applications logs - */ - Flux logs(LogsRequest request); - /** * List the applications logs. Uses Doppler under the hood. * Only works with {@code Loggregator < 107.0}, shipped in {@code CFD < 24.3} @@ -135,7 +127,7 @@ public interface Applications { * @deprecated Use {@link #logs(ApplicationLogsRequest)} instead. */ @Deprecated - Flux logs(LogsRequest request); + Flux logs(LogsRequest request); /** * List the applications logs from logCacheClient. diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java index 880bcdc339..22a923607d 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java @@ -154,12 +154,11 @@ import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.doppler.RecentLogsRequest; import org.cloudfoundry.doppler.StreamRequest; +import org.cloudfoundry.doppler.Envelope; import org.cloudfoundry.logcache.v1.Log; import org.cloudfoundry.logcache.v1.LogCacheClient; import org.cloudfoundry.logcache.v1.ReadRequest; -import org.cloudfoundry.logcache.v1.ReadResponse; import org.cloudfoundry.logcache.v1.EnvelopeBatch; -import org.cloudfoundry.logcache.v1.Envelope; import org.cloudfoundry.operations.util.OperationsLogging; import org.cloudfoundry.util.DateUtils; import org.cloudfoundry.util.DelayTimeoutException; @@ -566,25 +565,25 @@ public Flux logsRecent(ReadRequest request) { .checkpoint(); } -// @Override -// public Flux logs(ApplicationLogsRequest request) { -// return logs(LogsRequest.builder() -// .name(request.getName()) -// .recent(request.getRecent()) -// .build()) -// .map( -// logMessage -> -// ApplicationLog.builder() -// .sourceId(logMessage.getApplicationId()) -// .sourceType(logMessage.getSourceType()) -// .instanceId(logMessage.getSourceInstance()) -// .message(logMessage.getMessage()) -// .timestamp(logMessage.getTimestamp()) -// .logType( -// ApplicationLogType.from( -// logMessage.getMessageType().name())) -// .build()); -// } + @Override + public Flux logs(ApplicationLogsRequest request) { + return logs(LogsRequest.builder() + .name(request.getName()) + .recent(request.getRecent()) + .build()) + .map( + logMessage -> + ApplicationLog.builder() + .sourceId(logMessage.getApplicationId()) + .sourceType(logMessage.getSourceType()) + .instanceId(logMessage.getSourceInstance()) + .message(logMessage.getMessage()) + .timestamp(logMessage.getTimestamp()) + .logType( + ApplicationLogType.from( + logMessage.getMessageType().name())) + .build()); + } @Override @SuppressWarnings("deprecation") @@ -2445,57 +2444,6 @@ private static Mono requestGetApplication( .cast(AbstractApplicationResource.class); } - private static void requestInstancesApplicationFailing( - CloudFoundryClient cloudFoundryClient, String applicationId) { - when(cloudFoundryClient - .applicationsV2() - .instances( - ApplicationInstancesRequest.builder() - .applicationId(applicationId) - .build())) - .thenReturn( - Mono.just( - fill( - ApplicationInstancesResponse.builder(), - "application-instances-") - .instance( - "instance-0", - fill( - ApplicationInstanceInfo.builder(), - "application-instance-info-") - .state("FAILED") - .build()) - .build())); - } - - private static void requestLogsRecentLogCache( - LogCacheClient logCacheClient, String applicationName, String payload) { - when(logCacheClient.recentLogs(any())) - .thenReturn( - Mono.just( - fill(ReadResponse.builder()) - .envelopes( - fill(EnvelopeBatch.builder()) - .batch( - Arrays.asList( - fill(org.cloudfoundry - .logcache.v1 - .Envelope - .builder()) - .log( - Log - .builder() - .payload( - payload) - .type( - LogType - .OUT) - .build()) - .build())) - .build()) - .build())); - } - private static Flux requestListDomains( CloudFoundryClient cloudFoundryClient, String organizationId) { return PaginationUtils.requestClientV3Resources( diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java index 08effafac7..5594830836 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java @@ -5054,44 +5054,72 @@ private static void requestGetApplicationFailing( .build())); } - private static void requestInstancesApplicationFailing( + private static void requestGetApplicationTimeout( CloudFoundryClient cloudFoundryClient, String applicationId) { when(cloudFoundryClient .applicationsV2() - .instances( - ApplicationInstancesRequest.builder() + .get( + org.cloudfoundry.client.v2.applications.GetApplicationRequest + .builder() .applicationId(applicationId) .build())) + .thenReturn( + Mono.just( + fill(GetApplicationResponse.builder()) + .entity( + fill(ApplicationEntity.builder()) + .packageState("STAGING") + .build()) + .build())); + } + + private static void requestInstancesApplicationFailing( + CloudFoundryClient cloudFoundryClient, String applicationId) { + when(cloudFoundryClient + .applicationsV2() + .instances( + ApplicationInstancesRequest.builder() + .applicationId(applicationId) + .build())) .thenReturn( Mono.just( fill( - ApplicationInstancesResponse.builder(), - "application-instances-") + ApplicationInstancesResponse.builder(), + "application-instances-") .instance( "instance-0", fill( - ApplicationInstanceInfo.builder(), - "application-instance-info-") + ApplicationInstanceInfo.builder(), + "application-instance-info-") .state("FAILED") .build()) .build())); } - private static void requestGetApplicationTimeout( - CloudFoundryClient cloudFoundryClient, String applicationId) { - when(cloudFoundryClient - .applicationsV2() - .get( - org.cloudfoundry.client.v2.applications.GetApplicationRequest - .builder() - .applicationId(applicationId) - .build())) + private static void requestLogsRecentLogCache( + LogCacheClient logCacheClient, String applicationName, String payload) { + when(logCacheClient.recentLogs(any())) .thenReturn( Mono.just( - fill(GetApplicationResponse.builder()) - .entity( - fill(ApplicationEntity.builder()) - .packageState("STAGING") + fill(ReadResponse.builder()) + .envelopes( + fill(EnvelopeBatch.builder()) + .batch( + Arrays.asList( + fill(org.cloudfoundry + .logcache.v1 + .Envelope + .builder()) + .log( + Log + .builder() + .payload( + payload) + .type( + LogType + .OUT) + .build()) + .build())) .build()) .build())); } @@ -5342,34 +5370,6 @@ private static void requestListTasksEmpty( .build())); } - private static void requestLogsRecentLogCache( - LogCacheClient logCacheClient, String applicationName, String payload) { - when(logCacheClient.recentLogs(any())) - .thenReturn( - Mono.just( - fill(ReadResponse.builder()) - .envelopes( - fill(EnvelopeBatch.builder()) - .batch( - Arrays.asList( - fill(org.cloudfoundry - .logcache.v1 - .Envelope - .builder()) - .log( - Log - .builder() - .payload( - payload) - .type( - LogType - .OUT) - .build()) - .build())) - .build()) - .build())); - } - private static void requestLogsStream(DopplerClient dopplerClient, String applicationId) { when(dopplerClient.stream(StreamRequest.builder().applicationId(applicationId).build())) .thenReturn( From 1abc21050f088132a5d5f5757e8f242d0e93b17b Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Thu, 26 Feb 2026 11:55:22 +0100 Subject: [PATCH 10/14] feat: Adjust the integrationtests --- .../java/org/cloudfoundry/operations/ApplicationsTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java index 19d784cb16..e3cc443c50 100644 --- a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java +++ b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java @@ -529,14 +529,14 @@ public void logs() throws IOException { this.cloudFoundryOperations .applications() .logs( - LogsRequest.builder() + ApplicationLogsRequest.builder() .name(applicationName) .recent(true) .build())) - .map(LogMessage::getMessageType) + .map(ApplicationLog::getLogType) .next() .as(StepVerifier::create) - .expectNext(MessageType.OUT) + .expectNext(ApplicationLogType.OUT) .expectComplete() .verify(Duration.ofMinutes(5)); } From 210376c48ed68d9a3b318688cea91cba5f2166f4 Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Thu, 26 Feb 2026 15:05:21 +0100 Subject: [PATCH 11/14] fix: Adjust the lint issues --- .../ReactorServiceInstancesV3Test.java | 1 - .../cloudfoundry/doppler/DopplerClient.java | 2 +- .../operations/applications/Applications.java | 1 - .../applications/DefaultApplications.java | 10 ++++---- .../applications/DefaultApplicationsTest.java | 24 +++++++++---------- .../operations/ApplicationsTest.java | 12 +++++----- 6 files changed, 24 insertions(+), 26 deletions(-) diff --git a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceinstances/ReactorServiceInstancesV3Test.java b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceinstances/ReactorServiceInstancesV3Test.java index 1745aa7285..1e6df1f258 100644 --- a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceinstances/ReactorServiceInstancesV3Test.java +++ b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceinstances/ReactorServiceInstancesV3Test.java @@ -62,7 +62,6 @@ import org.cloudfoundry.reactor.TestRequest; import org.cloudfoundry.reactor.TestResponse; import org.cloudfoundry.reactor.client.AbstractClientApiTest; -import org.cloudfoundry.reactor.client.v3.serviceinstances.ReactorServiceInstancesV3; import org.junit.jupiter.api.Test; import reactor.test.StepVerifier; diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java index 4e2c869b32..44d5306036 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java @@ -39,7 +39,7 @@ public interface DopplerClient { */ Flux firehose(FirehoseRequest request); - //TODO Adapt the message + // TODO Adapt the message /** * Makes the Recent Logs request * diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java index 38ffb6251e..53317ccb63 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java @@ -19,7 +19,6 @@ import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.logcache.v1.Log; import org.cloudfoundry.logcache.v1.ReadRequest; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java index 22a923607d..2f1bdef41a 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java @@ -40,7 +40,6 @@ import java.util.function.Predicate; import java.util.function.UnaryOperator; import java.util.stream.Collectors; - import org.cloudfoundry.client.CloudFoundryClient; import org.cloudfoundry.client.v2.OrderDirection; import org.cloudfoundry.client.v2.applications.AbstractApplicationResource; @@ -150,15 +149,15 @@ import org.cloudfoundry.client.v3.tasks.CreateTaskResponse; import org.cloudfoundry.client.v3.tasks.TaskResource; import org.cloudfoundry.doppler.DopplerClient; +import org.cloudfoundry.doppler.Envelope; import org.cloudfoundry.doppler.EventType; import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.doppler.RecentLogsRequest; import org.cloudfoundry.doppler.StreamRequest; -import org.cloudfoundry.doppler.Envelope; +import org.cloudfoundry.logcache.v1.EnvelopeBatch; import org.cloudfoundry.logcache.v1.Log; import org.cloudfoundry.logcache.v1.LogCacheClient; import org.cloudfoundry.logcache.v1.ReadRequest; -import org.cloudfoundry.logcache.v1.EnvelopeBatch; import org.cloudfoundry.operations.util.OperationsLogging; import org.cloudfoundry.util.DateUtils; import org.cloudfoundry.util.DelayTimeoutException; @@ -205,8 +204,9 @@ public final class DefaultApplications implements Applications { private static final Comparator LOG_MESSAGE_COMPARATOR = Comparator.comparing(LogMessage::getTimestamp); - private static final Comparator LOG_MESSAGE_COMPARATOR_LOG_CACHE = - Comparator.comparing(org.cloudfoundry.logcache.v1.Envelope::getTimestamp); + private static final Comparator + LOG_MESSAGE_COMPARATOR_LOG_CACHE = + Comparator.comparing(org.cloudfoundry.logcache.v1.Envelope::getTimestamp); private static final Duration LOG_MESSAGE_TIMESPAN = Duration.ofMillis(500); diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java index 5594830836..5695108af7 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java @@ -5076,21 +5076,21 @@ private static void requestGetApplicationTimeout( private static void requestInstancesApplicationFailing( CloudFoundryClient cloudFoundryClient, String applicationId) { when(cloudFoundryClient - .applicationsV2() - .instances( - ApplicationInstancesRequest.builder() - .applicationId(applicationId) - .build())) + .applicationsV2() + .instances( + ApplicationInstancesRequest.builder() + .applicationId(applicationId) + .build())) .thenReturn( Mono.just( fill( - ApplicationInstancesResponse.builder(), - "application-instances-") + ApplicationInstancesResponse.builder(), + "application-instances-") .instance( "instance-0", fill( - ApplicationInstanceInfo.builder(), - "application-instance-info-") + ApplicationInstanceInfo.builder(), + "application-instance-info-") .state("FAILED") .build()) .build())); @@ -5107,9 +5107,9 @@ private static void requestLogsRecentLogCache( .batch( Arrays.asList( fill(org.cloudfoundry - .logcache.v1 - .Envelope - .builder()) + .logcache.v1 + .Envelope + .builder()) .log( Log .builder() diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java index e3cc443c50..832afe3c07 100644 --- a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java +++ b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java @@ -547,18 +547,18 @@ public void logsRecent() throws IOException { Mono applicationGuid = getAppGuidFromAppName(cloudFoundryOperations, applicationName); createApplication( - this.cloudFoundryOperations, - new ClassPathResource("test-application.zip").getFile().toPath(), - applicationName, - false) + this.cloudFoundryOperations, + new ClassPathResource("test-application.zip").getFile().toPath(), + applicationName, + false) .then( applicationGuid .map(ApplicationsTest::getReadRequest) .flatMapMany( readRequest -> callLogsRecent( - this.cloudFoundryOperations, - readRequest) + this.cloudFoundryOperations, + readRequest) .log(null, Level.ALL, SignalType.ON_NEXT)) .map(ApplicationsTest::checkOneLogEntry) .then()) From 0d8873bdcd64483b0ac0508f46057971f58af8af Mon Sep 17 00:00:00 2001 From: Joris Baum Date: Thu, 26 Feb 2026 11:40:17 +0100 Subject: [PATCH 12/14] Fix some issues --- .../reactor/tokenprovider/AbstractUaaTokenProvider.java | 2 +- .../_ClientCredentialsGrantTokenProvider.java | 7 ------- .../operations/applications/DefaultApplicationsTest.java | 9 ++++----- .../org/cloudfoundry/operations/ApplicationsTest.java | 5 +++-- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/AbstractUaaTokenProvider.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/AbstractUaaTokenProvider.java index 10e34a4b0b..6cfc85a486 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/AbstractUaaTokenProvider.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/AbstractUaaTokenProvider.java @@ -74,7 +74,7 @@ public abstract class AbstractUaaTokenProvider implements TokenProvider { private static final ZoneId UTC = ZoneId.of("UTC"); - protected final ConcurrentMap> accessTokens = + private final ConcurrentMap> accessTokens = new ConcurrentHashMap<>(1); private final ConcurrentMap refreshTokenStreams = diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/_ClientCredentialsGrantTokenProvider.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/_ClientCredentialsGrantTokenProvider.java index 2bbbbaa101..c66d2e5d3e 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/_ClientCredentialsGrantTokenProvider.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/_ClientCredentialsGrantTokenProvider.java @@ -16,7 +16,6 @@ package org.cloudfoundry.reactor.tokenprovider; -import org.cloudfoundry.reactor.ConnectionContext; import org.cloudfoundry.reactor.TokenProvider; import org.immutables.value.Value; import reactor.netty.http.client.HttpClientForm; @@ -36,10 +35,4 @@ void tokenRequestTransformer(HttpClientRequest request, HttpClientForm form) { .attr("grant_type", "client_credentials") .attr("response_type", "token"); } - - @Override - public void invalidate(ConnectionContext connectionContext) { - this.accessTokens.remove(connectionContext); - } - } diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java index 5695108af7..0782c8b547 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java @@ -33,6 +33,7 @@ import java.util.Collections; import java.util.Date; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Queue; @@ -144,6 +145,7 @@ import org.cloudfoundry.doppler.LogMessage; import org.cloudfoundry.doppler.RecentLogsRequest; import org.cloudfoundry.doppler.StreamRequest; +import org.cloudfoundry.logcache.v1.Envelope; import org.cloudfoundry.logcache.v1.EnvelopeBatch; import org.cloudfoundry.logcache.v1.Log; import org.cloudfoundry.logcache.v1.LogCacheClient; @@ -5105,11 +5107,8 @@ private static void requestLogsRecentLogCache( .envelopes( fill(EnvelopeBatch.builder()) .batch( - Arrays.asList( - fill(org.cloudfoundry - .logcache.v1 - .Envelope - .builder()) + List.of( + fill(Envelope.builder()) .log( Log .builder() diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java index 832afe3c07..be8539f302 100644 --- a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java +++ b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java @@ -529,7 +529,8 @@ public void logs() throws IOException { this.cloudFoundryOperations .applications() .logs( - ApplicationLogsRequest.builder() + ApplicationLogsRequest + .builder() .name(applicationName) .recent(true) .build())) @@ -2205,7 +2206,7 @@ private static Mono getAppGuidFromAppName( } private static Log checkOneLogEntry(Log log) { - assertThat(log.getType().equals(LogType.OUT)); + assertThat(log.getType()).isEqualTo(LogType.OUT); OperationsLogging.log("one log entry: " + log.getType() + " " + log.getPayloadAsText()); return log; } From e27b34ff914f770a5335293bf60c9eb1ff1e1f3a Mon Sep 17 00:00:00 2001 From: Joris Baum Date: Thu, 26 Feb 2026 14:26:15 +0100 Subject: [PATCH 13/14] Better documentation for deprecated method --- .../main/java/org/cloudfoundry/doppler/DopplerClient.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java index 44d5306036..2f5afdf73c 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/doppler/DopplerClient.java @@ -39,13 +39,15 @@ public interface DopplerClient { */ Flux firehose(FirehoseRequest request); - // TODO Adapt the message /** * Makes the Recent Logs request * - * @deprecated Do not use this type directly, it exists only for the Jackson-binding infrastructure * @param request the Recent Logs request * @return the events from the recent logs + * @deprecated Use {@link org.cloudfoundry.logcache.v1.LogCacheClient#recentLogs(org.cloudfoundry.logcache.v1.ReadRequest)} instead. + * The Doppler recent logs endpoint has been removed since {@code Loggregator 107.0}, + * shipped in {@code CFD 24.3}. + * @see org.cloudfoundry.logcache.v1.LogCacheClient#recentLogs(org.cloudfoundry.logcache.v1.ReadRequest) */ @Deprecated Flux recentLogs(RecentLogsRequest request); From f40fbee10c0f9cf3febdfd8b9ec6b73d7e643d16 Mon Sep 17 00:00:00 2001 From: Joris Baum Date: Thu, 26 Feb 2026 17:12:59 +0100 Subject: [PATCH 14/14] Apply spotless to integration tests --- .../java/org/cloudfoundry/operations/ApplicationsTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java index be8539f302..1fdbd023ab 100644 --- a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java +++ b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java @@ -529,8 +529,7 @@ public void logs() throws IOException { this.cloudFoundryOperations .applications() .logs( - ApplicationLogsRequest - .builder() + ApplicationLogsRequest.builder() .name(applicationName) .recent(true) .build()))