diff --git a/google-cloud-contrib/google-cloud-logging-adapters/README.md b/google-cloud-contrib/google-cloud-logging-adapters/README.md new file mode 100644 index 000000000000..9a62a01002f8 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/README.md @@ -0,0 +1,8 @@ +# cloud-logging-adapters +Cloud logging adapters with standard Java frameworks + +- Write structured logs to Cloud logging, stdout or via socket (Fluentd forwarding port) + +Slf4j : +- [README](cloud-logging-over-slf4j/README.md) +- Example application [here](test-adapters) diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/README.md b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/README.md new file mode 100644 index 000000000000..6b62dac1677f --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/README.md @@ -0,0 +1,67 @@ +## Slf4j Adapter for Google Cloud Logging + +Built with [Slf4j](https://www.slf4j.org/) v1.7.21 and +[Google cloud logging library](https://github.com/GoogleCloudPlatform/google-cloud-java/tree/master/google-cloud-logging) + +Adapter library for [Google Cloud logging](https://cloud.google.com/logging/docs/view/logs_viewer_v2) over Slf4j. + + +## Configuration and setup +Install [Apache Maven](https://maven.apache.org/)

+`mvn clean install` + +If you are using Maven, add this to your pom.xml file +```xml + + com.example + cloud-logging-over-slf4j + 0.1.0-SNAPSHOT + +``` + +### Configuration file +Set system property or environment variable `CLOUD_LOGGING_CONFIG` to the absolute path of .yaml configuration file.

+Here is a sample configuration file : [google-cloud-logging.yaml](src/test/resources/google-cloud-logging.yaml)

+ +#### Fields +- `destination` (optional) : defaults to direct writes via API.

+Allowed values :

+ -`"stdout"` : logs to standard out

+ -`"fluentd"` logs to fluentd forwarding port (`localhost:24224`) + +- `loggers` (list) : (optional) + ##### Required fields for custom loggers : + - `name` : "default" or package/class name + ##### Optional fields : + - `log_name` defaults to `name` if not specified

