Skip to content

Commit ca705fb

Browse files
committed
Migrate logs(ApplicationLogsRequest) from Doppler to LogCache
Use LogCacheClient.read() for recent logs (the default), fall back to Doppler streaming when recent is explicitly false. Remove logCacheLogs() integration test — it was a temporary reference for the direct LogCache API, now redundant since logs() exercises the same path. Remove logsRecent() and its helpers likewise.
1 parent e742f32 commit ca705fb

File tree

4 files changed

+76
-159
lines changed

4 files changed

+76
-159
lines changed

cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
package org.cloudfoundry.operations.applications;
1818

1919
import org.cloudfoundry.doppler.LogMessage;
20-
import org.cloudfoundry.logcache.v1.Log;
21-
import org.cloudfoundry.logcache.v1.ReadRequest;
2220
import reactor.core.publisher.Flux;
2321
import reactor.core.publisher.Mono;
2422

@@ -129,18 +127,7 @@ public interface Applications {
129127
Flux<LogMessage> logs(LogsRequest request);
130128

131129
/**
132-
* List the applications logs from logCacheClient.
133-
* If no messages are available, an empty Flux is returned.
134-
*
135-
* @param request the application logs request
136-
* @return the applications logs
137-
*/
138-
Flux<Log> logsRecent(ReadRequest request);
139-
140-
/**
141-
* List the applications logs.
142-
* Only works with {@code Loggregator < 107.0}, shipped in {@code CFD < 24.3}
143-
* and {@code TAS < 4.0}.
130+
* List the applications logs. Uses Log Cache under the hood.
144131
*
145132
* @param request the application logs request
146133
* @return the applications logs

cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@
155155
import org.cloudfoundry.doppler.RecentLogsRequest;
156156
import org.cloudfoundry.doppler.StreamRequest;
157157
import org.cloudfoundry.logcache.v1.EnvelopeBatch;
158-
import org.cloudfoundry.logcache.v1.Log;
159158
import org.cloudfoundry.logcache.v1.LogCacheClient;
160159
import org.cloudfoundry.logcache.v1.ReadRequest;
161160
import org.cloudfoundry.operations.util.OperationsLogging;
@@ -558,31 +557,25 @@ public Flux<LogMessage> logs(LogsRequest request) {
558557
.checkpoint();
559558
}
560559

561-
@Override
562-
public Flux<Log> logsRecent(ReadRequest request) {
563-
return getRecentLogsLogCache(this.logCacheClient, request)
564-
.transform(OperationsLogging.log("Get Application Logs"))
565-
.checkpoint();
566-
}
567-
568560
@Override
569561
public Flux<ApplicationLog> logs(ApplicationLogsRequest request) {
570-
return logs(LogsRequest.builder()
571-
.name(request.getName())
572-
.recent(request.getRecent())
573-
.build())
574-
.map(
575-
logMessage ->
576-
ApplicationLog.builder()
577-
.sourceId(logMessage.getApplicationId())
578-
.sourceType(logMessage.getSourceType())
579-
.instanceId(logMessage.getSourceInstance())
580-
.message(logMessage.getMessage())
581-
.timestamp(logMessage.getTimestamp())
582-
.logType(
583-
ApplicationLogType.from(
584-
logMessage.getMessageType().name()))
585-
.build());
562+
if (Optional.ofNullable(request.getRecent()).orElse(true)) {
563+
return Mono.zip(this.cloudFoundryClient, this.spaceId)
564+
.flatMap(
565+
function(
566+
(cloudFoundryClient, spaceId) ->
567+
getApplicationId(
568+
cloudFoundryClient,
569+
request.getName(),
570+
spaceId)))
571+
.flatMapMany(
572+
applicationId -> getLogsLogCache(this.logCacheClient, applicationId))
573+
.transform(OperationsLogging.log("Get Application Logs"))
574+
.checkpoint();
575+
} else {
576+
return logs(LogsRequest.builder().name(request.getName()).recent(false).build())
577+
.map(DefaultApplications::toApplicationLog);
578+
}
586579
}
587580

588581
@Override
@@ -1637,12 +1630,33 @@ private static Flux<LogMessage> getLogs(
16371630
}
16381631
}
16391632

1640-
private static Flux<Log> getRecentLogsLogCache(
1641-
Mono<LogCacheClient> logCacheClient, ReadRequest readRequest) {
1642-
return requestLogsRecentLogCache(logCacheClient, readRequest)
1633+
private static Flux<ApplicationLog> getLogsLogCache(
1634+
Mono<LogCacheClient> logCacheClient, String sourceId) {
1635+
return logCacheClient
1636+
.flatMap(client -> client.read(ReadRequest.builder().sourceId(sourceId).build()))
1637+
.flatMap(response -> Mono.justOrEmpty(response.getEnvelopes()))
16431638
.flatMapIterable(EnvelopeBatch::getBatch)
1639+
.filter(e -> e.getLog() != null)
16441640
.sort(LOG_MESSAGE_COMPARATOR_LOG_CACHE)
1645-
.mapNotNull(org.cloudfoundry.logcache.v1.Envelope::getLog);
1641+
.map(
1642+
envelope ->
1643+
ApplicationLog.builder()
1644+
.sourceId(
1645+
Optional.ofNullable(envelope.getSourceId())
1646+
.orElse(""))
1647+
.sourceType(
1648+
envelope.getTags().getOrDefault("source_type", ""))
1649+
.instanceId(
1650+
Optional.ofNullable(envelope.getInstanceId())
1651+
.orElse(""))
1652+
.message(envelope.getLog().getPayloadAsText())
1653+
.timestamp(
1654+
Optional.ofNullable(envelope.getTimestamp())
1655+
.orElse(0L))
1656+
.logType(
1657+
ApplicationLogType.from(
1658+
envelope.getLog().getType().name()))
1659+
.build());
16461660
}
16471661

16481662
@SuppressWarnings("unchecked")
@@ -2538,14 +2552,6 @@ private static Flux<Envelope> requestLogsRecent(
25382552
RecentLogsRequest.builder().applicationId(applicationId).build()));
25392553
}
25402554

2541-
private static Mono<EnvelopeBatch> requestLogsRecentLogCache(
2542-
Mono<LogCacheClient> logCacheClient, ReadRequest readRequest) {
2543-
return logCacheClient.flatMap(
2544-
client ->
2545-
client.read(readRequest)
2546-
.flatMap(response -> Mono.justOrEmpty(response.getEnvelopes())));
2547-
}
2548-
25492555
private static Flux<Envelope> requestLogsStream(
25502556
Mono<DopplerClient> dopplerClient, String applicationId) {
25512557
return dopplerClient.flatMapMany(
@@ -2951,6 +2957,17 @@ private static Mono<AbstractApplicationResource> stopApplicationIfNotStopped(
29512957
: Mono.just(resource);
29522958
}
29532959

2960+
private static ApplicationLog toApplicationLog(LogMessage logMessage) {
2961+
return ApplicationLog.builder()
2962+
.sourceId(logMessage.getApplicationId())
2963+
.sourceType(logMessage.getSourceType())
2964+
.instanceId(logMessage.getSourceInstance())
2965+
.message(logMessage.getMessage())
2966+
.timestamp(logMessage.getTimestamp())
2967+
.logType(ApplicationLogType.from(logMessage.getMessageType().name()))
2968+
.build();
2969+
}
2970+
29542971
private static ApplicationDetail toApplicationDetail(
29552972
List<String> buildpacks,
29562973
SummaryApplicationResponse summaryApplicationResponse,

cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
import static org.mockito.Mockito.when;
2626

2727
import java.io.IOException;
28+
import java.nio.charset.StandardCharsets;
2829
import java.nio.file.Path;
2930
import java.time.Duration;
3031
import java.util.Arrays;
32+
import java.util.Base64;
3133
import java.util.Collection;
3234
import java.util.Collections;
3335
import java.util.Date;
@@ -1367,18 +1369,25 @@ void logsRecentDoppler() {
13671369
}
13681370

13691371
@Test
1370-
void logsRecentLogCache() {
1372+
void logsLogCache() {
13711373
requestApplications(
13721374
this.cloudFoundryClient,
13731375
"test-application-name",
13741376
TEST_SPACE_ID,
13751377
"test-metadata-id");
1376-
requestLogsRecentLogCache(this.logCacheClient, "test-metadata-id", "test-payload");
1378+
requestLogsRecentLogCache(this.logCacheClient, "test-metadata-id");
13771379

13781380
this.applications
1379-
.logsRecent(ReadRequest.builder().sourceId("test-metadata-id").build())
1381+
.logs(ApplicationLogsRequest.builder().name("test-application-name").build())
13801382
.as(StepVerifier::create)
1381-
.expectNext(fill(Log.builder()).type(LogType.OUT).build())
1383+
.expectNextMatches(
1384+
log ->
1385+
log.getMessage().equals("test-payload")
1386+
&& log.getLogType() == ApplicationLogType.OUT
1387+
&& log.getSourceId().equals("test-sourceId")
1388+
&& log.getInstanceId().equals("test-instanceId")
1389+
&& log.getSourceType().equals("APP/PROC/WEB")
1390+
&& log.getTimestamp() == 1L)
13821391
.expectComplete()
13831392
.verify(Duration.ofSeconds(5));
13841393
}
@@ -5359,8 +5368,9 @@ private static void requestLogsRecent(DopplerClient dopplerClient, String applic
53595368
.build()));
53605369
}
53615370

5362-
private static void requestLogsRecentLogCache(
5363-
LogCacheClient logCacheClient, String sourceId, String payload) {
5371+
private static void requestLogsRecentLogCache(LogCacheClient logCacheClient, String sourceId) {
5372+
String base64Payload =
5373+
Base64.getEncoder().encodeToString("test-payload".getBytes(StandardCharsets.UTF_8));
53645374
when(logCacheClient.read(ReadRequest.builder().sourceId(sourceId).build()))
53655375
.thenReturn(
53665376
Mono.just(
@@ -5370,11 +5380,16 @@ private static void requestLogsRecentLogCache(
53705380
.batch(
53715381
Arrays.asList(
53725382
fill(Envelope.builder())
5383+
.tags(
5384+
Collections
5385+
.singletonMap(
5386+
"source_type",
5387+
"APP/PROC/WEB"))
53735388
.log(
53745389
Log
53755390
.builder()
53765391
.payload(
5377-
payload)
5392+
base64Payload)
53785393
.type(
53795394
LogType
53805395
.OUT)

integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java

Lines changed: 0 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,11 @@
2525
import java.util.Collections;
2626
import java.util.List;
2727
import java.util.Map;
28-
import java.util.logging.Level;
2928
import org.cloudfoundry.AbstractIntegrationTest;
3029
import org.cloudfoundry.CleanupCloudFoundryAfterClass;
3130
import org.cloudfoundry.CloudFoundryVersion;
3231
import org.cloudfoundry.IfCloudFoundryVersion;
3332
import org.cloudfoundry.client.CloudFoundryClient;
34-
import org.cloudfoundry.logcache.v1.Envelope;
35-
import org.cloudfoundry.logcache.v1.EnvelopeBatch;
36-
import org.cloudfoundry.logcache.v1.EnvelopeType;
37-
import org.cloudfoundry.logcache.v1.Log;
38-
import org.cloudfoundry.logcache.v1.LogCacheClient;
39-
import org.cloudfoundry.logcache.v1.LogType;
40-
import org.cloudfoundry.logcache.v1.ReadRequest;
41-
import org.cloudfoundry.logcache.v1.ReadResponse;
4233
import org.cloudfoundry.operations.applications.ApplicationDetail;
4334
import org.cloudfoundry.operations.applications.ApplicationEnvironments;
4435
import org.cloudfoundry.operations.applications.ApplicationEvent;
@@ -87,15 +78,13 @@
8778
import org.cloudfoundry.operations.services.CreateUserProvidedServiceInstanceRequest;
8879
import org.cloudfoundry.operations.services.GetServiceInstanceRequest;
8980
import org.cloudfoundry.operations.services.ServiceInstance;
90-
import org.cloudfoundry.operations.util.OperationsLogging;
9181
import org.cloudfoundry.util.FluentMap;
9282
import org.junit.jupiter.api.Test;
9383
import org.springframework.beans.factory.annotation.Autowired;
9484
import org.springframework.beans.factory.annotation.Qualifier;
9585
import org.springframework.core.io.ClassPathResource;
9686
import reactor.core.publisher.Flux;
9787
import reactor.core.publisher.Mono;
98-
import reactor.core.publisher.SignalType;
9988
import reactor.test.StepVerifier;
10089

10190
@CleanupCloudFoundryAfterClass
@@ -111,7 +100,6 @@ public final class ApplicationsTest extends AbstractIntegrationTest {
111100

112101
@Autowired private String serviceName;
113102

114-
@Autowired private LogCacheClient logCacheClient;
115103
@Autowired private CloudFoundryClient cloudFoundryClient;
116104

117105
// To create a service in #pushBindService, the Service Broker must be installed first.
@@ -514,7 +502,6 @@ public void listTasks() throws IOException {
514502
* Doppler was dropped in PCF 4.x in favor of logcache. This test does not work
515503
* on TAS 4.x.
516504
*/
517-
@Deprecated
518505
@Test
519506
@IfCloudFoundryVersion(lessThan = CloudFoundryVersion.PCF_4_v2)
520507
public void logs() throws IOException {
@@ -541,72 +528,6 @@ public void logs() throws IOException {
541528
.verify(Duration.ofMinutes(5));
542529
}
543530

544-
@Test
545-
@IfCloudFoundryVersion(greaterThanOrEqualTo = CloudFoundryVersion.PCF_4_v2)
546-
public void logsRecent() throws IOException {
547-
String applicationName = this.nameFactory.getApplicationName();
548-
Mono<String> applicationGuid =
549-
getAppGuidFromAppName(cloudFoundryOperations, applicationName);
550-
createApplication(
551-
this.cloudFoundryOperations,
552-
new ClassPathResource("test-application.zip").getFile().toPath(),
553-
applicationName,
554-
false)
555-
.then(
556-
applicationGuid
557-
.map(ApplicationsTest::getReadRequest)
558-
.flatMapMany(
559-
readRequest ->
560-
callLogsRecent(
561-
this.cloudFoundryOperations,
562-
readRequest)
563-
.log(null, Level.ALL, SignalType.ON_NEXT))
564-
.map(ApplicationsTest::checkOneLogEntry)
565-
.then())
566-
.as(StepVerifier::create)
567-
.expectComplete()
568-
.verify(Duration.ofMinutes(5));
569-
}
570-
571-
/**
572-
* Exercise the LogCache client. Serves as a reference for using the logcache client,
573-
* and will help with the transition to the new
574-
* {@link org.cloudfoundry.operations.applications.Applications#logs(ApplicationLogsRequest)}.
575-
*/
576-
@Test
577-
public void logCacheLogs() throws IOException {
578-
String applicationName = this.nameFactory.getApplicationName();
579-
580-
createApplication(
581-
this.cloudFoundryOperations,
582-
new ClassPathResource("test-application.zip").getFile().toPath(),
583-
applicationName,
584-
false)
585-
.then(
586-
this.cloudFoundryOperations
587-
.applications()
588-
.get(GetApplicationRequest.builder().name(applicationName).build()))
589-
.map(ApplicationDetail::getId)
590-
.flatMapMany(
591-
appGuid ->
592-
this.logCacheClient.read(
593-
ReadRequest.builder()
594-
.sourceId(appGuid)
595-
.envelopeType(EnvelopeType.LOG)
596-
.limit(1)
597-
.build()))
598-
.map(ReadResponse::getEnvelopes)
599-
.map(EnvelopeBatch::getBatch)
600-
.flatMap(Flux::fromIterable)
601-
.map(Envelope::getLog)
602-
.map(Log::getType)
603-
.next()
604-
.as(StepVerifier::create)
605-
.expectNext(LogType.OUT)
606-
.expectComplete()
607-
.verify(Duration.ofMinutes(5));
608-
}
609-
610531
@Test
611532
public void pushBindServices() throws IOException {
612533
String applicationName = this.nameFactory.getApplicationName();
@@ -2187,27 +2108,4 @@ private static Mono<Boolean> requestSshEnabled(
21872108
.applications()
21882109
.sshEnabled(ApplicationSshEnabledRequest.builder().name(applicationName).build());
21892110
}
2190-
2191-
private static ReadRequest getReadRequest(String applicationId) {
2192-
return ReadRequest.builder().sourceId(applicationId).build();
2193-
}
2194-
2195-
private static Flux<Log> callLogsRecent(
2196-
CloudFoundryOperations cloudFoundryOperations, ReadRequest readRequest) {
2197-
return cloudFoundryOperations.applications().logsRecent(readRequest);
2198-
}
2199-
2200-
private static Mono<String> getAppGuidFromAppName(
2201-
CloudFoundryOperations cloudFoundryOperations, String applicationName) {
2202-
return cloudFoundryOperations
2203-
.applications()
2204-
.get(GetApplicationRequest.builder().name(applicationName).build())
2205-
.map(ApplicationDetail::getId);
2206-
}
2207-
2208-
private static Log checkOneLogEntry(Log log) {
2209-
OperationsLogging.log("one log entry: " + log.getType() + " " + log.getPayloadAsText());
2210-
assertThat(log.getType()).isIn(LogType.OUT, LogType.ERR);
2211-
return log;
2212-
}
22132111
}

0 commit comments

Comments
 (0)