Skip to content

Commit 636ca41

Browse files
Add logging during operations and files API calls (#1794)
LMCROSSITXSADEPLOY-3412
1 parent c534e80 commit 636ca41

8 files changed

Lines changed: 123 additions & 28 deletions

File tree

multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/Constants.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,27 @@ private Endpoints() {
7171
public static final String PURGE = "/purge";
7272
}
7373

74+
public static class ApiEndpointsNames {
75+
76+
private ApiEndpointsNames() {
77+
}
78+
79+
// Files API
80+
public static final String GET_FILES = "getFiles";
81+
public static final String UPLOAD_FILE = "uploadFile";
82+
public static final String START_UPLOAD_FROM_URL = "startUploadFromUrl";
83+
public static final String GET_UPLOAD_FROM_URL_JOB = "getUploadFromUrlJob";
84+
85+
// Operations API
86+
public static final String GET_OPERATIONS = "getOperations";
87+
public static final String START_OPERATION = "startOperation";
88+
public static final String GET_OPERATION = "getOperation";
89+
public static final String GET_OPERATION_ACTIONS = "getOperationActions";
90+
public static final String GET_OPERATION_LOGS = "getOperationLogs";
91+
public static final String GET_OPERATION_LOG_CONTENT = "getOperationLogContent";
92+
public static final String EXECUTE_OPERATION_ACTION = "executeOperationAction";
93+
}
94+
7495
public static final Set<String> NAMES_OF_SERVICE_PARAMETERS = Set.of(
7596
VARIABLE_NAME_SERVICE_ID, Variables.USER.getName(),
7697
Variables.USER_GUID.getName(), Variables.SPACE_NAME.getName(), Variables.SPACE_GUID.getName(),

multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/Messages.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ public final class Messages {
2525
public static final String MISSING_PROPERTIES_FOR_CREATING_THE_SPECIFIC_PROVIDER = "Missing properties for creating the specific provider!";
2626
public static final String DEPLOY_FROM_URL_WRONG_CREDENTIALS_FOR_JOB_WITH_ID = "Credentials to {0} are wrong. Make sure that they are correct. Job id: {1}";
2727
public static final String JOB_NOT_UPDATED_FOR_0_SECONDS = "Job not updated for {0} seconds";
28-
2928
public static final String FAILED_TO_CREATE_BLOB_STORE_CONTEXT = "Failed to create BlobStoreContext";
3029

3130
// Audit log messages

multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/api/impl/FilesApiServiceImpl.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
11
package org.cloudfoundry.multiapps.controller.web.api.impl;
22

3-
import java.io.BufferedInputStream;
4-
import java.io.InputStream;
5-
import java.math.BigInteger;
6-
import java.text.MessageFormat;
7-
import java.time.LocalDateTime;
8-
import java.time.temporal.ChronoUnit;
9-
import java.util.Base64;
10-
import java.util.List;
11-
import java.util.concurrent.ExecutorService;
12-
import java.util.stream.Collectors;
13-
143
import jakarta.inject.Inject;
154
import jakarta.inject.Named;
5+
import jakarta.servlet.http.HttpServletRequest;
166
import org.cloudfoundry.multiapps.common.SLException;
177
import org.cloudfoundry.multiapps.controller.api.FilesApiService;
188
import org.cloudfoundry.multiapps.controller.api.model.AsyncUploadResult;
@@ -36,6 +26,7 @@
3626
import org.cloudfoundry.multiapps.controller.process.util.PriorityFuture;
3727
import org.cloudfoundry.multiapps.controller.web.Constants;
3828
import org.cloudfoundry.multiapps.controller.web.Messages;
29+
import org.cloudfoundry.multiapps.controller.web.monitoring.ApiUsageLogger;
3930
import org.cloudfoundry.multiapps.controller.web.upload.AsyncUploadJobOrchestrator;
4031
import org.cloudfoundry.multiapps.controller.web.upload.exception.RejectedAsyncUploadJobException;
4132
import org.cloudfoundry.multiapps.controller.web.util.SecurityContextUtil;
@@ -48,6 +39,17 @@
4839
import org.springframework.web.multipart.MultipartFile;
4940
import org.springframework.web.multipart.MultipartHttpServletRequest;
5041

42+
import java.io.BufferedInputStream;
43+
import java.io.InputStream;
44+
import java.math.BigInteger;
45+
import java.text.MessageFormat;
46+
import java.time.LocalDateTime;
47+
import java.time.temporal.ChronoUnit;
48+
import java.util.Base64;
49+
import java.util.List;
50+
import java.util.concurrent.ExecutorService;
51+
import java.util.stream.Collectors;
52+
5153
@Named
5254
public class FilesApiServiceImpl implements FilesApiService {
5355

@@ -74,10 +76,15 @@ public class FilesApiServiceImpl implements FilesApiService {
7476
@Inject
7577
private AsyncUploadJobOrchestrator asyncUploadJobOrchestrator;
7678
@Inject
79+
private ApiUsageLogger apiUsageLogger;
80+
@Inject
7781
private ExecutorService fileStorageThreadPool;
82+
@Inject
83+
private HttpServletRequest httpServletRequest;
7884

7985
@Override
8086
public ResponseEntity<List<FileMetadata>> getFiles(String spaceGuid, String namespace) {
87+
apiUsageLogger.logFilesReadCall(spaceGuid, namespace, Constants.ApiEndpointsNames.GET_FILES, httpServletRequest);
8188
try {
8289
filesApiServiceAuditLog.logGetFiles(SecurityContextUtil.getUsername(), spaceGuid, namespace);
8390
List<FileEntry> entries = fileService.listFiles(spaceGuid, namespace);
@@ -93,6 +100,7 @@ public ResponseEntity<List<FileMetadata>> getFiles(String spaceGuid, String name
93100

94101
@Override
95102
public ResponseEntity<FileMetadata> uploadFile(MultipartHttpServletRequest request, String spaceGuid, String namespace) {
103+
apiUsageLogger.logFilesMutatingCall(spaceGuid, namespace, Constants.ApiEndpointsNames.UPLOAD_FILE, request);
96104
LOGGER.trace(Messages.RECEIVED_UPLOAD_REQUEST, ServletUtil.decodeUri(request));
97105
var multipartFile = getFileFromRequest(request);
98106
try (InputStream in = new BufferedInputStream(multipartFile.getInputStream(), INPUT_STREAM_BUFFER_SIZE)) {
@@ -113,11 +121,13 @@ public ResponseEntity<FileMetadata> uploadFile(MultipartHttpServletRequest reque
113121

114122
@Override
115123
public ResponseEntity<Void> startUploadFromUrl(String spaceGuid, String namespace, FileUrl fileUrl) {
124+
apiUsageLogger.logFilesMutatingCall(spaceGuid, namespace, Constants.ApiEndpointsNames.START_UPLOAD_FROM_URL, httpServletRequest);
116125
String decodedUrl = new String(Base64.getUrlDecoder()
117126
.decode(fileUrl.getFileUrl()));
118127
String urlWithoutUserInfo = UriUtil.stripUserInfo(decodedUrl);
119128
LOGGER.trace(Messages.RECEIVED_UPLOAD_FROM_URL_REQUEST, urlWithoutUserInfo);
120129
filesApiServiceAuditLog.logStartUploadFromUrl(SecurityContextUtil.getUsername(), spaceGuid, decodedUrl);
130+
121131
var existingJob = getExistingJob(spaceGuid, namespace, urlWithoutUserInfo);
122132
if (existingJob == null) {
123133
return triggerUploadFromUrl(spaceGuid, namespace, urlWithoutUserInfo, decodedUrl, fileUrl.getUserCredentials());
@@ -144,6 +154,7 @@ private String getLocationHeader(String spaceGuid, String jobId) {
144154

145155
@Override
146156
public ResponseEntity<AsyncUploadResult> getUploadFromUrlJob(String spaceGuid, String namespace, String jobId) {
157+
apiUsageLogger.logFilesReadCall(spaceGuid, namespace, Constants.ApiEndpointsNames.GET_UPLOAD_FROM_URL_JOB, httpServletRequest);
147158
filesApiServiceAuditLog.logGetUploadFromUrlJob(SecurityContextUtil.getUsername(), spaceGuid, namespace, jobId);
148159
AsyncUploadJobEntry job = getJob(jobId, spaceGuid, namespace);
149160
if (job == null) {

multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/api/impl/OperationsApiServiceImpl.java

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
11
package org.cloudfoundry.multiapps.controller.web.api.impl;
22

3-
import java.text.MessageFormat;
4-
import java.time.ZoneId;
5-
import java.time.ZonedDateTime;
6-
import java.time.format.DateTimeFormatter;
7-
import java.util.Arrays;
8-
import java.util.Collections;
9-
import java.util.Date;
10-
import java.util.HashMap;
11-
import java.util.List;
12-
import java.util.Map;
13-
import java.util.Set;
14-
import java.util.UUID;
15-
import java.util.stream.Collectors;
16-
173
import jakarta.inject.Inject;
184
import jakarta.inject.Named;
195
import jakarta.persistence.NoResultException;
@@ -38,7 +24,6 @@
3824
import org.cloudfoundry.multiapps.controller.core.cf.CloudControllerClientFactory;
3925
import org.cloudfoundry.multiapps.controller.core.security.token.TokenService;
4026
import org.cloudfoundry.multiapps.controller.core.util.UserInfo;
41-
import org.cloudfoundry.multiapps.controller.persistence.Constants;
4227
import org.cloudfoundry.multiapps.controller.persistence.OrderDirection;
4328
import org.cloudfoundry.multiapps.controller.persistence.model.ProgressMessage;
4429
import org.cloudfoundry.multiapps.controller.persistence.model.ProgressMessage.ProgressMessageType;
@@ -54,7 +39,9 @@
5439
import org.cloudfoundry.multiapps.controller.process.metadata.ProcessTypeToOperationMetadataMapper;
5540
import org.cloudfoundry.multiapps.controller.process.util.OperationsHelper;
5641
import org.cloudfoundry.multiapps.controller.process.variables.Variables;
42+
import org.cloudfoundry.multiapps.controller.web.Constants;
5743
import org.cloudfoundry.multiapps.controller.web.Messages;
44+
import org.cloudfoundry.multiapps.controller.web.monitoring.ApiUsageLogger;
5845
import org.cloudfoundry.multiapps.controller.web.util.SecurityContextUtil;
5946
import org.flowable.engine.runtime.ProcessInstance;
6047
import org.slf4j.Logger;
@@ -63,6 +50,21 @@
6350
import org.springframework.http.ResponseEntity;
6451
import org.springframework.web.server.ResponseStatusException;
6552

53+
import java.text.MessageFormat;
54+
import java.time.ZoneId;
55+
import java.time.ZonedDateTime;
56+
import java.time.format.DateTimeFormatter;
57+
import java.util.Arrays;
58+
import java.util.Collections;
59+
import java.util.Date;
60+
import java.util.HashMap;
61+
import java.util.List;
62+
import java.util.Map;
63+
import java.util.Set;
64+
import java.util.UUID;
65+
import java.util.stream.Collectors;
66+
67+
import static org.cloudfoundry.multiapps.controller.persistence.Constants.VARIABLE_NAME_SERVICE_ID;
6668
import static org.cloudfoundry.multiapps.controller.web.Constants.NAMES_OF_SERVICE_PARAMETERS;
6769

6870
@Named
@@ -89,9 +91,14 @@ public class OperationsApiServiceImpl implements OperationsApiService {
8991
private ProcessActionRegistry processActionRegistry;
9092
@Inject
9193
private OperationsApiServiceAuditLog operationsApiServiceAuditLog;
94+
@Inject
95+
private ApiUsageLogger apiUsageLogger;
96+
@Inject
97+
private HttpServletRequest httpServletRequest;
9298

9399
@Override
94100
public ResponseEntity<List<Operation>> getOperations(String spaceGuid, String mtaId, List<String> stateStrings, Integer last) {
101+
apiUsageLogger.logOperationsReadCall(spaceGuid, Constants.ApiEndpointsNames.GET_OPERATIONS, null, httpServletRequest);
95102
operationsApiServiceAuditLog.logGetOperations(SecurityContextUtil.getUsername(), spaceGuid, mtaId);
96103
List<Operation.State> states = getStates(stateStrings);
97104
List<Operation> operations = filterByQueryParameters(last, states, spaceGuid, mtaId);
@@ -101,6 +108,8 @@ public ResponseEntity<List<Operation>> getOperations(String spaceGuid, String mt
101108

102109
@Override
103110
public ResponseEntity<Void> executeOperationAction(String spaceGuid, String operationId, String actionId) {
111+
apiUsageLogger.logOperationsMutatingCall(spaceGuid, Constants.ApiEndpointsNames.EXECUTE_OPERATION_ACTION, operationId,
112+
httpServletRequest);
104113
operationsApiServiceAuditLog.logExecuteOperationAction(SecurityContextUtil.getUsername(), spaceGuid, operationId, actionId);
105114
Operation operation = getOperationByOperationGuidAndSpaceGuid(operationId, spaceGuid);
106115
List<String> availableOperations = getAvailableActions(operation);
@@ -119,6 +128,8 @@ public ResponseEntity<Void> executeOperationAction(String spaceGuid, String oper
119128
@Override
120129
public ResponseEntity<List<Log>> getOperationLogs(String spaceGuid, String operationId) {
121130
try {
131+
apiUsageLogger.logOperationsReadCall(spaceGuid, Constants.ApiEndpointsNames.GET_OPERATION_LOGS, operationId,
132+
httpServletRequest);
122133
operationsApiServiceAuditLog.logGetOperationLogs(SecurityContextUtil.getUsername(), spaceGuid, operationId);
123134
getOperationByOperationGuidAndSpaceGuid(operationId, spaceGuid);
124135
List<String> logIds = logsService.getLogNames(spaceGuid, operationId);
@@ -138,6 +149,8 @@ public ResponseEntity<List<Log>> getOperationLogs(String spaceGuid, String opera
138149
@Override
139150
public ResponseEntity<String> getOperationLogContent(String spaceGuid, String operationId, String logId) {
140151
try {
152+
apiUsageLogger.logOperationsReadCall(spaceGuid, Constants.ApiEndpointsNames.GET_OPERATION_LOG_CONTENT, operationId,
153+
httpServletRequest);
141154
operationsApiServiceAuditLog.logGetOperationLogContent(SecurityContextUtil.getUsername(), spaceGuid, operationId, logId);
142155
String content = logsService.getOperationLog(spaceGuid, operationId, logId);
143156

@@ -150,6 +163,7 @@ public ResponseEntity<String> getOperationLogContent(String spaceGuid, String op
150163

151164
@Override
152165
public ResponseEntity<Operation> startOperation(String spaceGuid, Operation operation, HttpServletRequest httpServletRequest) {
166+
apiUsageLogger.logOperationsMutatingCall(spaceGuid, Constants.ApiEndpointsNames.START_OPERATION, null, httpServletRequest);
153167
operationsApiServiceAuditLog.logStartOperation(SecurityContextUtil.getUsername(), spaceGuid, operation);
154168
UserInfo authenticatedUser = getAuthenticatedUser();
155169
String processDefinitionKey = operationsHelper.getProcessDefinitionKey(operation);
@@ -167,6 +181,7 @@ public ResponseEntity<Operation> startOperation(String spaceGuid, Operation oper
167181

168182
@Override
169183
public ResponseEntity<Operation> getOperation(String spaceGuid, String operationId, String embed) {
184+
apiUsageLogger.logOperationsReadCall(spaceGuid, Constants.ApiEndpointsNames.GET_OPERATION, operationId, httpServletRequest);
170185
operationsApiServiceAuditLog.logGetOperation(SecurityContextUtil.getUsername(), spaceGuid, operationId, embed);
171186
Operation operation = getOperationByOperationGuidAndSpaceGuid(operationId, spaceGuid);
172187
if (!operation.getSpaceId()
@@ -213,6 +228,7 @@ private List<Operation> filterByQueryParameters(Integer lastRequestedOperationsC
213228

214229
@Override
215230
public ResponseEntity<List<String>> getOperationActions(String spaceGuid, String operationId) {
231+
apiUsageLogger.logOperationsReadCall(spaceGuid, Constants.ApiEndpointsNames.GET_OPERATION_ACTIONS, operationId, httpServletRequest);
216232
operationsApiServiceAuditLog.logGetOperationActions(spaceGuid, SecurityContextUtil.getUsername(), operationId);
217233
Operation operation = getOperationByOperationGuidAndSpaceGuid(operationId, spaceGuid);
218234
return ResponseEntity.ok()
@@ -257,7 +273,7 @@ private Operation addServiceParameters(Operation operation, String spaceGuid, St
257273

258274
String processDefinitionKey = operationsHelper.getProcessDefinitionKey(operation);
259275

260-
parameters.put(Constants.VARIABLE_NAME_SERVICE_ID, processDefinitionKey);
276+
parameters.put(VARIABLE_NAME_SERVICE_ID, processDefinitionKey);
261277
parameters.put(Variables.USER.getName(), user);
262278
parameters.put(Variables.USER_GUID.getName(), userGuid);
263279
parameters.put(Variables.SPACE_NAME.getName(), space.getName());
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.cloudfoundry.multiapps.controller.web.monitoring;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
5+
public interface ApiUsageLogger {
6+
7+
void logFilesMutatingCall(String spaceGuid, String namespace, String endpoint, HttpServletRequest request);
8+
9+
void logFilesReadCall(String spaceGuid, String namespace, String endpoint, HttpServletRequest request);
10+
11+
void logOperationsMutatingCall(String spaceGuid, String endpoint, String operationId, HttpServletRequest request);
12+
13+
void logOperationsReadCall(String spaceGuid, String endpoint, String operationId, HttpServletRequest request);
14+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.cloudfoundry.multiapps.controller.web.monitoring;
2+
3+
import jakarta.inject.Named;
4+
import jakarta.servlet.http.HttpServletRequest;
5+
6+
@Named
7+
public class NoopApiUsageLogger implements ApiUsageLogger {
8+
9+
@Override
10+
public void logFilesMutatingCall(String spaceGuid, String namespace, String endpoint, HttpServletRequest request) {
11+
// no-op
12+
}
13+
14+
@Override
15+
public void logFilesReadCall(String spaceGuid, String namespace, String endpoint, HttpServletRequest request) {
16+
// no-op
17+
}
18+
19+
@Override
20+
public void logOperationsMutatingCall(String spaceGuid, String endpoint, String operationId, HttpServletRequest request) {
21+
// no-op
22+
}
23+
24+
@Override
25+
public void logOperationsReadCall(String spaceGuid, String endpoint, String operationId, HttpServletRequest request) {
26+
// no-op
27+
}
28+
}

multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/api/impl/FilesApiServiceImplTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.cloudfoundry.multiapps.controller.persistence.services.AsyncUploadJobService;
3131
import org.cloudfoundry.multiapps.controller.persistence.services.FileService;
3232
import org.cloudfoundry.multiapps.controller.persistence.services.FileStorageException;
33+
import org.cloudfoundry.multiapps.controller.web.monitoring.ApiUsageLogger;
3334
import org.cloudfoundry.multiapps.controller.web.upload.AsyncUploadJobOrchestrator;
3435
import org.cloudfoundry.multiapps.controller.web.upload.exception.RejectedAsyncUploadJobException;
3536
import org.junit.jupiter.api.AfterEach;
@@ -76,6 +77,8 @@ class FilesApiServiceImplTest {
7677
private final FilesApiServiceImpl testedClass = new FilesApiServiceImpl();
7778
@Mock
7879
private FilesApiServiceAuditLog filesApiServiceAuditLog;
80+
@Mock
81+
private ApiUsageLogger apiUsageLogger;
7982
@Mock(name = "fileStorageThreadPool")
8083
private ExecutorService fileStorageThreadPool;
8184
@Mock

multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/api/impl/OperationsApiServiceImplTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.cloudfoundry.multiapps.controller.process.metadata.ProcessTypeToOperationMetadataMapper;
3838
import org.cloudfoundry.multiapps.controller.process.util.OperationsHelper;
3939
import org.cloudfoundry.multiapps.controller.process.variables.Variables;
40+
import org.cloudfoundry.multiapps.controller.web.monitoring.ApiUsageLogger;
4041
import org.flowable.engine.runtime.ProcessInstance;
4142
import org.junit.jupiter.api.Assertions;
4243
import org.junit.jupiter.api.BeforeEach;
@@ -85,6 +86,8 @@ class OperationsApiServiceImplTest {
8586
private ProcessAction processAction;
8687
@Mock
8788
private OperationsApiServiceAuditLog operationsApiServiceAuditLog;
89+
@Mock
90+
private ApiUsageLogger apiUsageLogger;
8891

8992
@InjectMocks
9093
private OperationsApiServiceImpl operationsApiService = new OperationsApiServiceImpl();

0 commit comments

Comments
 (0)