Skip to content
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

feat: Add an ability to delete logs based on project, folder, organization or billing account resource names #731

Merged
merged 6 commits into from Nov 3, 2021
Merged
9 changes: 9 additions & 0 deletions google-cloud-logging/clirr-ignored-differences.xml
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- see http://www.mojohaus.org/clirr-maven-plugin/examples/ignored-differences.html -->
<differences>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/logging/Logging</className>
<method>* deleteLog*(*)</method>
losalex marked this conversation as resolved.
Show resolved Hide resolved
</difference>
</differences>
Expand Up @@ -597,6 +597,57 @@ default ApiFuture<AsyncPage<String>> listLogsAsync(ListOption... options) {
*/
boolean deleteLog(String log);

/**
* Deletes a log and all its log entries for given log destination (see 'logName' parameter in
* https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry). The log will reappear if
* new entries are written to it.
*
* <p>Example of deleting a log.
*
* <pre>
* {
* &#64;code
* String logName = "my_log_name";
* String folder = "my_folder";
losalex marked this conversation as resolved.
Show resolved Hide resolved
* boolean deleted = logging.deleteLog(logName, LogDestinationName.folder(folder));
* if (deleted) {
* // the log was deleted
* } else {
* // the log was not found
* }
* }
* </pre>
*
* @return {@code true} if the log was deleted, {@code false} if it was not found
*/
boolean deleteLog(String log, LogDestinationName destination);
losalex marked this conversation as resolved.
Show resolved Hide resolved

/**
* Sends a request for deleting a log and all its log entries for given log destination (see
* 'logName' parameter in https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry).
* This method returns a {@code ApiFuture} object to consume the result. {@link ApiFuture#get()}
* returns {@code true} if the log was deleted, {@code false} if it was not found.
*
* <p>Example of asynchronously deleting a log.
*
* <pre>
* {
* &#64;code
* String logName = "my_log_name";
* String folder = "my_folder";
* ApiFuture<Boolean> future = logging.deleteLogAsync(logName, LogDestinationName.folder(folder));
* // ...
* boolean deleted = future.get();
* if (deleted) {
* // the log was deleted
* } else {
* // the log was not found
* }
* }
* </pre>
*/
ApiFuture<Boolean> deleteLogAsync(String log, LogDestinationName destination);
losalex marked this conversation as resolved.
Show resolved Hide resolved

/**
* Sends a request for deleting a log and all its log entries. This method returns a {@code
* ApiFuture} object to consume the result. {@link ApiFuture#get()} returns {@code true} if the
Expand Down
Expand Up @@ -40,6 +40,7 @@
import com.google.cloud.logging.spi.v2.LoggingRpc;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
Expand Down Expand Up @@ -443,11 +444,23 @@ public boolean deleteLog(String log) {
return get(deleteLogAsync(log));
}

public boolean deleteLog(String log, LogDestinationName destination) {
return get(deleteLogAsyncImpl(log, destination));
}

public ApiFuture<Boolean> deleteLogAsync(String log) {
DeleteLogRequest request =
DeleteLogRequest.newBuilder()
.setLogName(LogName.ofProjectLogName(getOptions().getProjectId(), log).toString())
.build();
return deleteLogAsyncImpl(log, null);
losalex marked this conversation as resolved.
Show resolved Hide resolved
}

public ApiFuture<Boolean> deleteLogAsync(String log, LogDestinationName destination) {
return deleteLogAsyncImpl(log, destination);
losalex marked this conversation as resolved.
Show resolved Hide resolved
}

private ApiFuture<Boolean> deleteLogAsyncImpl(String log, LogDestinationName destination) {
LogName name =
Preconditions.checkNotNull(getLogName(getOptions().getProjectId(), log, destination));
losalex marked this conversation as resolved.
Show resolved Hide resolved

DeleteLogRequest request = DeleteLogRequest.newBuilder().setLogName(name.toString()).build();
return transform(rpc.delete(request), EMPTY_TO_BOOLEAN_FUNCTION);
}

Expand Down
Expand Up @@ -1777,6 +1777,50 @@ public void testDeleteLogAsync() throws ExecutionException, InterruptedException
assertTrue(logging.deleteLogAsync(LOG_NAME).get());
}

@Test
public void testDeleteLogBillingDestination() throws ExecutionException, InterruptedException {
losalex marked this conversation as resolved.
Show resolved Hide resolved
testDeleteByBestination(
losalex marked this conversation as resolved.
Show resolved Hide resolved
LOG_NAME, LOG_NAME_BILLING_PATH, LogDestinationName.billingAccount(BILLING), false);
}

@Test
public void testDeleteLogBillingDestinationAsync()
throws ExecutionException, InterruptedException {
testDeleteByBestination(
LOG_NAME, LOG_NAME_BILLING_PATH, LogDestinationName.billingAccount(BILLING), true);
}

@Test
public void testDeleteLogFolderDestination() throws ExecutionException, InterruptedException {
testDeleteByBestination(
LOG_NAME, LOG_NAME_FOLDER_PATH, LogDestinationName.folder(FOLDER), false);
}

@Test
public void testDeleteLogFolderDestinationAsync()
throws ExecutionException, InterruptedException {
testDeleteByBestination(
LOG_NAME, LOG_NAME_FOLDER_PATH, LogDestinationName.folder(FOLDER), true);
}

@Test
public void testDeleteLogOrgDestination() throws ExecutionException, InterruptedException {
testDeleteByBestination(
LOG_NAME, LOG_NAME_ORGANIZATION_PATH, LogDestinationName.organization(ORGANIZATION), false);
}

@Test
public void testDeleteLogOrgDestinationAsync() throws ExecutionException, InterruptedException {
testDeleteByBestination(
LOG_NAME, LOG_NAME_ORGANIZATION_PATH, LogDestinationName.organization(ORGANIZATION), true);
}

@Test
public void testDeleteLogProjectDestination() throws ExecutionException, InterruptedException {
testDeleteByBestination(
LOG_NAME, LOG_NAME_PROJECT_PATH, LogDestinationName.project(PROJECT), false);
}

@Test
public void testDeleteLogAsync_Null() throws ExecutionException, InterruptedException {
DeleteLogRequest request =
Expand Down Expand Up @@ -2241,6 +2285,20 @@ public void run() {
assertSame(0, exceptions.get());
}

private void testDeleteByBestination(
losalex marked this conversation as resolved.
Show resolved Hide resolved
String logId, String logName, LogDestinationName destination, boolean useAsyncDelete)
throws ExecutionException, InterruptedException {
DeleteLogRequest request = DeleteLogRequest.newBuilder().setLogName(logName).build();
ApiFuture<Empty> response = ApiFutures.immediateFuture(Empty.getDefaultInstance());
EasyMock.expect(loggingRpcMock.delete(request)).andReturn(response);
EasyMock.replay(rpcFactoryMock, loggingRpcMock);
logging = options.getService();
assertTrue(
useAsyncDelete
? logging.deleteLogAsync(logId, destination).get()
: logging.deleteLog(logId, destination));
}

private void testWriteLogEntriesWithDestination(
String projectId, String fullLogNamePath, LogDestinationName destination) {
Map<String, String> labels = ImmutableMap.of("key", "value");
Expand Down