Skip to content

Commit 0f36f52

Browse files
authored
google-cloud-logging-logback: Allow user to specify custom LoggingOptions (googleapis#4729)
google-cloud-logging-logback: googleapis#3215 allow user to specify custom LoggingOptions
1 parent 7e1d8e5 commit 0f36f52

3 files changed

Lines changed: 76 additions & 2 deletions

File tree

java-logging/google-cloud-contrib/google-cloud-logging-logback/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ See [Logback filters](https://logback.qos.ch/manual/filters.html#thresholdFilter
5050
<level>INFO</level>
5151
</filter>
5252
<log>application.log</log> <!-- Optional : default java.log -->
53+
<!-- Optional : will use the default credentials of the environment if this property is not set -->
54+
<credentialsFile>/path/to/credentials.json</credentialsFile>
5355
<enhancer>com.example.enhancers.TestLoggingEnhancer</enhancer> <!-- Optional -->
5456
<enhancer>com.example.enhancers.AnotherEnhancer</enhancer> <!-- Optional -->
5557
<flushLevel>WARN</flushLevel> <!-- Optional : default ERROR -->
@@ -88,6 +90,7 @@ Authentication
8890
See the [Authentication](https://github.com/googleapis/google-cloud-java#authentication)
8991
section in the base directory's README.
9092

93+
You can also specify custom credentials by setting the optional property credentialsFile in your configuration file.
9194

9295
Limitations
9396
-----------

java-logging/google-cloud-contrib/google-cloud-logging-logback/src/main/java/com/google/cloud/logging/logback/LoggingAppender.java

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import ch.qos.logback.core.UnsynchronizedAppenderBase;
2424
import ch.qos.logback.core.util.Loader;
2525
import com.google.api.core.InternalApi;
26+
import com.google.auth.oauth2.GoogleCredentials;
2627
import com.google.cloud.MonitoredResource;
2728
import com.google.cloud.logging.LogEntry;
2829
import com.google.cloud.logging.Logging;
@@ -32,6 +33,9 @@
3233
import com.google.cloud.logging.MonitoredResourceUtil;
3334
import com.google.cloud.logging.Payload;
3435
import com.google.cloud.logging.Severity;
36+
import com.google.common.base.Strings;
37+
import java.io.FileInputStream;
38+
import java.io.IOException;
3539
import java.util.ArrayList;
3640
import java.util.Collections;
3741
import java.util.HashSet;
@@ -55,6 +59,8 @@
5559
* Standard, GCE and GKE, defaults to "global". See <a
5660
* href="https://cloud.google.com/logging/docs/api/v2/resource-list">supported resource
5761
* types</a>
62+
* <li>&lt;credentialsFile&gt;/path/to/credentials/file&lt;/credentialsFile&gt; (Optional,
63+
* defaults to the default credentials of the environment)
5864
* <li>(Optional) add custom labels to log entries using {@link LoggingEnhancer} classes.
5965
* <li>&lt;enhancer&gt;com.example.enhancer1&lt;/enhancer&gt;
6066
* <li>&lt;enhancer&gt;com.example.enhancer2&lt;/enhancer&gt;
@@ -67,13 +73,15 @@ public class LoggingAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
6773
private static final String LEVEL_VALUE_KEY = "levelValue";
6874

6975
private volatile Logging logging;
76+
private LoggingOptions loggingOptions;
7077
private List<LoggingEnhancer> loggingEnhancers;
7178
private List<LoggingEventEnhancer> loggingEventEnhancers;
7279
private WriteOption[] defaultWriteOptions;
7380

7481
private Level flushLevel;
7582
private String log;
7683
private String resourceType;
84+
private String credentialsFile;
7785
private Set<String> enhancerClassNames = new HashSet<>();
7886
private Set<String> loggingEventEnhancerClassNames = new HashSet<>();
7987

@@ -111,6 +119,17 @@ public void setResourceType(String resourceType) {
111119
this.resourceType = resourceType;
112120
}
113121

122+
/**
123+
* Sets the credentials file to use to create the {@link LoggingOptions}. The credentials returned
124+
* by {@link GoogleCredentials#getApplicationDefault()} will be used if no custom credentials file
125+
* has been set.
126+
*
127+
* @param credentialsFile The credentials file to use.
128+
*/
129+
public void setCredentialsFile(String credentialsFile) {
130+
this.credentialsFile = credentialsFile;
131+
}
132+
114133
/** Add extra labels using classes that implement {@link LoggingEnhancer}. */
115134
public void addEnhancer(String enhancerClassName) {
116135
this.enhancerClassNames.add(enhancerClassName);
@@ -186,7 +205,7 @@ public synchronized void start() {
186205
}
187206

188207
String getProjectId() {
189-
return LoggingOptions.getDefaultInstance().getProjectId();
208+
return getLoggingOptions().getProjectId();
190209
}
191210

192211
@Override
@@ -212,13 +231,37 @@ Logging getLogging() {
212231
if (logging == null) {
213232
synchronized (this) {
214233
if (logging == null) {
215-
logging = LoggingOptions.getDefaultInstance().getService();
234+
logging = getLoggingOptions().getService();
216235
}
217236
}
218237
}
219238
return logging;
220239
}
221240

241+
/** Gets the {@link LoggingOptions} to use for this {@link LoggingAppender}. */
242+
LoggingOptions getLoggingOptions() {
243+
if (loggingOptions == null) {
244+
if (Strings.isNullOrEmpty(credentialsFile)) {
245+
loggingOptions = LoggingOptions.getDefaultInstance();
246+
} else {
247+
try {
248+
loggingOptions =
249+
LoggingOptions.newBuilder()
250+
.setCredentials(
251+
GoogleCredentials.fromStream(new FileInputStream(credentialsFile)))
252+
.build();
253+
} catch (IOException e) {
254+
throw new RuntimeException(
255+
String.format(
256+
"Could not read credentials file %s. Please verify that the file exists and is a valid Google credentials file.",
257+
credentialsFile),
258+
e);
259+
}
260+
}
261+
}
262+
return loggingOptions;
263+
}
264+
222265
private LogEntry logEntryFor(ILoggingEvent e) {
223266
StringBuilder payload = new StringBuilder(e.getFormattedMessage()).append('\n');
224267
writeStack(e.getThrowableProxy(), "", payload);

java-logging/google-cloud-contrib/google-cloud-logging-logback/src/test/java/com/google/cloud/logging/logback/LoggingAppenderTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static org.easymock.EasyMock.expectLastCall;
2323
import static org.easymock.EasyMock.replay;
2424
import static org.easymock.EasyMock.verify;
25+
import static org.junit.Assert.fail;
2526

2627
import ch.qos.logback.classic.Level;
2728
import ch.qos.logback.classic.filter.ThresholdFilter;
@@ -31,6 +32,7 @@
3132
import com.google.cloud.logging.LogEntry;
3233
import com.google.cloud.logging.Logging;
3334
import com.google.cloud.logging.Logging.WriteOption;
35+
import com.google.cloud.logging.LoggingOptions;
3436
import com.google.cloud.logging.Payload.StringPayload;
3537
import com.google.cloud.logging.Severity;
3638
import com.google.common.collect.ImmutableMap;
@@ -211,6 +213,32 @@ public void testMdcValuesAreConvertedToLabels() {
211213
assertThat(capturedArgument.getValue().iterator().next()).isEqualTo(logEntry);
212214
}
213215

216+
@Test
217+
public void testCreateLoggingOptions() {
218+
// Try to build LoggingOptions with custom credentials.
219+
final String nonExistentFile = "/path/to/non/existent/file";
220+
LoggingAppender appender = new LoggingAppender();
221+
appender.setCredentialsFile(nonExistentFile);
222+
try {
223+
appender.getLoggingOptions();
224+
fail("Expected exception");
225+
} catch (Exception e) {
226+
assertThat(e.getMessage().contains(nonExistentFile));
227+
}
228+
// Try to build LoggingOptions with default credentials.
229+
LoggingOptions defaultOptions = null;
230+
try {
231+
defaultOptions = LoggingOptions.getDefaultInstance();
232+
} catch (Exception e) {
233+
// Could not build a default LoggingOptions instance.
234+
}
235+
if (defaultOptions != null) {
236+
appender = new LoggingAppender();
237+
LoggingOptions options = appender.getLoggingOptions();
238+
assertThat(options).isEqualTo(defaultOptions);
239+
}
240+
}
241+
214242
private LoggingEvent createLoggingEvent(Level level, long timestamp) {
215243
LoggingEvent loggingEvent = new LoggingEvent();
216244
loggingEvent.setMessage("this is a test");

0 commit comments

Comments
 (0)