Skip to content

Deprecate doppler-based ApplicationsTests#logs, restrict tests to to CF 2.x line #1265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.cloudfoundry.operations.applications;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

public enum ApplicationLogType {
/**
* {@code STDERR}
*/
ERR("ERR"),

/**
* {@code STDOUT}
*/
OUT("OUT");

private final String value;

ApplicationLogType(String value) {
this.value = value;
}

@JsonCreator
public static ApplicationLogType from(String s) {
switch (s.toLowerCase()) {
case "err":
return ERR;
case "out":
return OUT;
default:
throw new IllegalArgumentException(String.format("Unknown log type: %s", s));
}
}

@JsonValue
public String getValue() {
return this.value;
}

@Override
public String toString() {
return getValue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,27 @@ public interface Applications {
Flux<Task> listTasks(ListApplicationTasksRequest request);

/**
* List the applications logs
* List the applications logs. Uses Doppler under the hood.
* Only works with {@code Loggregator < 107.0}, shipped in {@code CFD < 24.3}
* and {@code TAS < 4.0}.
*
* @param request the application logs request
* @return the applications logs
* @deprecated Use {@link #logs(ApplicationLogsRequest)} instead.
*/
@Deprecated
Flux<LogMessage> logs(LogsRequest request);

/**
* List the applications logs.
* Only works with {@code Loggregator < 107.0}, shipped in {@code CFD < 24.3}
* and {@code TAS < 4.0}.
*
* @param request the application logs request
* @return the applications logs
*/
Flux<ApplicationLog> logs(ApplicationLogsRequest request);

/**
* Push a specific application
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,26 @@ public Flux<LogMessage> logs(LogsRequest request) {
.checkpoint();
}

@Override
public Flux<ApplicationLog> 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")
public Mono<Void> push(PushApplicationRequest request) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.cloudfoundry.operations.applications;

import org.immutables.value.Value;

/**
* Represents an application log.
*/
@Value.Immutable
abstract class _ApplicationLog {
abstract String getSourceId();

abstract String getInstanceId();

abstract String getSourceType();

abstract String getMessage();

abstract ApplicationLogType getLogType();

abstract Long getTimestamp();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.cloudfoundry.operations.applications;

import org.cloudfoundry.Nullable;
import org.immutables.value.Value;

/**
* Represents a request for logs.
*/
@Value.Immutable
abstract class _ApplicationLogsRequest {

/**
* The name of the application
*/
abstract String getName();

/**
* Whether only recent logs should be retrieved
*/
@Nullable
abstract Boolean getRecent();
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,21 @@
import org.cloudfoundry.AbstractIntegrationTest;
import org.cloudfoundry.CloudFoundryVersion;
import org.cloudfoundry.IfCloudFoundryVersion;
import org.cloudfoundry.doppler.LogMessage;
import org.cloudfoundry.doppler.MessageType;
import org.cloudfoundry.logcache.v1.Envelope;
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.applications.ApplicationDetail;
import org.cloudfoundry.operations.applications.ApplicationEnvironments;
import org.cloudfoundry.operations.applications.ApplicationEvent;
import org.cloudfoundry.operations.applications.ApplicationHealthCheck;
import org.cloudfoundry.operations.applications.ApplicationLog;
import org.cloudfoundry.operations.applications.ApplicationLogType;
import org.cloudfoundry.operations.applications.ApplicationLogsRequest;
import org.cloudfoundry.operations.applications.ApplicationManifest;
import org.cloudfoundry.operations.applications.ApplicationSshEnabledRequest;
import org.cloudfoundry.operations.applications.ApplicationSummary;
Expand All @@ -47,7 +56,6 @@
import org.cloudfoundry.operations.applications.GetApplicationManifestRequest;
import org.cloudfoundry.operations.applications.GetApplicationRequest;
import org.cloudfoundry.operations.applications.ListApplicationTasksRequest;
import org.cloudfoundry.operations.applications.LogsRequest;
import org.cloudfoundry.operations.applications.ManifestV3;
import org.cloudfoundry.operations.applications.ManifestV3Application;
import org.cloudfoundry.operations.applications.PushApplicationManifestRequest;
Expand Down Expand Up @@ -96,6 +104,8 @@ public final class ApplicationsTest extends AbstractIntegrationTest {

@Autowired private String serviceName;

@Autowired private LogCacheClient logCacheClient;

@Test
public void copySource() throws IOException {
String sourceName = this.nameFactory.getApplicationName();
Expand Down Expand Up @@ -486,7 +496,12 @@ public void listTasks() throws IOException {
.verify(Duration.ofMinutes(5));
}

/**
* Doppler was dropped in PCF 4.x in favor of logcache. This test does not work
* on TAS 4.x.
*/
@Test
@IfCloudFoundryVersion(lessThan = CloudFoundryVersion.PCF_4_v2)
public void logs() throws IOException {
String applicationName = this.nameFactory.getApplicationName();

Expand All @@ -499,14 +514,53 @@ 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(ApplicationLogType.OUT)
.expectComplete()
.verify(Duration.ofMinutes(5));
}

/**
* Exercise the LogCache client. Serves as a reference for using the logcache client,
* and will help with the transition to the new
* {@link org.cloudfoundry.operations.applications.Applications#logs(ApplicationLogsRequest)}.
*/
@Test
public void logCacheLogs() throws IOException {
String applicationName = this.nameFactory.getApplicationName();

createApplication(
this.cloudFoundryOperations,
new ClassPathResource("test-application.zip").getFile().toPath(),
applicationName,
false)
.then(
this.cloudFoundryOperations
.applications()
.get(GetApplicationRequest.builder().name(applicationName).build()))
.map(ApplicationDetail::getId)
.flatMapMany(
appGuid ->
this.logCacheClient.read(
ReadRequest.builder()
.sourceId(appGuid)
.envelopeType(EnvelopeType.LOG)
.limit(1)
.build()))
.map(ReadResponse::getEnvelopes)
.map(EnvelopeBatch::getBatch)
.flatMap(Flux::fromIterable)
.map(Envelope::getLog)
.map(Log::getType)
.next()
.as(StepVerifier::create)
.expectNext(MessageType.OUT)
.expectNext(LogType.OUT)
.expectComplete()
.verify(Duration.ofMinutes(5));
}
Expand Down