Add cloud logging service feature#1847
Conversation
# Conflicts: # multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/backup-existing-app.bpmn # multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/deploy-app.bpmn # multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/stop-dependent-modules.bpmn # multiapps-controller-process/src/main/resources/org/cloudfoundry/multiapps/controller/process/undeploy-app.bpmn
20788df to
7220532
Compare
c1abde6 to
bb7fc04
Compare
|
|
|
||
| @Override | ||
| protected String getStepErrorMessage(ProcessContext context) { | ||
| return "Well, failed! Deal with it!"; |
There was a problem hiding this comment.
:O why so rude?
| import org.cloudfoundry.multiapps.controller.core.auditlogging.model.ConfigurationChangeActions; | ||
| import org.cloudfoundry.multiapps.controller.persistence.model.LoggingConfiguration; | ||
|
|
||
| public class CloudLoggingServiceConfigurationAuditLog { |
There was a problem hiding this comment.
Because SAP Cloud logging service is an internal proprietary service it should not be exposed in the open source. The whole logic related to the service must be move in the internal project.
Move every SAP related thing to the internal project and only leave the what is actually open source in this PR
| Map<String, String> identifiers = new HashMap<>(); | ||
| identifiers.put(MTA_ID_PROPERTY_NAME, loggingConfiguration.getMtaId()); | ||
| identifiers.put(NAMESPACE_PROPERTY_NAME, loggingConfiguration.getNamespace()); | ||
| auditLoggingFacade.logDataAccessAuditLog(new AuditLogConfiguration(username, |
There was a problem hiding this comment.
why buildIdentifiers is not used in this method?
| identifiers)); | ||
| } | ||
|
|
||
| public void logListLoggingConfigurations(String username, String spaceId) { |
There was a problem hiding this comment.
Is this really used?
| identifiers.put(NAMESPACE_PROPERTY_NAME, loggingConfiguration.getNamespace()); | ||
| identifiers.put(TARGET_SPACE_PROPERTY_NAME, loggingConfiguration.getTargetSpace()); | ||
| identifiers.put(TARGET_ORG_PROPERTY_NAME, loggingConfiguration.getTargetOrg()); | ||
| identifiers.put(SERVICE_INSTANCE_NAME_PROPERTY_NAME, loggingConfiguration.getServiceInstanceName()); | ||
| identifiers.put(SERVICE_KEY_NAME_PROPERTY_NAME, loggingConfiguration.getServiceKeyName()); |
There was a problem hiding this comment.
Can we use the IDs of target space and service instance?
| return logsMap; | ||
| } | ||
|
|
||
| private void getMessagesToLog(String log, Map<LogLevel, List<LogLogLog>> logsMap) { |
There was a problem hiding this comment.
return a Map of the logs instead of in-parameters
| InputStream serverCaStream = getCredentialInputStream(loggingConfiguration.getServerCa()); | ||
| InputStream clientCertStream = getCredentialInputStream(loggingConfiguration.getClientCert()); | ||
| InputStream clientKeyStream = getCredentialInputStream(loggingConfiguration.getClientKey()); |
There was a problem hiding this comment.
are these streams closed?
| .build(); | ||
| } | ||
|
|
||
| public record LogLogLog(String log, LocalDateTime dateTime) { |
There was a problem hiding this comment.
What is this Log :D
| } | ||
| } | ||
|
|
||
| private boolean areCloudLoggingParametersValid(String serviceInstanceName, String serviceKeyName) { |
There was a problem hiding this comment.
inverted naming?
| String credential = (String) credentials.get(credentialsName); | ||
|
|
||
| if (credential == null) { | ||
| throw new IllegalArgumentException("Missing required " + credentialsName + " credential for SAP Cloud Logging export"); |
There was a problem hiding this comment.
Use SLException instead.
IvanBorislavovDimitrov
left a comment
There was a problem hiding this comment.
Additional comments on OperationLogsExporter not yet covered in the earlier review.
| } | ||
|
|
||
| private boolean hasRequestFailed(ResponseEntity<Void> response) { | ||
| if (response == null) { |
There was a problem hiding this comment.
null response is treated as success here. .toBodilessEntity().block() can return null (empty Mono, cancellation, certain WebClient error paths). Treating that as a non-failure means a silently-dropped batch is reported as sent. Either treat null as failure, or document precisely under which condition it can be null and still be safe.
|
|
||
| for (ExternalOperationLogEntry entry : externalLogEntries) { | ||
| String entryJson = JsonUtil.toJson(entry); | ||
| int entrySize = entryJson.getBytes().length; |
There was a problem hiding this comment.
entryJson.getBytes().length uses the JVM default charset. The body that actually goes on the wire is UTF-8 (Jackson default). On a non-UTF-8 default platform you'll under- or over-estimate the batch size and either oversize a request or split too aggressively. Use entryJson.getBytes(StandardCharsets.UTF_8).length.
|
|
||
| String cleanedMessage = extractMessage(message); | ||
| String level = logLevels.get(levelIndex); | ||
| LocalDateTime date = dateLevels.get(levelIndex); |
There was a problem hiding this comment.
logLevels.get(levelIndex) / dateLevels.get(levelIndex) have no bounds check. The split regex and the level/date regexes walk the same input independently, so a single malformed line desynchronises them and you get an IndexOutOfBoundsException. Not fail-safe — even with isFailSafe = true the exception is unchecked and escapes.
|
|
||
| private List<LocalDateTime> getLogDate(String log) { | ||
| Matcher matcher = MESSAGE_LOG_DATE_PATTERN.matcher(log); | ||
| List<LocalDateTime> logLevels = new ArrayList<>(); |
There was a problem hiding this comment.
Variable is named logLevels but holds LocalDateTime. Rename to logDates.
| private String extractMessage(String message) { | ||
| String trimmed = message.substring(message.indexOf("]") + 1) | ||
| .trim(); | ||
| return trimmed.substring(0, trimmed.length() - 1); |
There was a problem hiding this comment.
trimmed.substring(0, trimmed.length() - 1) assumes the message ends with a delimiter. On an empty trimmed this throws StringIndexOutOfBoundsException; on a message that doesn't actually end in the expected # we silently drop the last real character. Guard the length, or use a regex that captures the body explicitly.
| webClient = clientCache.get(loggingConfiguration.getOperationId()); | ||
| } | ||
|
|
||
| LOGGER.debug(MessageFormat.format(Messages.CREATING_WEBCLIENT_WITH_MTLS_CONFIGURATION_FOR_ENDPOINT_1, |
There was a problem hiding this comment.
This debug line fires on every call — including cache hits — but the message reads "creating WebClient with mTLS configuration…", which is wrong on a hit. Move it inside the if branch above so it only logs when a client is actually created.
| } | ||
|
|
||
| private void logErrorOrThrowExceptionBasedOnFailSafe(LoggingConfiguration loggingConfiguration, String message) { | ||
| if (loggingConfiguration.isFailSafe()) { |
There was a problem hiding this comment.
loggingConfiguration.isFailSafe() returns @Nullable Boolean; auto-unboxing here will NPE if the field is null. Either default it at the model layer (e.g. @Value.Default) or null-check at the call site. The same trap exists in ExternalLoggingServiceConfigurationsCalculator#getServiceKeyWithLoggingConfiguration.




No description provided.