Skip to content

Commit

Permalink
feat: Extend a set of options in WriteOption to allow defining the lo…
Browse files Browse the repository at this point in the history
…g location as custom project, folder, organization or billing account (#727)

* feat: Extend a set of options in WriteOption to allow defining the log location as custom project, folder, organization or billing account

* Fix a test and small refactor in writeLogEntriesRequest

* 🦉 Updates from OwlBot

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* Make sure we do not propagate project id from request to log entries during write() and fix tests accordingly to cover all cases

* Add an empty log entry to be tested with latest destination handling logic

* Address PR comments

* 🦉 Updates from OwlBot

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* Fix lint errors

* Address test related PR comments

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
losalex and gcf-owl-bot[bot] committed Nov 2, 2021
1 parent 63986be commit 1996cb4
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 95 deletions.
Expand Up @@ -69,7 +69,8 @@ final class WriteOption extends Option {
enum OptionType implements Option.OptionType {
LOG_NAME,
RESOURCE,
LABELS;
LABELS,
LOG_DESTINATION;

@SuppressWarnings("unchecked")
<T> T get(Map<Option.OptionType, ?> options) {
Expand Down Expand Up @@ -105,6 +106,14 @@ public static WriteOption resource(MonitoredResource resource) {
public static WriteOption labels(Map<String, String> labels) {
return new WriteOption(OptionType.LABELS, ImmutableMap.copyOf(labels));
}

/**
* Returns an option to specify a log destination resource path (see {@link LogDestinationName}
* for details)
*/
public static WriteOption destination(LogDestinationName destination) {
return new WriteOption(OptionType.LOG_DESTINATION, destination);
}
}

/** Fields according to which log entries can be sorted. */
Expand Down
Expand Up @@ -22,7 +22,9 @@
import com.google.cloud.logging.Logging.WriteOption;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
Expand Down Expand Up @@ -172,7 +174,7 @@ public LoggingHandler(String log, LoggingOptions options) {
* a default resource is created based on the project ID and deployment environment.
*/
public LoggingHandler(String log, LoggingOptions options, MonitoredResource monitoredResource) {
this(log, options, monitoredResource, null);
this(log, options, monitoredResource, null, null);
}

/**
Expand All @@ -190,6 +192,27 @@ public LoggingHandler(
LoggingOptions options,
MonitoredResource monitoredResource,
List<LoggingEnhancer> enhancers) {
this(log, options, monitoredResource, enhancers, null);
}

/**
* Creates a handler that publishes messages to Cloud Logging.
*
* @param log the name of the log to which log entries are written
* @param options options for the Cloud Logging service
* @param monitoredResource the monitored resource to which log entries refer. If it is null then
* a default resource is created based on the project ID and deployment environment.
* @param enhancers List of {@link LoggingEnhancer} instances used to enhance any{@link LogEntry}
* instances built by this handler.
* @param destination the log destination {@link LogDestinationName} (see 'logName' parameter in
* https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry)
*/
public LoggingHandler(
String log,
LoggingOptions options,
MonitoredResource monitoredResource,
List<LoggingEnhancer> enhancers,
LogDestinationName destination) {
try {
loggingOptions = options != null ? options : LoggingOptions.getDefaultInstance();
LoggingConfig config = new LoggingConfig(getClass().getName());
Expand All @@ -204,17 +227,20 @@ public LoggingHandler(
MonitoredResource resource =
firstNonNull(
monitoredResource, config.getMonitoredResource(loggingOptions.getProjectId()));
defaultWriteOptions =
new WriteOption[] {
WriteOption.logName(logName),
WriteOption.resource(resource),
WriteOption.labels(
ImmutableMap.of(
LEVEL_NAME_KEY,
baseLevel.getName(),
LEVEL_VALUE_KEY,
String.valueOf(baseLevel.intValue())))
};
List<WriteOption> writeOptions = new ArrayList<WriteOption>();
writeOptions.add(WriteOption.logName(logName));
writeOptions.add(WriteOption.resource(resource));
writeOptions.add(
WriteOption.labels(
ImmutableMap.of(
LEVEL_NAME_KEY,
baseLevel.getName(),
LEVEL_VALUE_KEY,
String.valueOf(baseLevel.intValue()))));
if (destination != null) {
writeOptions.add(WriteOption.destination(destination));
}
defaultWriteOptions = Iterables.toArray(writeOptions, WriteOption.class);

getLogging().setFlushSeverity(severityFor(flushLevel));
getLogging().setWriteSynchronicity(config.getSynchronicity());
Expand Down
Expand Up @@ -21,6 +21,7 @@
import static com.google.cloud.logging.Logging.ListOption.OptionType.PAGE_SIZE;
import static com.google.cloud.logging.Logging.ListOption.OptionType.PAGE_TOKEN;
import static com.google.cloud.logging.Logging.WriteOption.OptionType.LABELS;
import static com.google.cloud.logging.Logging.WriteOption.OptionType.LOG_DESTINATION;
import static com.google.cloud.logging.Logging.WriteOption.OptionType.LOG_NAME;
import static com.google.cloud.logging.Logging.WriteOption.OptionType.RESOURCE;

Expand Down Expand Up @@ -738,11 +739,13 @@ private static WriteLogEntriesRequest writeLogEntriesRequest(
LoggingOptions serviceOptions,
Iterable<LogEntry> logEntries,
Map<Option.OptionType, ?> options) {
String projectId = serviceOptions.getProjectId();
WriteLogEntriesRequest.Builder builder = WriteLogEntriesRequest.newBuilder();
String logName = LOG_NAME.get(options);
String projectId = serviceOptions.getProjectId();

LogName logName = getLogName(projectId, LOG_NAME.get(options), LOG_DESTINATION.get(options));

if (logName != null) {
builder.setLogName(LogName.ofProjectLogName(projectId, logName).toString());
builder.setLogName(logName.toString());
}
MonitoredResource resource = RESOURCE.get(options);
if (resource != null) {
Expand All @@ -752,10 +755,25 @@ private static WriteLogEntriesRequest writeLogEntriesRequest(
if (labels != null) {
builder.putAllLabels(labels);
}

builder.addAllEntries(Iterables.transform(logEntries, LogEntry.toPbFunction(projectId)));
return builder.build();
}

private static LogName getLogName(
String projectId, String logName, LogDestinationName destination) {
if (logName == null) {
return null;
}

// If no destination specified, fallback to project based log name
if (destination == null) {
return LogName.ofProjectLogName(projectId, logName);
}

return destination.toLogName(logName);
}

public void write(Iterable<LogEntry> logEntries, WriteOption... options) {
if (inWriteCall.get() != null) {
return;
Expand Down
Expand Up @@ -310,6 +310,28 @@ public void testPublishCustomResource() {
handler.publish(newLogRecord(Level.FINEST, MESSAGE));
}

@Test
public void testPublishCustomResourceWithFolder() {
testPublishCustomResourceWithDestination(FINEST_ENTRY, LogDestinationName.folder("folder"));
}

@Test
public void testPublishCustomResourceWithBilling() {
testPublishCustomResourceWithDestination(
FINEST_ENTRY, LogDestinationName.billingAccount("billing"));
}

@Test
public void testPublishCustomResourceWithOrganization() {
testPublishCustomResourceWithDestination(
FINEST_ENTRY, LogDestinationName.organization("organization"));
}

@Test
public void testPublishCustomResourceWithProject() {
testPublishCustomResourceWithDestination(FINEST_ENTRY, LogDestinationName.project(PROJECT));
}

@Test
public void testPublishKubernetesContainerResource() {
expect(options.getProjectId()).andReturn(PROJECT).anyTimes();
Expand Down Expand Up @@ -582,4 +604,27 @@ public void testClose() throws Exception {
handler.close();
handler.close();
}

private void testPublishCustomResourceWithDestination(
LogEntry entry, LogDestinationName destination) {
expect(options.getProjectId()).andReturn(PROJECT).anyTimes();
expect(options.getService()).andReturn(logging);
logging.setFlushSeverity(Severity.ERROR);
expectLastCall().once();
logging.setWriteSynchronicity(Synchronicity.ASYNC);
expectLastCall().once();
MonitoredResource resource = MonitoredResource.of("custom", ImmutableMap.<String, String>of());
logging.write(
ImmutableList.of(entry),
WriteOption.logName(LOG_NAME),
WriteOption.resource(resource),
WriteOption.labels(BASE_SEVERITY_MAP),
WriteOption.destination(destination));
expectLastCall().once();
replay(options, logging);
Handler handler = new LoggingHandler(LOG_NAME, options, resource, null, destination);
handler.setLevel(Level.ALL);
handler.setFormatter(new TestFormatter());
handler.publish(newLogRecord(Level.FINEST, MESSAGE));
}
}

0 comments on commit 1996cb4

Please sign in to comment.