Skip to content

Commit 1996cb4

Browse files
feat: Extend a set of options in WriteOption to allow defining the log 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>
1 parent 63986be commit 1996cb4

File tree

7 files changed

+324
-95
lines changed

7 files changed

+324
-95
lines changed

google-cloud-logging/src/main/java/com/google/cloud/logging/Logging.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ final class WriteOption extends Option {
6969
enum OptionType implements Option.OptionType {
7070
LOG_NAME,
7171
RESOURCE,
72-
LABELS;
72+
LABELS,
73+
LOG_DESTINATION;
7374

7475
@SuppressWarnings("unchecked")
7576
<T> T get(Map<Option.OptionType, ?> options) {
@@ -105,6 +106,14 @@ public static WriteOption resource(MonitoredResource resource) {
105106
public static WriteOption labels(Map<String, String> labels) {
106107
return new WriteOption(OptionType.LABELS, ImmutableMap.copyOf(labels));
107108
}
109+
110+
/**
111+
* Returns an option to specify a log destination resource path (see {@link LogDestinationName}
112+
* for details)
113+
*/
114+
public static WriteOption destination(LogDestinationName destination) {
115+
return new WriteOption(OptionType.LOG_DESTINATION, destination);
116+
}
108117
}
109118

110119
/** Fields according to which log entries can be sorted. */

google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingHandler.java

+38-12
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import com.google.cloud.logging.Logging.WriteOption;
2323
import com.google.common.collect.ImmutableList;
2424
import com.google.common.collect.ImmutableMap;
25+
import com.google.common.collect.Iterables;
2526
import java.time.Instant;
27+
import java.util.ArrayList;
2628
import java.util.Collections;
2729
import java.util.LinkedList;
2830
import java.util.List;
@@ -172,7 +174,7 @@ public LoggingHandler(String log, LoggingOptions options) {
172174
* a default resource is created based on the project ID and deployment environment.
173175
*/
174176
public LoggingHandler(String log, LoggingOptions options, MonitoredResource monitoredResource) {
175-
this(log, options, monitoredResource, null);
177+
this(log, options, monitoredResource, null, null);
176178
}
177179

178180
/**
@@ -190,6 +192,27 @@ public LoggingHandler(
190192
LoggingOptions options,
191193
MonitoredResource monitoredResource,
192194
List<LoggingEnhancer> enhancers) {
195+
this(log, options, monitoredResource, enhancers, null);
196+
}
197+
198+
/**
199+
* Creates a handler that publishes messages to Cloud Logging.
200+
*
201+
* @param log the name of the log to which log entries are written
202+
* @param options options for the Cloud Logging service
203+
* @param monitoredResource the monitored resource to which log entries refer. If it is null then
204+
* a default resource is created based on the project ID and deployment environment.
205+
* @param enhancers List of {@link LoggingEnhancer} instances used to enhance any{@link LogEntry}
206+
* instances built by this handler.
207+
* @param destination the log destination {@link LogDestinationName} (see 'logName' parameter in
208+
* https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry)
209+
*/
210+
public LoggingHandler(
211+
String log,
212+
LoggingOptions options,
213+
MonitoredResource monitoredResource,
214+
List<LoggingEnhancer> enhancers,
215+
LogDestinationName destination) {
193216
try {
194217
loggingOptions = options != null ? options : LoggingOptions.getDefaultInstance();
195218
LoggingConfig config = new LoggingConfig(getClass().getName());
@@ -204,17 +227,20 @@ public LoggingHandler(
204227
MonitoredResource resource =
205228
firstNonNull(
206229
monitoredResource, config.getMonitoredResource(loggingOptions.getProjectId()));
207-
defaultWriteOptions =
208-
new WriteOption[] {
209-
WriteOption.logName(logName),
210-
WriteOption.resource(resource),
211-
WriteOption.labels(
212-
ImmutableMap.of(
213-
LEVEL_NAME_KEY,
214-
baseLevel.getName(),
215-
LEVEL_VALUE_KEY,
216-
String.valueOf(baseLevel.intValue())))
217-
};
230+
List<WriteOption> writeOptions = new ArrayList<WriteOption>();
231+
writeOptions.add(WriteOption.logName(logName));
232+
writeOptions.add(WriteOption.resource(resource));
233+
writeOptions.add(
234+
WriteOption.labels(
235+
ImmutableMap.of(
236+
LEVEL_NAME_KEY,
237+
baseLevel.getName(),
238+
LEVEL_VALUE_KEY,
239+
String.valueOf(baseLevel.intValue()))));
240+
if (destination != null) {
241+
writeOptions.add(WriteOption.destination(destination));
242+
}
243+
defaultWriteOptions = Iterables.toArray(writeOptions, WriteOption.class);
218244

219245
getLogging().setFlushSeverity(severityFor(flushLevel));
220246
getLogging().setWriteSynchronicity(config.getSynchronicity());

google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java

+21-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static com.google.cloud.logging.Logging.ListOption.OptionType.PAGE_SIZE;
2222
import static com.google.cloud.logging.Logging.ListOption.OptionType.PAGE_TOKEN;
2323
import static com.google.cloud.logging.Logging.WriteOption.OptionType.LABELS;
24+
import static com.google.cloud.logging.Logging.WriteOption.OptionType.LOG_DESTINATION;
2425
import static com.google.cloud.logging.Logging.WriteOption.OptionType.LOG_NAME;
2526
import static com.google.cloud.logging.Logging.WriteOption.OptionType.RESOURCE;
2627

@@ -738,11 +739,13 @@ private static WriteLogEntriesRequest writeLogEntriesRequest(
738739
LoggingOptions serviceOptions,
739740
Iterable<LogEntry> logEntries,
740741
Map<Option.OptionType, ?> options) {
741-
String projectId = serviceOptions.getProjectId();
742742
WriteLogEntriesRequest.Builder builder = WriteLogEntriesRequest.newBuilder();
743-
String logName = LOG_NAME.get(options);
743+
String projectId = serviceOptions.getProjectId();
744+
745+
LogName logName = getLogName(projectId, LOG_NAME.get(options), LOG_DESTINATION.get(options));
746+
744747
if (logName != null) {
745-
builder.setLogName(LogName.ofProjectLogName(projectId, logName).toString());
748+
builder.setLogName(logName.toString());
746749
}
747750
MonitoredResource resource = RESOURCE.get(options);
748751
if (resource != null) {
@@ -752,10 +755,25 @@ private static WriteLogEntriesRequest writeLogEntriesRequest(
752755
if (labels != null) {
753756
builder.putAllLabels(labels);
754757
}
758+
755759
builder.addAllEntries(Iterables.transform(logEntries, LogEntry.toPbFunction(projectId)));
756760
return builder.build();
757761
}
758762

763+
private static LogName getLogName(
764+
String projectId, String logName, LogDestinationName destination) {
765+
if (logName == null) {
766+
return null;
767+
}
768+
769+
// If no destination specified, fallback to project based log name
770+
if (destination == null) {
771+
return LogName.ofProjectLogName(projectId, logName);
772+
}
773+
774+
return destination.toLogName(logName);
775+
}
776+
759777
public void write(Iterable<LogEntry> logEntries, WriteOption... options) {
760778
if (inWriteCall.get() != null) {
761779
return;

google-cloud-logging/src/test/java/com/google/cloud/logging/LoggingHandlerTest.java

+45
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,28 @@ public void testPublishCustomResource() {
310310
handler.publish(newLogRecord(Level.FINEST, MESSAGE));
311311
}
312312

313+
@Test
314+
public void testPublishCustomResourceWithFolder() {
315+
testPublishCustomResourceWithDestination(FINEST_ENTRY, LogDestinationName.folder("folder"));
316+
}
317+
318+
@Test
319+
public void testPublishCustomResourceWithBilling() {
320+
testPublishCustomResourceWithDestination(
321+
FINEST_ENTRY, LogDestinationName.billingAccount("billing"));
322+
}
323+
324+
@Test
325+
public void testPublishCustomResourceWithOrganization() {
326+
testPublishCustomResourceWithDestination(
327+
FINEST_ENTRY, LogDestinationName.organization("organization"));
328+
}
329+
330+
@Test
331+
public void testPublishCustomResourceWithProject() {
332+
testPublishCustomResourceWithDestination(FINEST_ENTRY, LogDestinationName.project(PROJECT));
333+
}
334+
313335
@Test
314336
public void testPublishKubernetesContainerResource() {
315337
expect(options.getProjectId()).andReturn(PROJECT).anyTimes();
@@ -582,4 +604,27 @@ public void testClose() throws Exception {
582604
handler.close();
583605
handler.close();
584606
}
607+
608+
private void testPublishCustomResourceWithDestination(
609+
LogEntry entry, LogDestinationName destination) {
610+
expect(options.getProjectId()).andReturn(PROJECT).anyTimes();
611+
expect(options.getService()).andReturn(logging);
612+
logging.setFlushSeverity(Severity.ERROR);
613+
expectLastCall().once();
614+
logging.setWriteSynchronicity(Synchronicity.ASYNC);
615+
expectLastCall().once();
616+
MonitoredResource resource = MonitoredResource.of("custom", ImmutableMap.<String, String>of());
617+
logging.write(
618+
ImmutableList.of(entry),
619+
WriteOption.logName(LOG_NAME),
620+
WriteOption.resource(resource),
621+
WriteOption.labels(BASE_SEVERITY_MAP),
622+
WriteOption.destination(destination));
623+
expectLastCall().once();
624+
replay(options, logging);
625+
Handler handler = new LoggingHandler(LOG_NAME, options, resource, null, destination);
626+
handler.setLevel(Level.ALL);
627+
handler.setFormatter(new TestFormatter());
628+
handler.publish(newLogRecord(Level.FINEST, MESSAGE));
629+
}
585630
}

0 commit comments

Comments
 (0)