aboutsummaryrefslogtreecommitdiff
path: root/contrib/log_correlation
diff options
context:
space:
mode:
authorKristen Kozak <sebright@google.com>2018-05-25 01:02:27 -0700
committerKristen Kozak <sebright@google.com>2018-06-12 15:38:56 -0700
commitd34e4b2fb33eb26ea8cf88889682839579880bfb (patch)
treec7f970830254014bbe345f8486b6332102cff620 /contrib/log_correlation
parenta6e0485dd24b22779c0ca2d7b03b9c4a9da7a3ba (diff)
downloadopencensus-java-d34e4b2fb33eb26ea8cf88889682839579880bfb.tar.gz
Start adding log correlation for Stackdriver Logging.
Diffstat (limited to 'contrib/log_correlation')
-rw-r--r--contrib/log_correlation/stackdriver/README.md6
-rw-r--r--contrib/log_correlation/stackdriver/build.gradle10
-rw-r--r--contrib/log_correlation/stackdriver/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancer.java54
-rw-r--r--contrib/log_correlation/stackdriver/src/test/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancerTest.java135
-rw-r--r--contrib/log_correlation/stackdriver_demo/README.md9
-rw-r--r--contrib/log_correlation/stackdriver_demo/build.gradle36
-rw-r--r--contrib/log_correlation/stackdriver_demo/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/demo/OpenCensusTraceLoggingEnhancerDemo.java77
-rw-r--r--contrib/log_correlation/stackdriver_demo/src/main/resources/logback.xml16
8 files changed, 343 insertions, 0 deletions
diff --git a/contrib/log_correlation/stackdriver/README.md b/contrib/log_correlation/stackdriver/README.md
new file mode 100644
index 00000000..0b43d8c2
--- /dev/null
+++ b/contrib/log_correlation/stackdriver/README.md
@@ -0,0 +1,6 @@
+# OpenCensus Stackdriver Log Correlation
+
+This subproject is currently experimental. It provides a Stackdriver Logging LoggingEnhancer that
+automatically adds tracing data to log entries. The LoggingEnhancer adds the trace ID, which allows
+Stackdriver to display log entries associated with each trace or filter logs based on trace ID. It
+currently also adds the span ID and sampling decision.
diff --git a/contrib/log_correlation/stackdriver/build.gradle b/contrib/log_correlation/stackdriver/build.gradle
new file mode 100644
index 00000000..1b149ab7
--- /dev/null
+++ b/contrib/log_correlation/stackdriver/build.gradle
@@ -0,0 +1,10 @@
+description = 'OpenCensus Stackdriver Log Correlation'
+
+apply plugin: 'java'
+
+dependencies {
+ compile project(':opencensus-api'),
+ libraries.google_cloud_logging
+
+ signature "org.codehaus.mojo.signature:java16:+@signature"
+}
diff --git a/contrib/log_correlation/stackdriver/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancer.java b/contrib/log_correlation/stackdriver/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancer.java
new file mode 100644
index 00000000..a2ce3110
--- /dev/null
+++ b/contrib/log_correlation/stackdriver/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancer.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.logcorrelation.stackdriver;
+
+import com.google.cloud.ServiceOptions;
+import com.google.cloud.logging.LogEntry;
+import com.google.cloud.logging.LoggingEnhancer;
+import io.opencensus.common.ExperimentalApi;
+import io.opencensus.trace.SpanContext;
+import io.opencensus.trace.TraceId;
+import io.opencensus.trace.Tracer;
+import io.opencensus.trace.Tracing;
+
+/** Stackdriver {@link LoggingEnhancer} that adds OpenCensus tracing data to log entries. */
+@ExperimentalApi
+public final class OpenCensusTraceLoggingEnhancer implements LoggingEnhancer {
+ private static final String SPAN_ID_KEY = "span_id";
+ private static final String SAMPLED_KEY = "sampled";
+
+ private static final Tracer tracer = Tracing.getTracer();
+
+ /** Constructor to be called by Stackdriver logging. */
+ public OpenCensusTraceLoggingEnhancer() {}
+
+ @Override
+ public void enhanceLogEntry(LogEntry.Builder builder) {
+ SpanContext span = tracer.getCurrentSpan().getContext();
+ builder.setTrace(formatTraceId(span.getTraceId()));
+
+ // TODO(sebright): Find the correct way to add span ID and sampling decision.
+ builder.addLabel(SPAN_ID_KEY, span.getSpanId().toLowerBase16());
+ builder.addLabel(SAMPLED_KEY, Boolean.toString(span.getTraceOptions().isSampled()));
+ }
+
+ private static String formatTraceId(TraceId traceId) {
+ // TODO(sebright): Should we cache the project ID, for efficiency?
+ String projectId = ServiceOptions.getDefaultProjectId();
+ return "projects/" + projectId + "/traces/" + traceId.toLowerBase16();
+ }
+}
diff --git a/contrib/log_correlation/stackdriver/src/test/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancerTest.java b/contrib/log_correlation/stackdriver/src/test/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancerTest.java
new file mode 100644
index 00000000..7f399bb1
--- /dev/null
+++ b/contrib/log_correlation/stackdriver/src/test/java/io/opencensus/contrib/logcorrelation/stackdriver/OpenCensusTraceLoggingEnhancerTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.logcorrelation.stackdriver;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.cloud.logging.LogEntry;
+import io.opencensus.common.Scope;
+import io.opencensus.trace.Annotation;
+import io.opencensus.trace.AttributeValue;
+import io.opencensus.trace.BlankSpan;
+import io.opencensus.trace.EndSpanOptions;
+import io.opencensus.trace.Link;
+import io.opencensus.trace.Span;
+import io.opencensus.trace.SpanContext;
+import io.opencensus.trace.SpanId;
+import io.opencensus.trace.TraceId;
+import io.opencensus.trace.TraceOptions;
+import io.opencensus.trace.Tracer;
+import io.opencensus.trace.Tracing;
+import java.util.EnumSet;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for {@link OpenCensusTraceLoggingEnhancer}. */
+// TODO(sebright): Find a way to test that OpenCensusTraceLoggingEnhancer is called from Stackdriver
+// logging. See
+// https://github.com/GoogleCloudPlatform/google-cloud-java/blob/master/TESTING.md#testing-code-that-uses-logging.
+@RunWith(JUnit4.class)
+public class OpenCensusTraceLoggingEnhancerTest {
+ private static final String GOOGLE_CLOUD_PROJECT = "GOOGLE_CLOUD_PROJECT";
+
+ private static Tracer tracer = Tracing.getTracer();
+
+ @Test
+ public void enhanceLogEntry_Sampled() {
+ String projectId = "my-test-project-1";
+ String traceId = "4c9874d0b41224cce77ff74ee10f5ee6";
+ String spanId = "592ae363e92cb3dd";
+ boolean isSampled = true;
+ testLoggingEnhancer(projectId, traceId, spanId, isSampled);
+ }
+
+ @Test
+ public void enhanceLogEntry_NotSampled() {
+ String projectId = "my-test-project-2";
+ String traceId = "7f4703d9bb02f4f2e67fb840103cdd34";
+ String spanId = "2d7d95a555557434";
+ boolean isSampled = false;
+ testLoggingEnhancer(projectId, traceId, spanId, isSampled);
+ }
+
+ private static void testLoggingEnhancer(
+ String projectId, String traceId, String spanId, boolean isSampled) {
+ System.setProperty(GOOGLE_CLOUD_PROJECT, projectId);
+ try {
+ Scope scope =
+ tracer.withSpan(
+ new TestSpan(
+ SpanContext.create(
+ TraceId.fromLowerBase16(traceId),
+ SpanId.fromLowerBase16(spanId),
+ TraceOptions.builder().setIsSampled(isSampled).build())));
+ try {
+ LogEntry.Builder builder = LogEntry.newBuilder(null);
+ new OpenCensusTraceLoggingEnhancer().enhanceLogEntry(builder);
+ LogEntry logEntry = builder.build();
+ assertThat(logEntry.getLabels().get("span_id")).isEqualTo(spanId);
+ assertThat(logEntry.getLabels().get("sampled")).isEqualTo(isSampled ? "true" : "false");
+ assertThat(logEntry.getTrace()).isEqualTo("projects/" + projectId + "/traces/" + traceId);
+ } finally {
+ scope.close();
+ }
+ } finally {
+ System.clearProperty(GOOGLE_CLOUD_PROJECT);
+ }
+ }
+
+ // TODO(sebright): Should the OpenCensusTraceLoggingEnhancer avoid adding tracing data when the
+ // span is blank?
+ @Test
+ public void enhanceLogEntry_BlankSpan() {
+ System.setProperty(GOOGLE_CLOUD_PROJECT, "my-test-project-3");
+ try {
+ Scope scope = tracer.withSpan(BlankSpan.INSTANCE);
+ try {
+ LogEntry.Builder builder = LogEntry.newBuilder(null);
+ new OpenCensusTraceLoggingEnhancer().enhanceLogEntry(builder);
+ LogEntry logEntry = builder.build();
+ assertThat(logEntry.getLabels().get("span_id")).isEqualTo("0000000000000000");
+ assertThat(logEntry.getLabels().get("sampled")).isEqualTo("false");
+ assertThat(logEntry.getTrace())
+ .isEqualTo("projects/my-test-project-3/traces/00000000000000000000000000000000");
+ } finally {
+ scope.close();
+ }
+ } finally {
+ System.clearProperty(GOOGLE_CLOUD_PROJECT);
+ }
+ }
+
+ private static final class TestSpan extends Span {
+ TestSpan(SpanContext context) {
+ super(context, EnumSet.of(Options.RECORD_EVENTS));
+ }
+
+ @Override
+ public void end(EndSpanOptions options) {}
+
+ @Override
+ public void addLink(Link link) {}
+
+ @Override
+ public void addAnnotation(Annotation annotation) {}
+
+ @Override
+ public void addAnnotation(String description, Map<String, AttributeValue> attributes) {}
+ }
+}
diff --git a/contrib/log_correlation/stackdriver_demo/README.md b/contrib/log_correlation/stackdriver_demo/README.md
new file mode 100644
index 00000000..ba922e0c
--- /dev/null
+++ b/contrib/log_correlation/stackdriver_demo/README.md
@@ -0,0 +1,9 @@
+# OpenCensus Stackdriver Log Correlation Demo
+
+An application that demonstrates log correlation in Stackdriver, using
+`opencensus-contrib-log-correlation-stackdriver`. The application contains SLF4J log statements and
+OpenCensus tracing instrumentation. It configures logging with a Logback XML configuration and
+exports logs using the
+[Stackdriver Logging Logback appender](https://cloud.google.com/logging/docs/setup/java#logback_appender).
+It also exports traces using `opencensus-exporter-trace-stackdriver`, so that Stackdriver can show
+the log entries associated with each trace.
diff --git a/contrib/log_correlation/stackdriver_demo/build.gradle b/contrib/log_correlation/stackdriver_demo/build.gradle
new file mode 100644
index 00000000..ae6c9279
--- /dev/null
+++ b/contrib/log_correlation/stackdriver_demo/build.gradle
@@ -0,0 +1,36 @@
+description = 'OpenCensus Stackdriver Log Correlation Demo'
+
+apply plugin: 'java'
+
+[compileJava, compileTestJava].each() {
+ it.sourceCompatibility = 1.7
+ it.targetCompatibility = 1.7
+}
+
+dependencies {
+ compile project(':opencensus-api'),
+ project(':opencensus-contrib-log-correlation-stackdriver'),
+ project(':opencensus-exporter-trace-stackdriver'),
+ libraries.slf4j,
+ libraries.google_cloud_logging_logback
+
+ runtime project(':opencensus-impl-lite')
+
+ signature "org.codehaus.mojo.signature:java18:+@signature"
+}
+
+apply plugin: 'application'
+
+startScripts.enabled = false
+
+task openCensusLogCorrelationStackdriverDemo(type: CreateStartScripts) {
+ mainClassName = 'io.opencensus.contrib.logcorrelation.stackdriver.demo.OpenCensusTraceLoggingEnhancerDemo'
+ applicationName = 'OpenCensusTraceLoggingEnhancerDemo'
+ outputDir = new File(project.buildDir, 'tmp')
+ classpath = jar.outputs.files + project.configurations.runtime
+}
+
+applicationDistribution.into('bin') {
+ from(openCensusLogCorrelationStackdriverDemo)
+ fileMode = 0755
+}
diff --git a/contrib/log_correlation/stackdriver_demo/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/demo/OpenCensusTraceLoggingEnhancerDemo.java b/contrib/log_correlation/stackdriver_demo/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/demo/OpenCensusTraceLoggingEnhancerDemo.java
new file mode 100644
index 00000000..3b7bef5f
--- /dev/null
+++ b/contrib/log_correlation/stackdriver_demo/src/main/java/io/opencensus/contrib/logcorrelation/stackdriver/demo/OpenCensusTraceLoggingEnhancerDemo.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.logcorrelation.stackdriver.demo;
+
+import io.opencensus.common.Scope;
+import io.opencensus.contrib.logcorrelation.stackdriver.OpenCensusTraceLoggingEnhancer;
+import io.opencensus.exporter.trace.stackdriver.StackdriverTraceConfiguration;
+import io.opencensus.exporter.trace.stackdriver.StackdriverTraceExporter;
+import io.opencensus.trace.Sampler;
+import io.opencensus.trace.Tracer;
+import io.opencensus.trace.Tracing;
+import io.opencensus.trace.samplers.Samplers;
+import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Demo for {@link OpenCensusTraceLoggingEnhancer}. */
+public final class OpenCensusTraceLoggingEnhancerDemo {
+
+ // Use a high sampling probability to demonstrate tracing.
+ private static final Sampler SAMPLER = Samplers.probabilitySampler(0.7);
+
+ private static final Logger logger =
+ LoggerFactory.getLogger(OpenCensusTraceLoggingEnhancerDemo.class.getName());
+
+ private static final Tracer tracer = Tracing.getTracer();
+
+ private OpenCensusTraceLoggingEnhancerDemo() {}
+
+ /** Runs the demo. */
+ public static void main(String[] args) throws IOException {
+ StackdriverTraceExporter.createAndRegister(StackdriverTraceConfiguration.builder().build());
+ try (Scope scope = tracer.spanBuilder("Demo.Main").setSampler(SAMPLER).startScopedSpan()) {
+ pause();
+ logger.warn("parent span log message 1");
+ pause();
+ doWork();
+ pause();
+ logger.info("parent span log message 2");
+ pause();
+ }
+ Tracing.getExportComponent().shutdown();
+ }
+
+ private static void doWork() {
+ try (Scope scope = tracer.spanBuilder("Demo.DoWork").startScopedSpan()) {
+ pause();
+ logger.info("child span log message 1");
+ pause();
+ logger.error("child span log message 2");
+ pause();
+ }
+ }
+
+ /** Sleeps for 500 ms to spread out the events on the trace. */
+ private static void pause() {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+}
diff --git a/contrib/log_correlation/stackdriver_demo/src/main/resources/logback.xml b/contrib/log_correlation/stackdriver_demo/src/main/resources/logback.xml
new file mode 100644
index 00000000..3c16ed8a
--- /dev/null
+++ b/contrib/log_correlation/stackdriver_demo/src/main/resources/logback.xml
@@ -0,0 +1,16 @@
+<!-- This configuration file is based on the example at
+ https://github.com/GoogleCloudPlatform/google-cloud-java/tree/master/google-cloud-clients/google-cloud-contrib/google-cloud-logging-logback#usage -->
+<configuration>
+ <appender name="CLOUD" class="com.google.cloud.logging.logback.LoggingAppender">
+ <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+ <level>INFO</level>
+ </filter>
+ <log>application.log</log>
+ <enhancer>io.opencensus.contrib.logcorrelation.stackdriver.OpenCensusTraceLoggingEnhancer</enhancer>
+ <flushLevel>WARN</flushLevel>
+ </appender>
+
+ <root level="info">
+ <appender-ref ref="CLOUD" />
+ </root>
+</configuration>