+ - `resource` defaults to `global`, restricted to + [Supported ResourceTypes](https://cloud.google.com/logging/docs/api/v2/resource-list)

+ - `enable` : boolean [default : true]

+ - `level` : Min log level. Supported log levels [here](https://www.slf4j.org/api/org/apache/commons/logging/Log.html)

+ - `labels` (optional) : Adds custom labels to logs

+ - Format list of key, value pairs, eg `project_id: "$GOOGLE_CLOUD_PROJECT"` + - prefix values with `$` to use system/environment variable values. +

Use `default` logger name to update default logging parameters

+ +## Usage +Initialize the service in a class with +`Logger logger = LoggerFactory.getLogger(loggerName)` + +- Log using standard Slf4j formatting :

+ - `logger.info("Hello world {}: INFO", "app")`

+ - `logger.error("Hello world : {}", "exception", new Throwable("illegal argument"))`

+ - `logger.debug("Hello world : DEBUG")`

+ - `logger.trace("Hello world : TRACE")`

+ + - Markers can be used to set Cloud logging log levels that are not supported via Slf4j + : `NOTICE`, `CRITICAL`, `ALERT`, `EMERGENCY`

+ Examples :

+ - `logger.info(MarkerFactory.getMarker("NOTICE"), Hello world : INFO_NOTICE")`

+ - `logger.error(MarkerFactory.getMarker("CRITICAL"), "Hello world : Error")`

+ + - Markers can also be used to add custom labels

+ `logger.info(MarkerFactory.getMarker("label1:value1"), "Hello world : labels")`

+ + +## Todo +

Add support for fluentd port forwarding config, currently hardcoded \ No newline at end of file diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/pom.xml b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/pom.xml new file mode 100644 index 000000000000..73d6d5ad2ad0 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + com.example + cloud-logging-over-slf4j + 0.1.0-SNAPSHOT + + 1.7.21 + 0.9.3-beta + 1.7 + 1.7 + + + + org.slf4j + slf4j-api + ${slf4jVersion} + + + org.yaml + snakeyaml + 1.11 + + + com.google.cloud + google-cloud-logging + ${googleCloudLoggingVersion} + + + junit + junit + 4.12 + + + com.fasterxml.jackson.core + jackson-databind + 2.8.5 + + + \ No newline at end of file diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/CloudLogger.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/CloudLogger.java new file mode 100644 index 000000000000..70553cab31ee --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/CloudLogger.java @@ -0,0 +1,134 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl; + +import com.google.cloud.MonitoredResource; +import com.google.cloud.logging.LogEntry; +import com.google.cloud.logging.Payload.StringPayload; +import com.google.cloud.logging.Severity; +import com.google.common.base.Splitter; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.slf4j.Marker; +import org.slf4j.impl.config.ConfigLoader; +import org.slf4j.impl.logging.ILogging; +import org.slf4j.impl.logging.ILoggingFactory; + +/** Cloud logging service with external configuration */ +class CloudLogger { + + private static final String CONFIGURATION_FILE = "google-cloud-logging.yaml"; + private static final String CLOUD_LOGGING_CONFIG = "CLOUD_LOGGING_CONFIG"; + // 100kb payload limit : limit string payload to 95 kb (assume 2 bytes per character) + private static final int MAX_LOG_SIZE_IN_CHARS = 1024 * 95 / 2; + private static ConfigLoader configLoader; + private static ILogging logging; + private MonitoredResource resource; + private String fileName; + private String loggerName; + private Severity minSeverity; + private boolean isEnabled; + private Map labels; + + CloudLogger(String loggerName) throws Exception { + init(loggerName); + } + + static void init() { + String configFile = ConfigLoader.getValue(CLOUD_LOGGING_CONFIG, CONFIGURATION_FILE); + configLoader = new ConfigLoader(configFile); + logging = ILoggingFactory.get(configLoader.getDestination()); + logging.init(); + } + + String getName() { + return loggerName; + } + + boolean isEnabled(Severity severity) { + return (isEnabled && severity.compareTo(minSeverity) >= 0); + } + + void log(Marker marker, Severity severity, String text, Throwable throwable) { + writeLogEntries(marker, severity, text, throwable); + } + + void log(Severity severity, String text, Throwable throwable) { + writeLogEntries(null, severity, text, throwable); + } + + void log(Marker marker, Severity severity, String text) { + writeLogEntries(marker, severity, text, null); + } + + void log(Severity severity, String text) { + log(null, severity, text, null); + } + + private void updateConfig() { + minSeverity = configLoader.getSeverity(loggerName); + labels = configLoader.getLabels(loggerName); + fileName = configLoader.getFileName(loggerName); + this.resource = MonitoredResource.newBuilder(configLoader.getResource(loggerName)).build(); + this.isEnabled = configLoader.isEnabled(loggerName); + } + + private void init(String loggerName) throws Exception { + this.loggerName = loggerName; + updateConfig(); + } + + private LogEntry createLogEntry(Marker marker, Severity severity, String text) { + LogDetailsTuple logDetailsTuple = new LogDetailsTuple(marker, labels, severity); + return LogEntry.newBuilder(StringPayload.of(text)) + .setResource(resource) + .setLabels(logDetailsTuple.getLabels()) + .setLogName(fileName) + .setSeverity(logDetailsTuple.getLevel()) + .build(); + } + + private Iterable getChunks(String text) { + return Splitter.fixedLength(MAX_LOG_SIZE_IN_CHARS) + .omitEmptyStrings() + .split(text); + } + + private String getStackTrace(Throwable throwable) { + StringWriter errors = new StringWriter(); + throwable.printStackTrace(new PrintWriter(errors)); + return errors.toString(); + } + + private void writeLogEntries(Marker marker, Severity level, String text, Throwable t) { + if (!isEnabled(level)) { + return; + } + if (t != null) { + text = text + "\n" + getStackTrace(t); + } + Iterable chunks = getChunks(text); + List logEntries = new ArrayList<>(); + for (String chunk : chunks) { + logEntries.add(createLogEntry(marker, level, chunk)); + } + logging.write(logEntries); + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/CloudLoggingAdapter.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/CloudLoggingAdapter.java new file mode 100644 index 000000000000..d90a63e508de --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/CloudLoggingAdapter.java @@ -0,0 +1,312 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl; + +import com.google.cloud.logging.Severity; +import java.io.Serializable; +import org.slf4j.Logger; +import org.slf4j.Marker; +import org.slf4j.helpers.FormattingTuple; +import org.slf4j.helpers.MessageFormatter; + +public class CloudLoggingAdapter implements Logger, Serializable { + + private static final long serialVersionUID = 1L; + private CloudLogger cloudLogger; + + CloudLoggingAdapter(String loggerName) { + try { + cloudLogger = new CloudLogger(loggerName); + } catch (Exception e) { + e.printStackTrace(); + } + } + + static void lazyInit() { + CloudLogger.init(); + } + + public String getName() { + return cloudLogger.getName(); + } + + public boolean isTraceEnabled() { + return cloudLogger.isEnabled(Severity.DEBUG); + } + + public void trace(String s) { + log(Severity.DEBUG, s); + } + + public void trace(String s, Object o) { + log(Severity.DEBUG, s, o); + } + + public void trace(String format, Object o, Object o1) { + log(Severity.DEBUG, format, o, o1); + } + + public void trace(String format, Object[] objects) { + log(Severity.DEBUG, format, objects); + } + + public void trace(String s, Throwable throwable) { + log(Severity.DEBUG, s, throwable); + } + + public boolean isTraceEnabled(Marker marker) { + return cloudLogger.isEnabled(Severity.DEBUG); + } + + public void trace(Marker marker, String s) { + log(marker, Severity.DEBUG, s); + } + + public void trace(Marker marker, String format, Object o) { + log(marker, Severity.DEBUG, format, o); + } + + public void trace(Marker marker, String format, Object o, Object o1) { + log(Severity.DEBUG, format, o, o1); + } + + public void trace(Marker marker, String format, Object[] objects) { + log(marker, Severity.DEBUG, format, objects); + } + + public void trace(Marker marker, String s, Throwable throwable) { + log(marker, Severity.DEBUG, s, throwable); + } + + public boolean isDebugEnabled() { + return cloudLogger.isEnabled(Severity.DEBUG); + } + + public void debug(String s) { + log(Severity.DEBUG, s); + } + + public void debug(String format, Object o) { + log(Severity.DEBUG, format, o); + } + + public void debug(String format, Object o, Object o1) { + log(Severity.DEBUG, format, o, o1); + } + + public void debug(String format, Object[] objects) { + log(Severity.DEBUG, format, objects); + } + + public void debug(String s, Throwable throwable) { + log(Severity.DEBUG, s, throwable); + } + + public boolean isDebugEnabled(Marker marker) { + return cloudLogger.isEnabled(Severity.DEBUG); + } + + public void debug(Marker marker, String s) { + log(marker, Severity.DEBUG, s); + } + + public void debug(Marker marker, String format, Object o) { + log(marker, Severity.DEBUG, format, o); + } + + public void debug(Marker marker, String format, Object o, Object o1) { + log(marker, Severity.DEBUG, format, o, o1); + } + + public void debug(Marker marker, String format, Object[] objects) { + log(marker, Severity.DEBUG, format, objects); + } + + public void debug(Marker marker, String s, Throwable throwable) { + log(marker, Severity.DEBUG, s, throwable); + } + + public boolean isInfoEnabled() { + return cloudLogger.isEnabled(Severity.INFO); + } + + public void info(String s) { + log(Severity.INFO, s); + } + + public void info(String s, Object o) { + log(Severity.INFO, s, o); + } + + public void info(String s, Object o, Object o1) { + log(Severity.INFO, s, o, o1); + } + + public void info(String s, Object[] objects) { + log(Severity.INFO, s, objects); + } + + public void info(String s, Throwable throwable) { + log(Severity.INFO, s, throwable); + } + + public boolean isInfoEnabled(Marker marker) { + return cloudLogger.isEnabled(Severity.INFO); + } + + public void info(Marker marker, String s) { + cloudLogger.log(marker, Severity.INFO, s); + } + + public void info(Marker marker, String s, Object o) { + log(marker, Severity.INFO, s, o); + } + + public void info(Marker marker, String s, Object o, Object o1) { + log(marker, Severity.INFO, s, o, o1); + } + + public void info(Marker marker, String s, Object[] objects) { + log(marker, Severity.INFO, s, objects); + } + + public void info(Marker marker, String s, Throwable throwable) { + log(marker, Severity.INFO, s, throwable); + } + + public boolean isWarnEnabled() { + return cloudLogger.isEnabled(Severity.WARNING); + } + + public void warn(String s) { + log(Severity.WARNING, s); + } + + public void warn(String s, Object o) { + log(Severity.WARNING, s, o); + } + + public void warn(String s, Object[] objects) { + log(Severity.WARNING, s, objects); + } + + public void warn(String s, Object o, Object o1) { + log(Severity.WARNING, s, o, o1); + } + + public void warn(String s, Throwable throwable) { + log(Severity.WARNING, s, throwable); + } + + public boolean isWarnEnabled(Marker marker) { + return cloudLogger.isEnabled(Severity.WARNING); + } + + public void warn(Marker marker, String s) { + log(marker, Severity.WARNING, s); + } + + public void warn(Marker marker, String s, Object o) { + log(marker, Severity.WARNING, s, o); + } + + public void warn(Marker marker, String s, Object o, Object o1) { + log(marker, Severity.WARNING, s, o, o1); + } + + public void warn(Marker marker, String s, Object[] objects) { + log(marker, Severity.WARNING, s, objects); + } + + public void warn(Marker marker, String s, Throwable throwable) { + log(marker, Severity.WARNING, s, throwable); + } + + public boolean isErrorEnabled() { + return cloudLogger.isEnabled(Severity.ERROR); + } + + public void error(String s) { + log(Severity.ERROR, s); + } + + public void error(String s, Object o) { + log(Severity.ERROR, s, o); + } + + public void error(String s, Object o, Object o1) { + log(Severity.ERROR, s, o, o1); + } + + public void error(String s, Object[] objects) { + log(Severity.ERROR, s, objects); + } + + public void error(String s, Throwable throwable) { + log(Severity.ERROR, s, throwable); + } + + public boolean isErrorEnabled(Marker marker) { + return cloudLogger.isEnabled(Severity.ERROR); + } + + public void error(Marker marker, String s) { + cloudLogger.log(marker, Severity.ERROR, s); + } + + public void error(Marker marker, String s, Object o) { + log(marker, Severity.ERROR, s, o); + } + + public void error(Marker marker, String s, Object o, Object o1) { + log(marker, Severity.ERROR, s, o, o1); + } + + public void error(Marker marker, String s, Object[] objects) { + log(marker, Severity.ERROR, s, objects); + } + + public void error(Marker marker, String s, Throwable throwable) { + log(marker, Severity.ERROR, s, throwable); + } + + private void log(Severity severity, String s) { + if (cloudLogger.isEnabled(severity)) { + cloudLogger.log(severity, s); + } + } + + private void log(Severity severity, String format, Object... obj) { + if (cloudLogger.isEnabled(severity)) { + FormattingTuple tp = MessageFormatter.format(format, obj); + cloudLogger.log(severity, tp.getMessage(), tp.getThrowable()); + } + } + + private void log(Marker marker, Severity severity, String s) { + if (cloudLogger.isEnabled(severity)) { + cloudLogger.log(marker, severity, s); + } + } + + private void log(Marker marker, Severity severity, String format, Object... obj) { + if (cloudLogger.isEnabled(severity)) { + FormattingTuple tp = MessageFormatter.format(format, obj); + cloudLogger.log(marker, severity, tp.getMessage(), tp.getThrowable()); + } + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/LogDetailsTuple.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/LogDetailsTuple.java new file mode 100644 index 000000000000..444f5ba81db6 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/LogDetailsTuple.java @@ -0,0 +1,102 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl; + +import com.google.cloud.logging.Severity; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.slf4j.Marker; +import org.slf4j.impl.config.ConfigLoader; + +class LogDetailsTuple { + + private static final String DEFAULT_LABEL_VALUE = "true"; + private Map labels; + private Severity level; + + LogDetailsTuple(Marker marker, Map labels, Severity level) { + this.level = level; + this.labels = new HashMap<>(); + if (marker != null) { + add(marker); + Iterator markerIterator = marker.iterator(); + if (!markerIterator.hasNext()) { + add(marker); + } else { + while (markerIterator.hasNext()) { + add(markerIterator.next()); + } + } + if (labels != null) { + for (Map.Entry label : labels.entrySet()) { + add(label.getKey(), label.getValue()); + } + } + } + } + + private void add(Marker marker) { + String name = marker.getName(); + String value = DEFAULT_LABEL_VALUE; + String[] splits = name.split(":"); + if (splits.length == 2) { + name = splits[0]; + value = splits[1]; + } + add(name, value); + } + + private void add(String labelName, String labelValue) { + //label value from system property/environment + if (labelValue != null) { + if (labelValue.charAt(0) == '$' && labelValue.length() > 1) { + labelValue = ConfigLoader.getValue(labelValue.substring(1), DEFAULT_LABEL_VALUE); + } + } + // level label with higher severity overrides existing level, else gets added as label + if (labelName.toLowerCase().equals("level")) { + if (!overrideLevel(labelValue)) { + labels.put(labelName, labelValue); + } + } else if (!overrideLevel(labelName)) { + labels.put(labelName, labelValue); + } + } + + Map getLabels() { + return labels; + } + + Severity getLevel() { + return level; + } + + private boolean overrideLevel(String s) { + try { + Severity override = Severity.valueOf(s.toUpperCase()); + //If current severity is higher than marker severity, do not update + if (level == null || level.compareTo(override) < 0) { + level = override; + return true; + } + } catch (Exception e) { + return false; + } + return false; + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/LoggerFactory.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/LoggerFactory.java new file mode 100644 index 000000000000..3a0019e6f32d --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/LoggerFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.slf4j.impl; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; + +public class LoggerFactory implements ILoggerFactory { + + private final ConcurrentMap loggerMap; + + LoggerFactory() { + loggerMap = new ConcurrentHashMap<>(); + CloudLoggingAdapter.lazyInit(); + } + + /** Return an appropriate {@link CloudLoggingAdapter} instance by name. */ + public Logger getLogger(String name) { + Logger simpleLogger = loggerMap.get(name); + if (simpleLogger != null) { + return simpleLogger; + } else { + Logger newInstance = new CloudLoggingAdapter(name); + Logger oldInstance = loggerMap.putIfAbsent(name, newInstance); + return oldInstance == null ? newInstance : oldInstance; + } + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/StaticLoggerBinder.java new file mode 100644 index 000000000000..cdb4f372bc8d --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/StaticLoggerBinder.java @@ -0,0 +1,59 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.slf4j.impl; + +import org.slf4j.ILoggerFactory; +import org.slf4j.spi.LoggerFactoryBinder; + +public class StaticLoggerBinder implements LoggerFactoryBinder { + + /** The unique instance of this class. */ + private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); + + private static final String loggerFactoryClassStr = LoggerFactory.class.getName(); + /** + * Declare the version of the SLF4J API this implementation is compiled against. The value of this + * field is modified with each major release. + */ + // to avoid constant folding by the compiler, this field must *not* be final + public static String REQUESTED_API_VERSION = "1.6.1"; // !final + /** + * The ILoggerFactory instance returned by the {@link #getLoggerFactory} method should always be + * the same object + */ + private final ILoggerFactory loggerFactory; + + private StaticLoggerBinder() { + loggerFactory = new LoggerFactory(); + } + + /** + * Return the singleton of this class. + * + * @return the StaticLoggerBinder singleton + */ + public static final StaticLoggerBinder getSingleton() { + return SINGLETON; + } + + public ILoggerFactory getLoggerFactory() { + return loggerFactory; + } + + public String getLoggerFactoryClassStr() { + return loggerFactoryClassStr; + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/StaticMDCBinder.java new file mode 100644 index 000000000000..daa9cecbf8a1 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.slf4j.impl; + +import org.slf4j.helpers.NOPMDCAdapter; +import org.slf4j.spi.MDCAdapter; + +public class StaticMDCBinder { + + /** The unique instance of this class. */ + public static final StaticMDCBinder SINGLETON = new StaticMDCBinder(); + + private StaticMDCBinder() {} + + /** + * Return the singleton of this class. + * + * @return the StaticMDCBinder singleton + * @since 1.7.14 + */ + public static final StaticMDCBinder getSingleton() { + return SINGLETON; + } + + /** Currently this method always returns an instance of {@link StaticMDCBinder}. */ + public MDCAdapter getMDCA() { + return new NOPMDCAdapter(); + } + + public String getMDCAdapterClassStr() { + return NOPMDCAdapter.class.getName(); + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/StaticMarkerBinder.java new file mode 100644 index 000000000000..2e12695c531d --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -0,0 +1,50 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.slf4j.impl; + +import org.slf4j.IMarkerFactory; +import org.slf4j.helpers.BasicMarkerFactory; +import org.slf4j.spi.MarkerFactoryBinder; + +public class StaticMarkerBinder implements MarkerFactoryBinder { + + /** The unique instance of this class. */ + public static final StaticMarkerBinder SINGLETON = new StaticMarkerBinder(); + + final IMarkerFactory markerFactory = new BasicMarkerFactory(); + + private StaticMarkerBinder() {} + + /** + * Return the singleton of this class. + * + * @return the StaticMarkerBinder singleton + * @since 1.7.14 + */ + public static StaticMarkerBinder getSingleton() { + return SINGLETON; + } + + /** Currently this method always returns an instance of {@link BasicMarkerFactory}. */ + public IMarkerFactory getMarkerFactory() { + return markerFactory; + } + + /** Currently, this method returns the class name of {@link BasicMarkerFactory}. */ + public String getMarkerFactoryClassStr() { + return BasicMarkerFactory.class.getName(); + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/CloudLoggingConfig.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/CloudLoggingConfig.java new file mode 100644 index 000000000000..23f72f10f5c3 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/CloudLoggingConfig.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl.config; + +import java.util.List; + +public class CloudLoggingConfig { + + private String destination; + + private List loggers; + + public String getDestination() { + return destination; + } + + public void setDestination(String destination) { + this.destination = destination; + } + + public List getLoggers() { + return loggers; + } + + public void setLoggers(List loggers) { + this.loggers = loggers; + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/ConfigDefaults.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/ConfigDefaults.java new file mode 100644 index 000000000000..02c649375f11 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/ConfigDefaults.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl.config; + +import com.google.cloud.logging.Severity; + +public class ConfigDefaults { + + public static final Severity severity = Severity.DEFAULT; + public static final boolean enable = true; + public static final String resource = "global"; + public static final String destination = "default"; +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/ConfigLoader.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/ConfigLoader.java new file mode 100644 index 000000000000..a85be657a824 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/ConfigLoader.java @@ -0,0 +1,131 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl.config; + +import com.google.cloud.logging.Severity; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import org.yaml.snakeyaml.TypeDescription; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; + +public class ConfigLoader { + + private static final String DEFAULT_LOGGER_NAME = "default"; + private Map loggerConfigs; + private String destination; + + public ConfigLoader(String fileName) { + this.loggerConfigs = new HashMap<>(); + LoggerConfig defaultConfig = new LoggerConfig(DEFAULT_LOGGER_NAME); + loggerConfigs.put(DEFAULT_LOGGER_NAME, defaultConfig); + loadConfiguration(fileName); + } + + public static String getValue(String name, String defaultValue) { + String value = System.getProperty(name); + if (value == null || value.length() == 0) { + value = System.getenv(name); + } + if (value == null || value.length() == 0) { + value = defaultValue; + } + return value; + } + + @SuppressWarnings("unchecked") + private void loadConfiguration(String fileName) { + try { + InputStream inputStream = getInputStream(fileName); + Constructor constructor = new Constructor(CloudLoggingConfig.class); + TypeDescription listDescription = new TypeDescription(CloudLoggingConfig.class); + listDescription.putListPropertyType("loggers", LoggerConfig.class); + constructor.addTypeDescription(listDescription); + Yaml yaml = new Yaml(constructor); + CloudLoggingConfig cloudLoggingConfig = yaml.loadAs(inputStream, CloudLoggingConfig.class); + for (LoggerConfig config : cloudLoggingConfig.getLoggers()) { + loggerConfigs.put(config.getName(), config); + } + destination = cloudLoggingConfig.getDestination(); + } catch (Exception e) { + System.err.println( + "Error loading configuration from " + fileName + ":" + e.getLocalizedMessage()); + } + } + + private InputStream getInputStream(String fileName) { + InputStream inputStream = null; + try { + inputStream = new FileInputStream(fileName); + } catch (IOException e) { + System.err.println( + "Error loading configuration from " + fileName + ":" + e.getLocalizedMessage()); + } + return inputStream; + } + + private LoggerConfig getLoggerConfig(String loggerName) { + LoggerConfig config = loggerConfigs.get(loggerName); + int packageDelimiter; + while (config == null) { + packageDelimiter = loggerName.lastIndexOf('.'); + if (packageDelimiter > 0 && packageDelimiter < loggerName.length() - 1) { + loggerName = loggerName.substring(0, packageDelimiter); + config = loggerConfigs.get(loggerName); + } else { + break; + } + } + return (config != null) ? config : loggerConfigs.get(DEFAULT_LOGGER_NAME); + } + + public Map getLabels(String loggerName) { + LoggerConfig config = getLoggerConfig(loggerName); + return (config != null) ? config.getLabels() : null; + } + + public String getFileName(String loggerName) { + LoggerConfig config = getLoggerConfig(loggerName); + return (config != null && config.getLog_name() != null) + ? config.getLog_name() + : getResource(loggerName); + } + + public Severity getSeverity(String loggerName) { + LoggerConfig config = getLoggerConfig(loggerName); + return (config != null && config.getLevel() != null) + ? Severity.valueOf(config.getLevel().toUpperCase()) + : ConfigDefaults.severity; + } + + public String getResource(String loggerName) { + LoggerConfig config = getLoggerConfig(loggerName); + return (config != null && config.getResource() != null) ? config.getResource() : loggerName; + } + + public boolean isEnabled(String loggerName) { + LoggerConfig config = getLoggerConfig(loggerName); + return (config != null) ? config.isEnable() : ConfigDefaults.enable; + } + + public String getDestination() { + return (destination != null) ? destination : ConfigDefaults.destination; + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/LoggerConfig.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/LoggerConfig.java new file mode 100644 index 000000000000..d46f93517545 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/config/LoggerConfig.java @@ -0,0 +1,83 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl.config; + +import java.util.Map; + +public class LoggerConfig { + + private String name; + private String resource; + private Map labels; + private String log_name; + private String level; + private Boolean enable; + + public LoggerConfig() {} + + public LoggerConfig(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getResource() { + return (resource != null) ? resource : ConfigDefaults.resource; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public Map getLabels() { + return labels; + } + + public void setLabels(Map labels) { + this.labels = labels; + } + + public String getLog_name() { + return (log_name != null) ? log_name : name; + } + + public void setLog_name(String log_name) { + this.log_name = log_name; + } + + public String getLevel() { + return (level != null) ? level : ConfigDefaults.severity.name(); + } + + public void setLevel(String level) { + this.level = level; + } + + public Boolean isEnable() { + return (enable != null) ? enable : ConfigDefaults.enable; + } + + public void setEnable(Boolean enable) { + this.enable = enable; + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/CloudLogging.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/CloudLogging.java new file mode 100644 index 000000000000..7f292561d442 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/CloudLogging.java @@ -0,0 +1,50 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl.logging; + +import com.google.cloud.logging.LogEntry; +import com.google.cloud.logging.Logging; +import com.google.cloud.logging.LoggingOptions; +import java.util.List; + +public class CloudLogging implements ILogging { + + private Logging logging; + + @Override + public void init() { + logging = LoggingOptions.getDefaultInstance().getService(); + Runtime.getRuntime().addShutdownHook(new ShutdownService()); + } + + @Override + public void write(List logEntries) { + logging.writeAsync(logEntries); + } + + class ShutdownService extends Thread { + + @Override + public void run() { + try { + logging.close(); + } catch (Exception e) { + System.err.println("Error closing cloud logger : " + e.getMessage()); + } + } + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/FluentdLogging.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/FluentdLogging.java new file mode 100644 index 000000000000..e416c357ba1d --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/FluentdLogging.java @@ -0,0 +1,79 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl.logging; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.cloud.logging.LogEntry; +import java.io.IOException; +import java.net.Socket; +import java.util.List; + +public class FluentdLogging implements ILogging { + + private static final String DEFAULT_HOST_NAME = "localhost"; + private static int DEFAULT_PORT = 24224; + private final String hostName; + private final int port; + private Socket socket; + private ObjectMapper objectMapper; + + public FluentdLogging() { + this.hostName = DEFAULT_HOST_NAME; + this.port = DEFAULT_PORT; + } + + public void init() { + try { + socket = new Socket(hostName, port); + } catch (IOException e) { + System.err.println("Error opening port : " + e.getMessage()); + } + Runtime.getRuntime().addShutdownHook(new ShutdownService(socket)); + } + + public void write(List logEntries) { + try { + String log = objectMapper.writeValueAsString(logEntries); + socket.getOutputStream().write(log.getBytes()); + } catch (JsonProcessingException e) { + System.err.println("Error processing json : " + e.getMessage()); + } catch (IOException e) { + System.err.println("Error connecting to socket : " + e.getMessage()); + System.out.println("Reconnecting..."); + init(); + } + } + + class ShutdownService extends Thread { + + Socket socket; + + ShutdownService(Socket socket) { + this.socket = socket; + } + + @Override + public void run() { + try { + socket.close(); + } catch (Exception e) { + System.err.println("Error closing cloud logger : " + e.getMessage()); + } + } + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/ILogging.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/ILogging.java new file mode 100644 index 000000000000..ec529fa42d27 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/ILogging.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl.logging; + +import com.google.cloud.logging.LogEntry; +import java.util.List; + +public interface ILogging { + + void init(); + + void write(List logEntries); +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/ILoggingFactory.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/ILoggingFactory.java new file mode 100644 index 000000000000..114941f9cf1a --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/ILoggingFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl.logging; + +public class ILoggingFactory { + + public static ILogging get(String type) { + switch (type) { + case "fluentd": + return new FluentdLogging(); + case "stdout": + return new StdoutLogging(); + case "default": + default: + return new CloudLogging(); + } + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/StdoutLogging.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/StdoutLogging.java new file mode 100644 index 000000000000..09f28b027072 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/main/java/org/slf4j/impl/logging/StdoutLogging.java @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl.logging; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.cloud.logging.LogEntry; +import java.util.List; + +public class StdoutLogging implements ILogging { + + private ObjectMapper objectMapper; + + public StdoutLogging() { + objectMapper = new ObjectMapper(); + } + + @Override + public void init() {} + + @Override + public void write(List logEntries) { + try { + System.out.println(objectMapper.writeValueAsString(logEntries)); + } catch (JsonProcessingException e) { + System.err.println(); + } + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/test/java/org/slf4j/impl/ConfigLoaderTest.java b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/test/java/org/slf4j/impl/ConfigLoaderTest.java new file mode 100644 index 000000000000..878542f4e46f --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/test/java/org/slf4j/impl/ConfigLoaderTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.slf4j.impl; + +import com.google.cloud.logging.Severity; +import java.io.File; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.impl.config.ConfigLoader; + +public class ConfigLoaderTest { + + private static final String cloudLoggingConfigProperty = "CLOUD_LOGGING_CONFIG"; + private String cloudLoggingConfigOldValue; + + @Before + public void startUp() { + ClassLoader classLoader = getClass().getClassLoader(); + cloudLoggingConfigOldValue = System.getProperty(cloudLoggingConfigProperty); + File file = new File(classLoader.getResource("google-cloud-logging.yaml").getFile()); + System.setProperty(cloudLoggingConfigProperty, file.getAbsolutePath()); + } + + @Test + public void configurationHasDefaults() { + ConfigLoader configLoader = new ConfigLoader(null); + Assert.assertEquals(configLoader.getFileName("test"), "default"); + Assert.assertEquals(configLoader.getResource("test"), "global"); + Assert.assertEquals(configLoader.getSeverity("test"), Severity.DEFAULT); + Assert.assertEquals(configLoader.getDestination(), "default"); + } + + @Test + public void configurationLoadsTheRightConfig() { + ConfigLoader configLoader = new ConfigLoader(System.getProperty(cloudLoggingConfigProperty)); + Assert.assertEquals(configLoader.getFileName("com.example.app"), "app.log"); + Assert.assertEquals(configLoader.getResource("com.example.app"), "global"); + Assert.assertEquals(configLoader.getSeverity("com.example.app"), Severity.DEBUG); + Assert.assertEquals(configLoader.isEnabled("com.example.app"), true); + Assert.assertEquals(configLoader.isEnabled("default"), false); + Assert.assertEquals(configLoader.getDestination(), "fluentd"); + } + + @Test + public void configurationLoadsPackageConfigAsFallback() { + ConfigLoader configLoader = new ConfigLoader(System.getProperty(cloudLoggingConfigProperty)); + Assert.assertEquals(configLoader.getFileName("com.example.app.new"), "app.log"); + Assert.assertEquals(configLoader.getResource("com.example.app.new"), "global"); + Assert.assertEquals(configLoader.getSeverity("com.example.app.new"), Severity.DEBUG); + Assert.assertEquals(configLoader.isEnabled("com.example.app.new"), true); + } + + @After + public void tearDown() { + if (cloudLoggingConfigOldValue == null) { + System.clearProperty(cloudLoggingConfigProperty); + } else { + System.setProperty(cloudLoggingConfigProperty, cloudLoggingConfigOldValue); + } + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/test/resources/google-cloud-logging.yaml b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/test/resources/google-cloud-logging.yaml new file mode 100644 index 000000000000..1c1c635e983a --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/cloud-logging-over-slf4j/src/test/resources/google-cloud-logging.yaml @@ -0,0 +1,25 @@ +destination: "fluentd" +loggers: +- name: "default" + enable: false +- name: "com.example.db" + resource: "global" + log_name: "db" + labels: + project_id: "$GOOGLE_CLOUD_PROJECT" + level: "info" +- name: "com.example.app" + resource: "global" + log_name: "app.log" + labels: + service_id: "$GOOGLE_CLOUD_PROJECT" + level: "debug" +- name: "com.example.app.experimental" + resource: "global" + log_name: "app.experimental" + labels: + instance_id: "$GAE_INSTANCE" + version_id: "$GAE_VERSION" + service_id: "$GAE_SERVICE" + feature_x: "$FEATURE_X_ENABLED" + level: "debug" diff --git a/google-cloud-contrib/google-cloud-logging-adapters/pom.xml b/google-cloud-contrib/google-cloud-logging-adapters/pom.xml new file mode 100644 index 000000000000..7de3ad3aba12 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + com.example + test-adapters + 0.1.0-SNAPSHOT + jar + + + cloud-logging-over-slf4j + + \ No newline at end of file diff --git a/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/pom.xml b/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/pom.xml new file mode 100644 index 000000000000..359734f03482 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + com.example + test-adapters + 0.1.0-SNAPSHOT + jar + + + + com.example + cloud-logging-over-slf4j + 0.1.0-SNAPSHOT + + + + + + maven-assembly-plugin + + + + com.example.app.TestSlf4jLoggerDirect + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + \ No newline at end of file diff --git a/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/java/com/example/app/TestSlf4JLoggerStdout.java b/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/java/com/example/app/TestSlf4JLoggerStdout.java new file mode 100644 index 000000000000..069064932bb2 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/java/com/example/app/TestSlf4JLoggerStdout.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.app; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MarkerFactory; + +public class TestSlf4JLoggerStdout { + private Logger logger = LoggerFactory.getLogger(TestSlf4jLoggerDirect.class); + + private void print() { + logger.info("Hello world : INFO"); + logger.info(MarkerFactory.getMarker("NOTICE"), "Hello world : INFO_NOTICE"); + logger.error(MarkerFactory.getMarker("CRITICAL"), "Hello world : Error"); + logger.info(MarkerFactory.getMarker("label1:value1"), "Hello world : labels"); + logger.error("Hello world : {}", "exception", new Throwable("illegal argument")); + logger.debug("Hello world : DEBUG"); + logger.trace("Hello world : TRACE"); + } + + public static void main(String[] args) { + System.setProperty( + "CLOUD_LOGGING_CONFIG", "src/main/resources/google-cloud-logging-stdout.yaml"); + TestSlf4JLoggerStdout testSlf4JLoggerStdout = new TestSlf4JLoggerStdout(); + testSlf4JLoggerStdout.print(); + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/java/com/example/app/TestSlf4jLoggerDirect.java b/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/java/com/example/app/TestSlf4jLoggerDirect.java new file mode 100644 index 000000000000..6159a81e3a88 --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/java/com/example/app/TestSlf4jLoggerDirect.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.app; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MarkerFactory; + +public class TestSlf4jLoggerDirect { + + private Logger logger = LoggerFactory.getLogger(TestSlf4jLoggerDirect.class); + + private void print() { + logger.info("Hello world : INFO"); + logger.info(MarkerFactory.getMarker("NOTICE"), "Hello world : INFO_NOTICE"); + logger.error(MarkerFactory.getMarker("CRITICAL"), "Hello world : Error"); + logger.info(MarkerFactory.getMarker("label1:value1"), "Hello world : labels"); + logger.error("Hello world : {}", "exception", new Throwable("illegal argument")); + logger.debug("Hello world : DEBUG"); + logger.trace("Hello world : TRACE"); + } + + public static void main(String[] args) { + System.setProperty("CLOUD_LOGGING_CONFIG", "src/main/resources/google-cloud-logging.yaml"); + TestSlf4jLoggerDirect testSlf4JLoggerDirect = new TestSlf4jLoggerDirect(); + testSlf4JLoggerDirect.print(); + } +} diff --git a/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/resources/google-cloud-logging-stdout.yaml b/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/resources/google-cloud-logging-stdout.yaml new file mode 100644 index 000000000000..018a662bffac --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/resources/google-cloud-logging-stdout.yaml @@ -0,0 +1,19 @@ +destination: "stdout" +loggers: +- name: "default" + enable: false +- name: "com.example.db" + resource: "global" + log_name: "db" + labels: + project_id: "$GOOGLE_CLOUD_PROJECT" + level: "info" +- name: "com.example.app" + log_name: "app_new" + level: "debug" +- name: "com.example.app.experimental" + resource: "gce_instance" + log_name: "app.experimental" + labels: + feature_x: "$FEATURE_X_ENABLED" + level: "debug" diff --git a/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/resources/google-cloud-logging.yaml b/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/resources/google-cloud-logging.yaml new file mode 100644 index 000000000000..e29e189990ab --- /dev/null +++ b/google-cloud-contrib/google-cloud-logging-adapters/test-adapters/src/main/resources/google-cloud-logging.yaml @@ -0,0 +1,19 @@ +loggers: +- name: "default" + enable: false +- name: "com.example.db" + resource: "global" + log_name: "db" + labels: + project_id: "$GOOGLE_CLOUD_PROJECT" + level: "info" +- name: "com.example.app" + log_name: "app" + resource: "gce_instance" + level: "debug" +- name: "com.example.app.experimental" + resource: "gce_instance" + log_name: "app.experimental" + labels: + feature_x: "$FEATURE_X_ENABLED" + level: "debug" diff --git a/google-cloud-contrib/pom.xml b/google-cloud-contrib/pom.xml index f35816e40114..0b3be9d38fd4 100644 --- a/google-cloud-contrib/pom.xml +++ b/google-cloud-contrib/pom.xml @@ -19,6 +19,7 @@ google-cloud-nio google-cloud-nio-examples + google-cloud-logging-adapters