From 4cd6272abe18efa025f9e156c847dab07193b9c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 2 Apr 2019 11:30:55 +0200 Subject: [PATCH] google-cloud-logging-logback: Allow user to specify custom LoggingOptions (#4729) google-cloud-logging-logback: #3215 allow user to specify custom LoggingOptions --- .../google-cloud-logging-logback/README.md | 3 ++ .../logging/logback/LoggingAppender.java | 47 ++++++++++++++++++- .../logging/logback/LoggingAppenderTest.java | 28 +++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/README.md b/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/README.md index 644f081c60ac..dbc78d656ee0 100644 --- a/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/README.md +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/README.md @@ -50,6 +50,8 @@ See [Logback filters](https://logback.qos.ch/manual/filters.html#thresholdFilter INFO application.log + + /path/to/credentials.json com.example.enhancers.TestLoggingEnhancer com.example.enhancers.AnotherEnhancer WARN @@ -88,6 +90,7 @@ Authentication See the [Authentication](https://github.com/googleapis/google-cloud-java#authentication) section in the base directory's README. +You can also specify custom credentials by setting the optional property credentialsFile in your configuration file. Limitations ----------- diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/src/main/java/com/google/cloud/logging/logback/LoggingAppender.java b/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/src/main/java/com/google/cloud/logging/logback/LoggingAppender.java index 23d5e4183fdf..2e49e8d51e9a 100644 --- a/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/src/main/java/com/google/cloud/logging/logback/LoggingAppender.java +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/src/main/java/com/google/cloud/logging/logback/LoggingAppender.java @@ -23,6 +23,7 @@ import ch.qos.logback.core.UnsynchronizedAppenderBase; import ch.qos.logback.core.util.Loader; import com.google.api.core.InternalApi; +import com.google.auth.oauth2.GoogleCredentials; import com.google.cloud.MonitoredResource; import com.google.cloud.logging.LogEntry; import com.google.cloud.logging.Logging; @@ -32,6 +33,9 @@ import com.google.cloud.logging.MonitoredResourceUtil; import com.google.cloud.logging.Payload; import com.google.cloud.logging.Severity; +import com.google.common.base.Strings; +import java.io.FileInputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -55,6 +59,8 @@ * Standard, GCE and GKE, defaults to "global". See supported resource * types + *
  • <credentialsFile>/path/to/credentials/file</credentialsFile> (Optional, + * defaults to the default credentials of the environment) *
  • (Optional) add custom labels to log entries using {@link LoggingEnhancer} classes. *
  • <enhancer>com.example.enhancer1</enhancer> *
  • <enhancer>com.example.enhancer2</enhancer> @@ -67,6 +73,7 @@ public class LoggingAppender extends UnsynchronizedAppenderBase { private static final String LEVEL_VALUE_KEY = "levelValue"; private volatile Logging logging; + private LoggingOptions loggingOptions; private List loggingEnhancers; private List loggingEventEnhancers; private WriteOption[] defaultWriteOptions; @@ -74,6 +81,7 @@ public class LoggingAppender extends UnsynchronizedAppenderBase { private Level flushLevel; private String log; private String resourceType; + private String credentialsFile; private Set enhancerClassNames = new HashSet<>(); private Set loggingEventEnhancerClassNames = new HashSet<>(); @@ -111,6 +119,17 @@ public void setResourceType(String resourceType) { this.resourceType = resourceType; } + /** + * Sets the credentials file to use to create the {@link LoggingOptions}. The credentials returned + * by {@link GoogleCredentials#getApplicationDefault()} will be used if no custom credentials file + * has been set. + * + * @param credentialsFile The credentials file to use. + */ + public void setCredentialsFile(String credentialsFile) { + this.credentialsFile = credentialsFile; + } + /** Add extra labels using classes that implement {@link LoggingEnhancer}. */ public void addEnhancer(String enhancerClassName) { this.enhancerClassNames.add(enhancerClassName); @@ -186,7 +205,7 @@ public synchronized void start() { } String getProjectId() { - return LoggingOptions.getDefaultInstance().getProjectId(); + return getLoggingOptions().getProjectId(); } @Override @@ -212,13 +231,37 @@ Logging getLogging() { if (logging == null) { synchronized (this) { if (logging == null) { - logging = LoggingOptions.getDefaultInstance().getService(); + logging = getLoggingOptions().getService(); } } } return logging; } + /** Gets the {@link LoggingOptions} to use for this {@link LoggingAppender}. */ + LoggingOptions getLoggingOptions() { + if (loggingOptions == null) { + if (Strings.isNullOrEmpty(credentialsFile)) { + loggingOptions = LoggingOptions.getDefaultInstance(); + } else { + try { + loggingOptions = + LoggingOptions.newBuilder() + .setCredentials( + GoogleCredentials.fromStream(new FileInputStream(credentialsFile))) + .build(); + } catch (IOException e) { + throw new RuntimeException( + String.format( + "Could not read credentials file %s. Please verify that the file exists and is a valid Google credentials file.", + credentialsFile), + e); + } + } + } + return loggingOptions; + } + private LogEntry logEntryFor(ILoggingEvent e) { StringBuilder payload = new StringBuilder(e.getFormattedMessage()).append('\n'); writeStack(e.getThrowableProxy(), "", payload); diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/src/test/java/com/google/cloud/logging/logback/LoggingAppenderTest.java b/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/src/test/java/com/google/cloud/logging/logback/LoggingAppenderTest.java index 5855c80177d7..9b66d88dc501 100644 --- a/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/src/test/java/com/google/cloud/logging/logback/LoggingAppenderTest.java +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback/src/test/java/com/google/cloud/logging/logback/LoggingAppenderTest.java @@ -22,6 +22,7 @@ import static org.easymock.EasyMock.expectLastCall; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; +import static org.junit.Assert.fail; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.filter.ThresholdFilter; @@ -31,6 +32,7 @@ import com.google.cloud.logging.LogEntry; import com.google.cloud.logging.Logging; import com.google.cloud.logging.Logging.WriteOption; +import com.google.cloud.logging.LoggingOptions; import com.google.cloud.logging.Payload.StringPayload; import com.google.cloud.logging.Severity; import com.google.common.collect.ImmutableMap; @@ -211,6 +213,32 @@ public void testMdcValuesAreConvertedToLabels() { assertThat(capturedArgument.getValue().iterator().next()).isEqualTo(logEntry); } + @Test + public void testCreateLoggingOptions() { + // Try to build LoggingOptions with custom credentials. + final String nonExistentFile = "/path/to/non/existent/file"; + LoggingAppender appender = new LoggingAppender(); + appender.setCredentialsFile(nonExistentFile); + try { + appender.getLoggingOptions(); + fail("Expected exception"); + } catch (Exception e) { + assertThat(e.getMessage().contains(nonExistentFile)); + } + // Try to build LoggingOptions with default credentials. + LoggingOptions defaultOptions = null; + try { + defaultOptions = LoggingOptions.getDefaultInstance(); + } catch (Exception e) { + // Could not build a default LoggingOptions instance. + } + if (defaultOptions != null) { + appender = new LoggingAppender(); + LoggingOptions options = appender.getLoggingOptions(); + assertThat(options).isEqualTo(defaultOptions); + } + } + private LoggingEvent createLoggingEvent(Level level, long timestamp) { LoggingEvent loggingEvent = new LoggingEvent(); loggingEvent.setMessage("this is a test");