Skip to content
Open
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
Expand Up @@ -9,6 +9,7 @@
exports org.cloudfoundry.multiapps.controller.persistence.model;
exports org.cloudfoundry.multiapps.controller.persistence.model.adapter;
exports org.cloudfoundry.multiapps.controller.persistence.model.filters;
exports org.cloudfoundry.multiapps.controller.persistence.monitoring;
exports org.cloudfoundry.multiapps.controller.persistence.query;
exports org.cloudfoundry.multiapps.controller.persistence.query.criteria;
exports org.cloudfoundry.multiapps.controller.persistence.query.impl;
Expand Down Expand Up @@ -46,6 +47,7 @@
requires google.cloud.core;
requires google.cloud.nio;
requires google.cloud.storage;
requires io.netty.handler;
requires jakarta.xml.bind;
requires jakarta.annotation;
requires jakarta.inject;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ public final class Messages {

// INFO log messages:
public static final String DELETING_FILES_WITHOUT_CONTENT_WITH_IDS_0 = "Deleting files without content with ids: {0}";
public static final String TIME_ELAPSED_FOR_JCLOUDS_OS_UPLOAD_0_IN_MILLIS = "Time elapsed for JClouds object store upload: {0} in millis";
public static final String TIME_ELAPSED_FOR_GCP_OS_UPLOAD_0_IN_MILLIS = "Time elapsed for GCP object store upload: {0} in millis";
public static final String TIME_ELAPSED_FOR_AZURE_OS_UPLOAD_0_IN_MILLIS = "Time elapsed for Azure object store upload: {0} in millis";
public static final String TIME_ELAPSED_FOR_AWS_OS_UPLOAD_0_IN_MILLIS = "Time elapsed for AWS object store upload: {0} in millis";

// DEBUG log messages:
public static final String STORED_FILE_0 = "Stored file: \"{0}\"";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package org.cloudfoundry.multiapps.controller.persistence.monitoring;

import jakarta.inject.Named;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

@Named
public class UploadDurationTracker {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class which dynatrace uses for monitoring is only in memory - per instance and the values will be zero after restart of instance of DS, LSS. This is expected right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I made it like that on purpose so we are better able to see when and if an instance has any problems and also we do not have to think and be responsible about the persistence part of the whole thing, since Dynatrace automatically saves the information on the charts, even after if lets say there have been lots of restarts. We would only have to change the timeframe and we will be able to see if and which metric exactly has abnormal values.


private final UploadPathStatistics appBinaryStatistics = new UploadPathStatistics();

private final UploadPathStatistics objectStoreStatistics = new UploadPathStatistics();

public void recordAppBinaryUpload(long durationMillis, boolean timedOut) {
appBinaryStatistics.record(durationMillis, timedOut);
}

public void recordObjectStoreUpload(long durationMillis, boolean timedOut) {
objectStoreStatistics.record(durationMillis, timedOut);
}

public void recordAppBinaryUploadRejection() {
appBinaryStatistics.recordRejection();
}

public UploadPathStatistics getAppBinaryStatistics() {
return this.appBinaryStatistics;
}

public UploadPathStatistics getObjectStoreStatistics() {
return this.objectStoreStatistics;
}

public static final class UploadPathStatistics {

private final LongAdder total = new LongAdder();

private final LongAdder timeouts = new LongAdder();

private final LongAdder sumDuration = new LongAdder();

private final LongAdder rejections = new LongAdder();

private final AtomicLong rejectionsInWindow = new AtomicLong(0);

private final AtomicLong maxDuration = new AtomicLong(0);

private final AtomicLong timeoutsInWindow = new AtomicLong(0);

public void record(long durationMillis, boolean timedOut) {

Check warning on line 51 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/monitoring/UploadDurationTracker.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename this method to not match a restricted identifier.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3gucUCp9xIDHFHEoS&open=AZ-3gucUCp9xIDHFHEoS&pullRequest=1885
long duration = Math.max(0, durationMillis);
total.increment();

if (timedOut) {
timeouts.increment();
timeoutsInWindow.incrementAndGet();
}

sumDuration.add(duration);
maxDuration.accumulateAndGet(duration, Math::max);
}

public void recordRejection() {
rejections.increment();
rejectionsInWindow.incrementAndGet();
}

public long totalCount() {
return total.sum();
}

public long timeoutCount() {
return timeouts.sum();
}

public long maxDurationMs() {
return maxDuration.getAndSet(0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this set to 0 after the value is read?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is on purpose as well, since Dynatrave is configured to poll each one minute which means that the poll happens at a random moment during these 60 seconds, which I would say that it is not fully correct, since a better way would be the way I have done it now - I am saving the maximum value per every 60 second poll and that is the value that dynatrace then displays on the charts. The idea is that in this one minute there might be a problematic deployment with lets say an abnormally high upload time and then after a couple of seconds there might be another totally normal one and the value would be overwritten and then if the Dynatrace poll is right after that - the chart would show that everything is totally alright.

}

public long sumDurationMs() {
return sumDuration.sum();
}

public long timeoutsInWindow() {
return timeoutsInWindow.getAndSet(0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as the one above :D

}

public long rejectionCount() {
return rejections.sum();
}

public long rejectionsInWindow() {
return rejectionsInWindow.getAndSet(0);
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.cloudfoundry.multiapps.controller.persistence.monitoring;

import com.google.cloud.storage.StorageException;
import io.netty.handler.timeout.ReadTimeoutException;

import java.net.SocketTimeoutException;
import java.util.concurrent.TimeoutException;

public class UploadTimeoutMatcher {

private UploadTimeoutMatcher() {

}

public static boolean isUploadTimeoutException(Throwable throwable) {
if (throwable == null) {
return false;
}

Throwable cause = throwable.getCause();
while (cause != null) {
if (cause instanceof SocketTimeoutException || cause instanceof TimeoutException || cause instanceof ReadTimeoutException || (
cause instanceof StorageException

Check warning on line 23 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/monitoring/UploadTimeoutMatcher.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this instanceof check and cast with 'instanceof StorageException storageexception'

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3guccCp9xIDHFHEoT&open=AZ-3guccCp9xIDHFHEoT&pullRequest=1885
&& ((StorageException) cause).getCode() == 504)) {
return true;
}
cause = cause.getCause();
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.io.InputStream;
import java.net.URI;
import java.text.MessageFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
Expand All @@ -16,8 +17,11 @@
import java.util.concurrent.Executors;
import java.util.function.BiPredicate;
import java.util.function.Consumer;

import org.cloudfoundry.multiapps.controller.persistence.Messages;
import org.cloudfoundry.multiapps.controller.persistence.model.FileEntry;
import org.cloudfoundry.multiapps.controller.persistence.monitoring.UploadDurationTracker;
import org.cloudfoundry.multiapps.controller.persistence.monitoring.UploadTimeoutMatcher;
import org.cloudfoundry.multiapps.controller.persistence.util.ObjectStoreConstants;
import org.cloudfoundry.multiapps.controller.persistence.util.ObjectStoreFilter;
import org.cloudfoundry.multiapps.controller.persistence.util.ObjectStoreMapper;
Expand Down Expand Up @@ -57,10 +61,12 @@

private final S3Client s3Client;
private final String bucketName;
private final UploadDurationTracker uploadDurationTracker;

public AwsS3ObjectStoreFileStorage(Map<String, Object> credentials) {
public AwsS3ObjectStoreFileStorage(Map<String, Object> credentials, UploadDurationTracker uploadDurationTracker) {
this.bucketName = (String) credentials.get(CredentialKeys.BUCKET);
this.s3Client = createS3Client(credentials);
this.uploadDurationTracker = uploadDurationTracker;
}

protected S3Client createS3Client(Map<String, Object> credentials) {
Expand Down Expand Up @@ -103,6 +109,7 @@

@Override
public void addFile(FileEntry fileEntry, InputStream content) throws FileStorageException {
LocalDateTime startTime = LocalDateTime.now();

Check warning on line 112 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AwsS3ObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Explicitly specify the time zone by passing a ZoneId or a Clock to the .now() method.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3gucECp9xIDHFHEoO&open=AZ-3gucECp9xIDHFHEoO&pullRequest=1885
long fileSize = fileEntry.getSize()
.longValue();
PutObjectRequest request = PutObjectRequest.builder()
Expand All @@ -115,8 +122,12 @@
try {
s3Client.putObject(request, RequestBody.fromInputStream(new BufferedInputStream(content), fileSize));
LOGGER.debug(MessageFormat.format(Messages.STORED_FILE_0_WITH_SIZE_1, fileEntry.getId(), fileSize));
uploadDurationTracker.recordObjectStoreUpload(getElapsedTimeInMillis(startTime), false);
LOGGER.info(MessageFormat.format(Messages.TIME_ELAPSED_FOR_AWS_OS_UPLOAD_0_IN_MILLIS, getElapsedTimeInMillis(startTime)));

Check warning on line 126 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AwsS3ObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Invoke method(s) only conditionally.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3gucECp9xIDHFHEoN&open=AZ-3gucECp9xIDHFHEoN&pullRequest=1885
} catch (Exception e) {
LOGGER.error(MessageFormat.format(Messages.S3_UPLOAD_FAILED_FILE_0_SIZE_1, fileEntry.getName(), fileSize, e));
uploadDurationTracker.recordObjectStoreUpload(getElapsedTimeInMillis(startTime),
UploadTimeoutMatcher.isUploadTimeoutException(e));
throw new FileStorageException(MessageFormat.format(Messages.UPLOAD_OF_FILE_WITH_NAMESPACE_FAILED, fileEntry.getName(),
fileEntry.getNamespace()), e);
}
Expand Down Expand Up @@ -183,14 +194,15 @@

@Override
public void deleteFilesBySpaceAndNamespace(String space, String namespace) {
int deletedFiles = deleteByFilterAndCount((key, metadata) -> ObjectStoreFilter.filterBySpaceAndNamespace(metadata, space, namespace));
int deletedFiles = deleteByFilterAndCount(
(key, metadata) -> ObjectStoreFilter.filterBySpaceAndNamespace(metadata, space, namespace));
LOGGER.debug(MessageFormat.format(Messages.DELETED_0_FILES_WITH_SPACE_1_AND_NAMESPACE_2, deletedFiles, space, namespace));
}

@Override
public int deleteFilesModifiedBefore(LocalDateTime modificationTime) {
int deletedFiles = deleteByFilterAndCount((key, metadata) -> ObjectStoreFilter.filterByModificationTime(metadata, key,
modificationTime));
modificationTime));
LOGGER.debug(MessageFormat.format(Messages.DELETED_0_FILES_MODIFIED_BEFORE_1, deletedFiles, modificationTime));
return deletedFiles;
}
Expand Down Expand Up @@ -319,6 +331,11 @@
s3Client.close();
}

private long getElapsedTimeInMillis(LocalDateTime startTime) {
return Duration.between(startTime, LocalDateTime.now())

Check warning on line 335 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AwsS3ObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Explicitly specify the time zone by passing a ZoneId or a Clock to the .now() method.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3gucFCp9xIDHFHEoQ&open=AZ-3gucFCp9xIDHFHEoQ&pullRequest=1885

Check warning on line 335 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AwsS3ObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Convert these arguments to time zone-aware types before computing a duration between them.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3gucFCp9xIDHFHEoP&open=AZ-3gucFCp9xIDHFHEoP&pullRequest=1885
.toMillis();
}

private static final class CredentialKeys {
static final String ACCESS_KEY_ID = "access_key_id";
static final String SECRET_ACCESS_KEY = "secret_access_key";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.text.MessageFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
Expand All @@ -29,6 +30,8 @@
import com.azure.storage.blob.options.BlobParallelUploadOptions;
import org.cloudfoundry.multiapps.controller.persistence.Messages;
import org.cloudfoundry.multiapps.controller.persistence.model.FileEntry;
import org.cloudfoundry.multiapps.controller.persistence.monitoring.UploadDurationTracker;
import org.cloudfoundry.multiapps.controller.persistence.monitoring.UploadTimeoutMatcher;
import org.cloudfoundry.multiapps.controller.persistence.util.ObjectStoreConstants;
import org.cloudfoundry.multiapps.controller.persistence.util.ObjectStoreFilter;
import org.cloudfoundry.multiapps.controller.persistence.util.ObjectStoreMapper;
Expand All @@ -46,15 +49,18 @@
private static final int MAX_CONCURRENCY = 5;
private final HttpClient httpClient;
private final BlobContainerClient containerClient;
private final UploadDurationTracker uploadDurationTracker;

public AzureObjectStoreFileStorage(Map<String, Object> credentials) {
public AzureObjectStoreFileStorage(Map<String, Object> credentials, UploadDurationTracker uploadDurationTracker) {
this.httpClient = new JdkHttpClientBuilder().build();
this.containerClient = createContainerClient(credentials);
this.uploadDurationTracker = uploadDurationTracker;
}

@Override
public void addFile(FileEntry fileEntry, InputStream content) throws FileStorageException {
BlobClient blobClient = containerClient.getBlobClient(fileEntry.getId());
LocalDateTime startTime = LocalDateTime.now();

Check warning on line 63 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AzureObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Explicitly specify the time zone by passing a ZoneId or a Clock to the .now() method.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3guafCp9xIDHFHEoC&open=AZ-3guafCp9xIDHFHEoC&pullRequest=1885
try {
ParallelTransferOptions pto = new ParallelTransferOptions().setMaxSingleUploadSizeLong(MAX_SINGLE_UPLOAD_SIZE)
.setMaxConcurrency(MAX_CONCURRENCY)
Expand All @@ -67,10 +73,14 @@
blobClient.uploadWithResponse(blobParallelUploadOptions,
ObjectStoreConstants.AZURE_OBJECT_STORE_TOTAL_TIMEOUT_CONFIG_IN_MINUTES, null);
LOGGER.debug(MessageFormat.format(Messages.STORED_FILE_0_WITH_SIZE_1, fileEntry.getId(), fileEntry.getSize()
.longValue()));
.longValue()));
} catch (BlobStorageException e) {
uploadDurationTracker.recordObjectStoreUpload(getElapsedTimeInMillis(startTime),
UploadTimeoutMatcher.isUploadTimeoutException(e));
throw new FileStorageException(e);
}
uploadDurationTracker.recordObjectStoreUpload(getElapsedTimeInMillis(startTime), false);
LOGGER.info(MessageFormat.format(Messages.TIME_ELAPSED_FOR_AZURE_OS_UPLOAD_0_IN_MILLIS, getElapsedTimeInMillis(startTime)));

Check warning on line 83 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AzureObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Invoke method(s) only conditionally.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3guafCp9xIDHFHEoB&open=AZ-3guafCp9xIDHFHEoB&pullRequest=1885
}

@Override
Expand Down Expand Up @@ -218,6 +228,11 @@
return deletedBlobsResult;
}

private long getElapsedTimeInMillis(LocalDateTime startTime) {
return Duration.between(startTime, LocalDateTime.now())

Check warning on line 232 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AzureObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Explicitly specify the time zone by passing a ZoneId or a Clock to the .now() method.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3guafCp9xIDHFHEoE&open=AZ-3guafCp9xIDHFHEoE&pullRequest=1885

Check warning on line 232 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/AzureObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Convert these arguments to time zone-aware types before computing a duration between them.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3guafCp9xIDHFHEoD&open=AZ-3guafCp9xIDHFHEoD&pullRequest=1885
.toMillis();
}

protected Set<String> getEntryNames(Predicate<? super BlobItem> filter) {
BlobListDetails blobListDetails = new BlobListDetails().setRetrieveMetadata(true);
ListBlobsOptions listBlobsOptions = new ListBlobsOptions().setDetails(blobListDetails);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import com.google.cloud.storage.StorageRetryStrategy;
import org.cloudfoundry.multiapps.controller.persistence.Messages;
import org.cloudfoundry.multiapps.controller.persistence.model.FileEntry;
import org.cloudfoundry.multiapps.controller.persistence.monitoring.UploadDurationTracker;
import org.cloudfoundry.multiapps.controller.persistence.monitoring.UploadTimeoutMatcher;
import org.cloudfoundry.multiapps.controller.persistence.util.ObjectStoreConstants;
import org.cloudfoundry.multiapps.controller.persistence.util.ObjectStoreFilter;
import org.cloudfoundry.multiapps.controller.persistence.util.ObjectStoreMapper;
Expand All @@ -25,6 +27,7 @@
import java.io.InputStream;
import java.nio.channels.Channels;
import java.text.MessageFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Base64;
Expand All @@ -41,10 +44,12 @@

private final String bucketName;
private final Storage storage;
private final UploadDurationTracker uploadDurationTracker;

public GcpObjectStoreFileStorage(Map<String, Object> credentials) {
public GcpObjectStoreFileStorage(Map<String, Object> credentials, UploadDurationTracker uploadDurationTracker) {
this.bucketName = (String) credentials.get(CredentialKeys.BUCKET);
this.storage = createObjectStoreStorage(credentials);
this.uploadDurationTracker = uploadDurationTracker;
}

protected Storage createObjectStoreStorage(Map<String, Object> credentials) {
Expand Down Expand Up @@ -92,11 +97,16 @@
}

private void putBlob(BlobInfo blobInfo, InputStream content) throws FileStorageException {
LocalDateTime startTime = LocalDateTime.now();

Check warning on line 100 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/GcpObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Explicitly specify the time zone by passing a ZoneId or a Clock to the .now() method.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3gua9Cp9xIDHFHEoG&open=AZ-3gua9Cp9xIDHFHEoG&pullRequest=1885
try {
storage.createFrom(blobInfo, content);
} catch (IOException | StorageException e) {
uploadDurationTracker.recordObjectStoreUpload(getElapsedTimeInMillis(startTime),
UploadTimeoutMatcher.isUploadTimeoutException(e));
throw new FileStorageException(e);
}
uploadDurationTracker.recordObjectStoreUpload(getElapsedTimeInMillis(startTime), false);
LOGGER.info(MessageFormat.format(Messages.TIME_ELAPSED_FOR_GCP_OS_UPLOAD_0_IN_MILLIS, getElapsedTimeInMillis(startTime)));

Check warning on line 109 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/GcpObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Invoke method(s) only conditionally.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3gua9Cp9xIDHFHEoF&open=AZ-3gua9Cp9xIDHFHEoF&pullRequest=1885
}

@Override
Expand Down Expand Up @@ -283,4 +293,10 @@
static final String BASE_64_ENCODED_PRIVATE_KEY_DATA = "base64EncodedPrivateKeyData";
static final String BUCKET = "bucket";
}

private long getElapsedTimeInMillis(LocalDateTime startTime) {
return Duration.between(startTime, LocalDateTime.now())

Check warning on line 298 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/GcpObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Convert these arguments to time zone-aware types before computing a duration between them.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3gua9Cp9xIDHFHEoH&open=AZ-3gua9Cp9xIDHFHEoH&pullRequest=1885

Check warning on line 298 in multiapps-controller-persistence/src/main/java/org/cloudfoundry/multiapps/controller/persistence/services/GcpObjectStoreFileStorage.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Explicitly specify the time zone by passing a ZoneId or a Clock to the .now() method.

See more on https://sonarcloud.io/project/issues?id=cloudfoundry_multiapps-controller&issues=AZ-3gua9Cp9xIDHFHEoI&open=AZ-3gua9Cp9xIDHFHEoI&pullRequest=1885
.toMillis();
}

}
Loading
Loading