diff options
16 files changed, 1217 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/.gitmodules diff --git a/all/build.gradle b/all/build.gradle index d46f2f61..83ffb69e 100644 --- a/all/build.gradle +++ b/all/build.gradle @@ -13,6 +13,7 @@ def subprojects = [ project(':opencensus-contrib-grpc-util'), project(':opencensus-contrib-grpc-metrics'), project(':opencensus-contrib-http-util'), + project(':opencensus-contrib-log-correlation-log4j2'), project(':opencensus-contrib-log-correlation-stackdriver'), project(':opencensus-contrib-monitored-resource-util'), project(':opencensus-contrib-spring'), @@ -39,6 +40,7 @@ def subprojects_javadoc = [ project(':opencensus-contrib-grpc-util'), project(':opencensus-contrib-grpc-metrics'), project(':opencensus-contrib-http-util'), + project(':opencensus-contrib-log-correlation-log4j2'), project(':opencensus-contrib-log-correlation-stackdriver'), project(':opencensus-contrib-monitored-resource-util'), project(':opencensus-contrib-spring'), diff --git a/build.gradle b/build.gradle index 07751679..dcb006ce 100644 --- a/build.gradle +++ b/build.gradle @@ -158,6 +158,7 @@ subprojects { googleAuthVersion = '0.11.0' googleCloudBetaVersion = '0.64.0-beta' googleCloudGaVersion = '1.46.0' + log4j2Version = '2.11.1' signalfxVersion = '0.0.39' springBootVersion = '1.5.15.RELEASE' springCloudVersion = '1.3.4.RELEASE' @@ -182,6 +183,7 @@ subprojects { google_auth: "com.google.auth:google-auth-library-credentials:${googleAuthVersion}", google_cloud_logging: "com.google.cloud:google-cloud-logging:${googleCloudGaVersion}", google_cloud_trace: "com.google.cloud:google-cloud-trace:${googleCloudBetaVersion}", + log4j2: "org.apache.logging.log4j:log4j-core:${log4j2Version}", zipkin_reporter: "io.zipkin.reporter2:zipkin-reporter:${zipkinReporterVersion}", zipkin_urlconnection: "io.zipkin.reporter2:zipkin-sender-urlconnection:${zipkinReporterVersion}", jaeger_reporter: "com.uber.jaeger:jaeger-core:${jaegerReporterVersion}", @@ -423,6 +425,7 @@ subprojects { 'opencensus-contrib-grpc-metrics', 'opencensus-contrib-grpc-util', 'opencensus-contrib-http-util', + 'opencensus-contrib-log-correlation-log4j2', 'opencensus-contrib-log-correlation-stackdriver', 'opencensus-contrib-monitored-resource-util', 'opencensus-contrib-spring', diff --git a/buildscripts/import-control.xml b/buildscripts/import-control.xml index 6dffe25a..d545878a 100644 --- a/buildscripts/import-control.xml +++ b/buildscripts/import-control.xml @@ -94,6 +94,12 @@ General guidelines on imports: <allow pkg="io.opencensus.tags"/> <allow pkg="io.opencensus.trace"/> </subpackage> + <subpackage name="logcorrelation.log4j2"> + <allow pkg="io.opencensus.contrib.logcorrelation.log4j2"/> + <allow pkg="io.opencensus.trace"/> + <disallow pkg="org.apache.logging.log4j.core.impl"/> + <allow pkg="org.apache.logging.log4j"/> + </subpackage> <subpackage name="logcorrelation.stackdriver"> <allow pkg="com.google.cloud"/> <allow pkg="io.opencensus.trace"/> diff --git a/checker-framework/stubs/log4j.astub b/checker-framework/stubs/log4j.astub new file mode 100644 index 00000000..20b3240e --- /dev/null +++ b/checker-framework/stubs/log4j.astub @@ -0,0 +1,8 @@ +import org.checkerframework.checker.nullness.qual.Nullable; + +package org.apache.logging.log4j; + +class ThreadContext { + @Nullable + static ReadOnlyThreadContextMap getThreadContextMap(); +} diff --git a/contrib/log_correlation/log4j2/README.md b/contrib/log_correlation/log4j2/README.md new file mode 100644 index 00000000..a5bf1449 --- /dev/null +++ b/contrib/log_correlation/log4j2/README.md @@ -0,0 +1,88 @@ +# OpenCensus Log4j 2 Log Correlation + +This subproject is currently experimental, so it may be redesigned or removed in the future. It +will remain experimental until we have a specification for a log correlation feature in +[opencensus-specs](https://github.com/census-instrumentation/opencensus-specs/) +(issue [#123](https://github.com/census-instrumentation/opencensus-specs/issues/123)). + +The `opencensus-contrib-log-correlation-log4j2` artifact provides a +[Log4j 2](https://logging.apache.org/log4j/2.x/) +[`ContextDataInjector`](https://logging.apache.org/log4j/2.x/manual/extending.html#Custom_ContextDataInjector) +that automatically adds tracing data to the context of Log4j +[`LogEvent`](https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html)s. +The class name is +`OpenCensusTraceContextDataInjector`. `OpenCensusTraceContextDataInjector` adds the current trace +ID, span ID, and sampling decision to each `LogEvent`, so that they can be accessed with +[`LogEvent.getContextData()`](https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getContextData()) +or included in a layout. + +See +https://github.com/census-ecosystem/opencensus-experiments/tree/master/java/log_correlation/log4j2 +for a demo that uses this library to correlate logs and traces in Stackdriver. + +## Instructions + +### Add the dependencies to your project + +For Maven add to your `pom.xml`: +```xml +<dependencies> + <dependency> + <groupId>io.opencensus</groupId> + <artifactId>opencensus-contrib-log-correlation-log4j2</artifactId> + <version>0.16.1</version> + <scope>runtime</scope> + </dependency> +</dependencies> +``` + +For Gradle add to your dependencies: +```groovy +runtime 'io.opencensus:opencensus-contrib-log-correlation-log4j2:0.16.1' +``` + +### Configure the `OpenCensusTraceContextDataInjector` + +#### Specify the `ContextDataInjector` override + +Override Log4j's default `ContextDataInjector` by setting the system property +`log4j2.contextDataInjector` to the full name of the class, +`io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector`. + +#### Choose when to add tracing data to log events + +The following system property controls the decision to add tracing data from the current span to a +log event: + +`io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector.spanSelection` + +The allowed values are: + +* `ALL_SPANS`: adds tracing data to all log events (default) + +* `NO_SPANS`: disables the log correlation feature + +* `SAMPLED_SPANS`: adds tracing data to log events when the current span is sampled + +### Add the tracing data to log entries + +`opencensus-contrib-log-correlation-log4j2` adds the following key-value pairs to the `LogEvent` +context: + +* `opencensusTraceId` - the lowercase base16 encoding of the current trace ID +* `opencensusSpanId` - the lowercase base16 encoding of the current span ID +* `opencensusTraceSampled` - the sampling decision of the current span ("true" or "false") + +These values can be accessed from layouts with +[Context Map Lookup](http://logging.apache.org/log4j/2.x/manual/lookups.html#ContextMapLookup). For +example, the trace ID can be accessed with `$${ctx:opencensusTraceId}`. The values can also be +accessed with the `X` conversion character in +[`PatternLayout`](http://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout), for +example, `%X{opencensusTraceId}`. + +See an example Log4j configuration file in the demo: +https://github.com/census-ecosystem/opencensus-experiments/tree/master/java/log_correlation/log4j2/src/main/resources/log4j2.xml + +### Java Versions + +Java 6 or above is required for using this artifact. diff --git a/contrib/log_correlation/log4j2/build.gradle b/contrib/log_correlation/log4j2/build.gradle new file mode 100644 index 00000000..4a4a6ebc --- /dev/null +++ b/contrib/log_correlation/log4j2/build.gradle @@ -0,0 +1,26 @@ +description = 'OpenCensus Log4j 2 Log Correlation' + +apply plugin: 'java' + +dependencies { + compile project(':opencensus-api'), + libraries.log4j2 + + testCompile libraries.guava + + signature "org.codehaus.mojo.signature:java16:+@signature" +} + +compileTestJava { + sourceCompatibility = "1.7" + targetCompatibility = "1.7" +} + +test { + systemProperties['log4j2.contextDataInjector'] = + 'io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector' + + // Each test class should run in a separate JVM. See the comment in + // AbstractOpenCensusLog4jLogCorrelationTest. + forkEvery = 1 +} diff --git a/contrib/log_correlation/log4j2/src/main/java/io/opencensus/contrib/logcorrelation/log4j2/ContextDataUtils.java b/contrib/log_correlation/log4j2/src/main/java/io/opencensus/contrib/logcorrelation/log4j2/ContextDataUtils.java new file mode 100644 index 00000000..dd32e448 --- /dev/null +++ b/contrib/log_correlation/log4j2/src/main/java/io/opencensus/contrib/logcorrelation/log4j2/ContextDataUtils.java @@ -0,0 +1,212 @@ +/* + * 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.log4j2; + +import io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector.SpanSelection; +import io.opencensus.trace.Span; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.unsafe.ContextUtils; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap; +import org.apache.logging.log4j.util.BiConsumer; +import org.apache.logging.log4j.util.ReadOnlyStringMap; +import org.apache.logging.log4j.util.SortedArrayStringMap; +import org.apache.logging.log4j.util.StringMap; +import org.apache.logging.log4j.util.TriConsumer; + +// Implementation of the methods inherited from ContextDataInjector. +// +// This class uses "shareable" to mean that a method's return value can be passed to another +// thread. +final class ContextDataUtils { + private ContextDataUtils() {} + + // The implementation of this method is based on the example in the Javadocs for + // ContextDataInjector.injectContextData. + static StringMap injectContextData( + SpanSelection spanSelection, @Nullable List<Property> properties, StringMap reusable) { + if (properties == null || properties.isEmpty()) { + return shareableRawContextData(spanSelection); + } + // Context data has precedence over configuration properties. + putProperties(properties, reusable); + // TODO(sebright): The following line can be optimized. See + // https://github.com/census-instrumentation/opencensus-java/pull/1422/files#r216425494. + reusable.putAll(nonShareableRawContextData(spanSelection)); + return reusable; + } + + private static void putProperties(Collection<Property> properties, StringMap stringMap) { + for (Property property : properties) { + stringMap.putValue(property.getName(), property.getValue()); + } + } + + private static StringMap shareableRawContextData(SpanSelection spanSelection) { + SpanContext spanContext = shouldAddTracingDataToLogEvent(spanSelection); + return spanContext == null + ? getShareableContextData() + : getShareableContextAndTracingData(spanContext); + } + + static ReadOnlyStringMap nonShareableRawContextData(SpanSelection spanSelection) { + SpanContext spanContext = shouldAddTracingDataToLogEvent(spanSelection); + return spanContext == null + ? getNonShareableContextData() + : getShareableContextAndTracingData(spanContext); + } + + // This method returns the current span context iff tracing data should be added to the LogEvent. + // It avoids getting the current span when the feature is disabled, for efficiency. + @Nullable + private static SpanContext shouldAddTracingDataToLogEvent(SpanSelection spanSelection) { + switch (spanSelection) { + case NO_SPANS: + return null; + case SAMPLED_SPANS: + SpanContext spanContext = getCurrentSpanContext(); + if (spanContext.getTraceOptions().isSampled()) { + return spanContext; + } else { + return null; + } + case ALL_SPANS: + return getCurrentSpanContext(); + } + throw new AssertionError("Unknown spanSelection: " + spanSelection); + } + + private static StringMap getShareableContextData() { + ReadOnlyThreadContextMap context = ThreadContext.getThreadContextMap(); + + // Return a new object, since StringMap is modifiable. + return context == null + ? new SortedArrayStringMap(ThreadContext.getImmutableContext()) + : new SortedArrayStringMap(context.getReadOnlyContextData()); + } + + private static ReadOnlyStringMap getNonShareableContextData() { + ReadOnlyThreadContextMap context = ThreadContext.getThreadContextMap(); + if (context != null) { + return context.getReadOnlyContextData(); + } else { + Map<String, String> contextMap = ThreadContext.getImmutableContext(); + return contextMap.isEmpty() + ? UnmodifiableReadOnlyStringMap.EMPTY + : new UnmodifiableReadOnlyStringMap(contextMap); + } + } + + private static StringMap getShareableContextAndTracingData(SpanContext spanContext) { + ReadOnlyThreadContextMap context = ThreadContext.getThreadContextMap(); + SortedArrayStringMap stringMap; + if (context == null) { + stringMap = new SortedArrayStringMap(ThreadContext.getImmutableContext()); + } else { + StringMap contextData = context.getReadOnlyContextData(); + stringMap = new SortedArrayStringMap(contextData.size() + 3); + stringMap.putAll(contextData); + } + // TODO(sebright): Move the calls to TraceId.toLowerBase16() and SpanId.toLowerBase16() out of + // the critical path by wrapping the trace and span IDs in objects that call toLowerBase16() in + // their toString() methods, after there is a fix for + // https://github.com/census-instrumentation/opencensus-java/issues/1436. + stringMap.putValue( + OpenCensusTraceContextDataInjector.TRACE_ID_CONTEXT_KEY, + spanContext.getTraceId().toLowerBase16()); + stringMap.putValue( + OpenCensusTraceContextDataInjector.SPAN_ID_CONTEXT_KEY, + spanContext.getSpanId().toLowerBase16()); + stringMap.putValue( + OpenCensusTraceContextDataInjector.TRACE_SAMPLED_CONTEXT_KEY, + spanContext.getTraceOptions().isSampled() ? "true" : "false"); + return stringMap; + } + + private static SpanContext getCurrentSpanContext() { + Span span = ContextUtils.CONTEXT_SPAN_KEY.get(); + return span == null ? SpanContext.INVALID : span.getContext(); + } + + @Immutable + private static final class UnmodifiableReadOnlyStringMap implements ReadOnlyStringMap { + private static final long serialVersionUID = 0L; + + static final ReadOnlyStringMap EMPTY = + new UnmodifiableReadOnlyStringMap(Collections.<String, String>emptyMap()); + + private final Map<String, String> map; + + UnmodifiableReadOnlyStringMap(Map<String, String> map) { + this.map = map; + } + + @Override + public boolean containsKey(String key) { + return map.containsKey(key); + } + + @Override + @SuppressWarnings("unchecked") + public <V> void forEach(BiConsumer<String, ? super V> action) { + for (Entry<String, String> entry : map.entrySet()) { + action.accept(entry.getKey(), (V) entry.getValue()); + } + } + + @Override + @SuppressWarnings("unchecked") + public <V, S> void forEach(TriConsumer<String, ? super V, S> action, S state) { + for (Entry<String, String> entry : map.entrySet()) { + action.accept(entry.getKey(), (V) entry.getValue(), state); + } + } + + @Override + @Nullable + @SuppressWarnings({ + "unchecked", + "TypeParameterUnusedInFormals" // This is an overridden method. + }) + public <V> V getValue(String key) { + return (V) map.get(key); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public Map<String, String> toMap() { + return map; + } + } +} diff --git a/contrib/log_correlation/log4j2/src/main/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusTraceContextDataInjector.java b/contrib/log_correlation/log4j2/src/main/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusTraceContextDataInjector.java new file mode 100644 index 00000000..38b18826 --- /dev/null +++ b/contrib/log_correlation/log4j2/src/main/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusTraceContextDataInjector.java @@ -0,0 +1,177 @@ +/* + * 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.log4j2; + +import io.opencensus.common.ExperimentalApi; +import java.util.List; +import javax.annotation.Nullable; +import org.apache.logging.log4j.core.ContextDataInjector; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.util.ReadOnlyStringMap; +import org.apache.logging.log4j.util.StringMap; + +/** + * A Log4j {@link ContextDataInjector} that adds OpenCensus tracing data to log events. + * + * <p>This class adds the following key-value pairs: + * + * <ul> + * <li>{@value #TRACE_ID_CONTEXT_KEY} - the lowercase base16 encoding of the current trace ID + * <li>{@value #SPAN_ID_CONTEXT_KEY} - the lowercase base16 encoding of the current span ID + * <li>{@value #TRACE_SAMPLED_CONTEXT_KEY} - the sampling decision of the current span ({@code + * "true"} or {@code "false"}) + * </ul> + * + * <p>The tracing data can be accessed with {@link LogEvent#getContextData} or included in a {@link + * Layout}. For example, the following patterns could be used to include the tracing data with a <a + * href="https://logging.apache.org/log4j/2.x/manual/layouts.html#Pattern_Layout">Pattern + * Layout</a>: + * + * <ul> + * <li><code>%X{opencensusTraceId}</code> + * <li><code>%X{opencensusSpanId}</code> + * <li><code>%X{opencensusTraceSampled}</code> + * </ul> + * + * <p>This feature is currently experimental. + * + * @since 0.16 + * @see <a + * href="https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/ContextDataInjector.html">org.apache.logging.log4j.core.ContextDataInjector</a> + */ +@ExperimentalApi +public final class OpenCensusTraceContextDataInjector implements ContextDataInjector { + private static final SpanSelection DEFAULT_SPAN_SELECTION = SpanSelection.ALL_SPANS; + + /** + * Context key for the current trace ID. The name is {@value}. + * + * @since 0.16 + */ + public static final String TRACE_ID_CONTEXT_KEY = "opencensusTraceId"; + + /** + * Context key for the current span ID. The name is {@value}. + * + * @since 0.16 + */ + public static final String SPAN_ID_CONTEXT_KEY = "opencensusSpanId"; + + /** + * Context key for the sampling decision of the current span. The name is {@value}. + * + * @since 0.16 + */ + public static final String TRACE_SAMPLED_CONTEXT_KEY = "opencensusTraceSampled"; + + /** + * Name of the property that defines the {@link SpanSelection}. The name is {@value}. + * + * @since 0.16 + */ + public static final String SPAN_SELECTION_PROPERTY_NAME = + "io.opencensus.contrib.logcorrelation.log4j2." + + "OpenCensusTraceContextDataInjector.spanSelection"; + + private final SpanSelection spanSelection; + + /** + * How to decide whether to add tracing data from the current span to a log entry. + * + * @since 0.16 + */ + public enum SpanSelection { + + /** + * Never add tracing data to log entries. This constant disables the log correlation feature. + * + * @since 0.16 + */ + NO_SPANS, + + /** + * Add tracing data to a log entry iff the current span is sampled. + * + * @since 0.16 + */ + SAMPLED_SPANS, + + /** + * Always add tracing data to log entries, even when the current span is not sampled. This is + * the default. + * + * @since 0.16 + */ + ALL_SPANS + } + + /** + * Returns the {@code SpanSelection} setting for this instance. + * + * @return the {@code SpanSelection} setting for this instance. + * @since 0.16 + */ + public SpanSelection getSpanSelection() { + return spanSelection; + } + + /** + * Constructor to be called by Log4j. + * + * <p>This constructor looks up the {@link SpanSelection} using the system property {@link + * #SPAN_SELECTION_PROPERTY_NAME}. + * + * @since 0.16 + */ + public OpenCensusTraceContextDataInjector() { + this(lookUpSpanSelectionProperty()); + } + + // visible for testing + OpenCensusTraceContextDataInjector(SpanSelection spanSelection) { + this.spanSelection = spanSelection; + } + + private static SpanSelection lookUpSpanSelectionProperty() { + String spanSelectionProperty = System.getProperty(SPAN_SELECTION_PROPERTY_NAME); + return spanSelectionProperty == null || spanSelectionProperty.isEmpty() + ? DEFAULT_SPAN_SELECTION + : parseSpanSelection(spanSelectionProperty); + } + + private static SpanSelection parseSpanSelection(String spanSelection) { + try { + return SpanSelection.valueOf(spanSelection); + } catch (IllegalArgumentException e) { + return DEFAULT_SPAN_SELECTION; + } + } + + // Note that this method must return an object that can be passed to another thread. + @Override + public StringMap injectContextData(@Nullable List<Property> properties, StringMap reusable) { + return ContextDataUtils.injectContextData(spanSelection, properties, reusable); + } + + // Note that this method does not need to return an object that can be passed to another thread. + @Override + public ReadOnlyStringMap rawContextData() { + return ContextDataUtils.nonShareableRawContextData(spanSelection); + } +} diff --git a/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/AbstractOpenCensusLog4jLogCorrelationTest.java b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/AbstractOpenCensusLog4jLogCorrelationTest.java new file mode 100644 index 00000000..93ad85e0 --- /dev/null +++ b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/AbstractOpenCensusLog4jLogCorrelationTest.java @@ -0,0 +1,97 @@ +/* + * 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.log4j2; + +import io.opencensus.common.Function; +import io.opencensus.common.Scope; +import io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector.SpanSelection; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.Tracer; +import io.opencensus.trace.Tracestate; +import io.opencensus.trace.Tracing; +import java.io.StringWriter; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.StringLayout; +import org.apache.logging.log4j.core.appender.WriterAppender; +import org.apache.logging.log4j.core.layout.PatternLayout; + +/** + * Superclass for all Log4j log correlation test classes. + * + * <p>The tests are split into multiple classes so that each one can be run with a different value + * for the system property {@link OpenCensusTraceContextDataInjector#SPAN_SELECTION_PROPERTY_NAME}. + * The property must be set when Log4j initializes a static variable, and running each test class in + * a separate JVM causes the static variable to be reinitialized. + */ +abstract class AbstractOpenCensusLog4jLogCorrelationTest { + private static final Tracer tracer = Tracing.getTracer(); + + static final String TEST_PATTERN = + "traceId=%X{opencensusTraceId} spanId=%X{opencensusSpanId} " + + "sampled=%X{opencensusTraceSampled} %-5level - %msg"; + + static final Tracestate EMPTY_TRACESTATE = Tracestate.builder().build(); + + private static Logger logger; + + // This method initializes Log4j after setting the SpanSelection, which means that Log4j + // initializes a static variable with a ContextDataInjector that is constructed with the proper + // SpanSelection. This method should be called from a @BeforeClass method in each subclass. + static void initializeLog4j(SpanSelection spanSelection) { + System.setProperty( + OpenCensusTraceContextDataInjector.SPAN_SELECTION_PROPERTY_NAME, spanSelection.toString()); + logger = (Logger) LogManager.getLogger(AbstractOpenCensusLog4jLogCorrelationTest.class); + } + + // Reconfigures Log4j using the given arguments and runs the function with the given SpanContext + // in scope. + String logWithSpanAndLog4jConfiguration( + String log4jPattern, SpanContext spanContext, Function<Logger, Void> loggingFunction) { + StringWriter output = new StringWriter(); + StringLayout layout = PatternLayout.newBuilder().withPattern(log4jPattern).build(); + Appender appender = + WriterAppender.newBuilder() + .setTarget(output) + .setLayout(layout) + .setName("TestAppender") + .build(); + ((LoggerContext) LogManager.getContext(false)).updateLoggers(); + appender.start(); + logger.addAppender(appender); + logger.setLevel(Level.ALL); + try { + logWithSpan(spanContext, loggingFunction, logger); + return output.toString(); + } finally { + logger.removeAppender(appender); + } + } + + private static void logWithSpan( + SpanContext spanContext, Function<Logger, Void> loggingFunction, Logger logger) { + Scope scope = tracer.withSpan(new TestSpan(spanContext)); + try { + loggingFunction.apply(logger); + } finally { + scope.close(); + } + } +} diff --git a/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusLog4jLogCorrelationAllSpansTest.java b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusLog4jLogCorrelationAllSpansTest.java new file mode 100644 index 00000000..355c9b67 --- /dev/null +++ b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusLog4jLogCorrelationAllSpansTest.java @@ -0,0 +1,167 @@ +/* + * 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.log4j2; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.common.Function; +import io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector.SpanSelection; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.TraceId; +import io.opencensus.trace.TraceOptions; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.Logger; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for Log4j log correlation with {@link + * OpenCensusTraceContextDataInjector#SPAN_SELECTION_PROPERTY_NAME} set to {@link + * SpanSelection#ALL_SPANS}. + */ +@RunWith(JUnit4.class) +public final class OpenCensusLog4jLogCorrelationAllSpansTest + extends AbstractOpenCensusLog4jLogCorrelationTest { + + @BeforeClass + public static void setUp() { + initializeLog4j(SpanSelection.ALL_SPANS); + } + + @Test + public void addSampledSpanToLogEntryWithAllSpans() { + String log = + logWithSpanAndLog4jConfiguration( + TEST_PATTERN, + SpanContext.create( + TraceId.fromLowerBase16("b9718fe3d82d36fce0e6a1ada1c21db0"), + SpanId.fromLowerBase16("75159dde8c503fee"), + TraceOptions.builder().setIsSampled(true).build(), + EMPTY_TRACESTATE), + new Function<Logger, Void>() { + @Override + public Void apply(Logger logger) { + logger.warn("message #1"); + return null; + } + }); + assertThat(log) + .isEqualTo( + "traceId=b9718fe3d82d36fce0e6a1ada1c21db0 spanId=75159dde8c503fee " + + "sampled=true WARN - message #1"); + } + + @Test + public void addNonSampledSpanToLogEntryWithAllSpans() { + String log = + logWithSpanAndLog4jConfiguration( + TEST_PATTERN, + SpanContext.create( + TraceId.fromLowerBase16("cd7061dfa9d312cdcc42edab3feab51b"), + SpanId.fromLowerBase16("117d42d4c7acd066"), + TraceOptions.builder().setIsSampled(false).build(), + EMPTY_TRACESTATE), + new Function<Logger, Void>() { + @Override + public Void apply(Logger logger) { + logger.info("message #2"); + return null; + } + }); + assertThat(log) + .isEqualTo( + "traceId=cd7061dfa9d312cdcc42edab3feab51b spanId=117d42d4c7acd066 sampled=false INFO " + + "- message #2"); + } + + @Test + public void addBlankSpanToLogEntryWithAllSpans() { + String log = + logWithSpanAndLog4jConfiguration( + TEST_PATTERN, + SpanContext.INVALID, + new Function<Logger, Void>() { + @Override + public Void apply(Logger logger) { + logger.fatal("message #3"); + return null; + } + }); + assertThat(log) + .isEqualTo( + "traceId=00000000000000000000000000000000 spanId=0000000000000000 sampled=false FATAL " + + "- message #3"); + } + + @Test + public void preserveOtherKeyValuePairs() { + String log = + logWithSpanAndLog4jConfiguration( + "%X{opencensusTraceId} %X{myTestKey} %-5level - %msg", + SpanContext.create( + TraceId.fromLowerBase16("c95329bb6b7de41afbc51a231c128f97"), + SpanId.fromLowerBase16("bf22ea74d38eddad"), + TraceOptions.builder().setIsSampled(true).build(), + EMPTY_TRACESTATE), + new Function<Logger, Void>() { + @Override + public Void apply(Logger logger) { + String key = "myTestKey"; + ThreadContext.put(key, "myTestValue"); + try { + logger.error("message #4"); + } finally { + ThreadContext.remove(key); + } + return null; + } + }); + assertThat(log).isEqualTo("c95329bb6b7de41afbc51a231c128f97 myTestValue ERROR - message #4"); + } + + @Test + public void overwriteExistingTracingKey() { + String log = + logWithSpanAndLog4jConfiguration( + TEST_PATTERN, + SpanContext.create( + TraceId.fromLowerBase16("18e4ae44273a0c44e0c9ea4380792c66"), + SpanId.fromLowerBase16("199a7e16daa000a7"), + TraceOptions.builder().setIsSampled(true).build(), + EMPTY_TRACESTATE), + new Function<Logger, Void>() { + @Override + public Void apply(Logger logger) { + ThreadContext.put( + OpenCensusTraceContextDataInjector.TRACE_ID_CONTEXT_KEY, "existingTraceId"); + try { + logger.error("message #5"); + } finally { + ThreadContext.remove(OpenCensusTraceContextDataInjector.TRACE_ID_CONTEXT_KEY); + } + return null; + } + }); + assertThat(log) + .isEqualTo( + "traceId=18e4ae44273a0c44e0c9ea4380792c66 spanId=199a7e16daa000a7 " + + "sampled=true ERROR - message #5"); + } +} diff --git a/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusLog4jLogCorrelationNoSpansTest.java b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusLog4jLogCorrelationNoSpansTest.java new file mode 100644 index 00000000..1205924e --- /dev/null +++ b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusLog4jLogCorrelationNoSpansTest.java @@ -0,0 +1,86 @@ +/* + * 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.log4j2; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.common.Function; +import io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector.SpanSelection; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.TraceId; +import io.opencensus.trace.TraceOptions; +import org.apache.logging.log4j.core.Logger; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for Log4j log correlation with {@link + * OpenCensusTraceContextDataInjector#SPAN_SELECTION_PROPERTY_NAME} set to {@link + * SpanSelection#NO_SPANS}. + */ +@RunWith(JUnit4.class) +public final class OpenCensusLog4jLogCorrelationNoSpansTest + extends AbstractOpenCensusLog4jLogCorrelationTest { + + @BeforeClass + public static void setUp() { + initializeLog4j(SpanSelection.NO_SPANS); + } + + @Test + public void doNotAddSampledSpanToLogEntryWithNoSpans() { + String log = + logWithSpanAndLog4jConfiguration( + TEST_PATTERN, + SpanContext.create( + TraceId.fromLowerBase16("03d2ada98f6eb8330605a45a88c7e67d"), + SpanId.fromLowerBase16("ce5b1cf09fe58bcb"), + TraceOptions.builder().setIsSampled(true).build(), + EMPTY_TRACESTATE), + new Function<Logger, Void>() { + @Override + public Void apply(Logger logger) { + logger.trace("message #1"); + return null; + } + }); + assertThat(log).isEqualTo("traceId= spanId= sampled= TRACE - message #1"); + } + + @Test + public void doNotAddNonSampledSpanToLogEntryWithNoSpans() { + String log = + logWithSpanAndLog4jConfiguration( + TEST_PATTERN, + SpanContext.create( + TraceId.fromLowerBase16("09664283d189791de5218ffe3be88d54"), + SpanId.fromLowerBase16("a7203a50089a4029"), + TraceOptions.builder().setIsSampled(false).build(), + EMPTY_TRACESTATE), + new Function<Logger, Void>() { + @Override + public Void apply(Logger logger) { + logger.warn("message #2"); + return null; + } + }); + assertThat(log).isEqualTo("traceId= spanId= sampled= WARN - message #2"); + } +} diff --git a/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusLog4jLogCorrelationSampledSpansTest.java b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusLog4jLogCorrelationSampledSpansTest.java new file mode 100644 index 00000000..bbce4135 --- /dev/null +++ b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusLog4jLogCorrelationSampledSpansTest.java @@ -0,0 +1,89 @@ +/* + * 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.log4j2; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.common.Function; +import io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector.SpanSelection; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.TraceId; +import io.opencensus.trace.TraceOptions; +import org.apache.logging.log4j.core.Logger; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for Log4j log correlation with {@link + * OpenCensusTraceContextDataInjector#SPAN_SELECTION_PROPERTY_NAME} set to {@link + * SpanSelection#SAMPLED_SPANS}. + */ +@RunWith(JUnit4.class) +public final class OpenCensusLog4jLogCorrelationSampledSpansTest + extends AbstractOpenCensusLog4jLogCorrelationTest { + + @BeforeClass + public static void setUp() { + initializeLog4j(SpanSelection.SAMPLED_SPANS); + } + + @Test + public void addSampledSpanToLogEntryWithSampledSpans() { + String log = + logWithSpanAndLog4jConfiguration( + TEST_PATTERN, + SpanContext.create( + TraceId.fromLowerBase16("0af7a7bef890695f1c5e85a8e7290164"), + SpanId.fromLowerBase16("d3f07c467ec2fbb2"), + TraceOptions.builder().setIsSampled(true).build(), + EMPTY_TRACESTATE), + new Function<Logger, Void>() { + @Override + public Void apply(Logger logger) { + logger.error("message #1"); + return null; + } + }); + assertThat(log) + .isEqualTo( + "traceId=0af7a7bef890695f1c5e85a8e7290164 spanId=d3f07c467ec2fbb2 sampled=true ERROR " + + "- message #1"); + } + + @Test + public void doNotAddNonSampledSpanToLogEntryWithSampledSpans() { + String log = + logWithSpanAndLog4jConfiguration( + TEST_PATTERN, + SpanContext.create( + TraceId.fromLowerBase16("9e09b559ebb8f7f7ed7451aff68cf441"), + SpanId.fromLowerBase16("0fc9ef54c50a1816"), + TraceOptions.builder().setIsSampled(false).build(), + EMPTY_TRACESTATE), + new Function<Logger, Void>() { + @Override + public Void apply(Logger logger) { + logger.debug("message #2"); + return null; + } + }); + assertThat(log).isEqualTo("traceId= spanId= sampled= DEBUG - message #2"); + } +} diff --git a/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusTraceContextDataInjectorTest.java b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusTraceContextDataInjectorTest.java new file mode 100644 index 00000000..3b704058 --- /dev/null +++ b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/OpenCensusTraceContextDataInjectorTest.java @@ -0,0 +1,207 @@ +/* + * 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.log4j2; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.Lists; +import io.opencensus.common.Scope; +import io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector.SpanSelection; +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.Tracestate; +import io.opencensus.trace.Tracing; +import java.util.Collections; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.util.SortedArrayStringMap; +import org.apache.logging.log4j.util.StringMap; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link OpenCensusTraceContextDataInjector}. */ +@RunWith(JUnit4.class) +public final class OpenCensusTraceContextDataInjectorTest { + static final Tracestate EMPTY_TRACESTATE = Tracestate.builder().build(); + + private final Tracer tracer = Tracing.getTracer(); + + @Test + @SuppressWarnings("TruthConstantAsserts") + public void spanSelectionPropertyName() { + assertThat(OpenCensusTraceContextDataInjector.SPAN_SELECTION_PROPERTY_NAME) + .isEqualTo(OpenCensusTraceContextDataInjector.class.getName() + ".spanSelection"); + } + + @Test + public void traceIdKey() { + assertThat(OpenCensusTraceContextDataInjector.TRACE_ID_CONTEXT_KEY) + .isEqualTo("opencensusTraceId"); + } + + @Test + public void spanIdKey() { + assertThat(OpenCensusTraceContextDataInjector.SPAN_ID_CONTEXT_KEY) + .isEqualTo("opencensusSpanId"); + } + + @Test + public void traceSampledKey() { + assertThat(OpenCensusTraceContextDataInjector.TRACE_SAMPLED_CONTEXT_KEY) + .isEqualTo("opencensusTraceSampled"); + } + + @Test + public void spanSelectionDefaultIsAllSpans() { + assertThat(new OpenCensusTraceContextDataInjector().getSpanSelection()) + .isEqualTo(SpanSelection.ALL_SPANS); + } + + @Test + public void setSpanSelectionWithSystemProperty() { + try { + System.setProperty( + OpenCensusTraceContextDataInjector.SPAN_SELECTION_PROPERTY_NAME, "NO_SPANS"); + assertThat(new OpenCensusTraceContextDataInjector().getSpanSelection()) + .isEqualTo(SpanSelection.NO_SPANS); + } finally { + System.clearProperty(OpenCensusTraceContextDataInjector.SPAN_SELECTION_PROPERTY_NAME); + } + } + + @Test + public void useDefaultValueForInvalidSpanSelection() { + try { + System.setProperty( + OpenCensusTraceContextDataInjector.SPAN_SELECTION_PROPERTY_NAME, + "INVALID_SPAN_SELECTION"); + assertThat(new OpenCensusTraceContextDataInjector().getSpanSelection()) + .isEqualTo(SpanSelection.ALL_SPANS); + } finally { + System.clearProperty(OpenCensusTraceContextDataInjector.SPAN_SELECTION_PROPERTY_NAME); + } + } + + @Test + public void insertConfigurationProperties() { + assertThat( + new OpenCensusTraceContextDataInjector(SpanSelection.ALL_SPANS) + .injectContextData( + Lists.newArrayList( + Property.createProperty("property1", "value1"), + Property.createProperty("property2", "value2")), + new SortedArrayStringMap()) + .toMap()) + .containsExactly( + "property1", + "value1", + "property2", + "value2", + "opencensusTraceId", + "00000000000000000000000000000000", + "opencensusSpanId", + "0000000000000000", + "opencensusTraceSampled", + "false"); + } + + @Test + public void handleEmptyConfigurationProperties() { + assertContainsOnlyDefaultTracingEntries( + new OpenCensusTraceContextDataInjector(SpanSelection.ALL_SPANS) + .injectContextData(Collections.<Property>emptyList(), new SortedArrayStringMap())); + } + + @Test + public void handleNullConfigurationProperties() { + assertContainsOnlyDefaultTracingEntries( + new OpenCensusTraceContextDataInjector(SpanSelection.ALL_SPANS) + .injectContextData(null, new SortedArrayStringMap())); + } + + private static void assertContainsOnlyDefaultTracingEntries(StringMap stringMap) { + assertThat(stringMap.toMap()) + .containsExactly( + "opencensusTraceId", + "00000000000000000000000000000000", + "opencensusSpanId", + "0000000000000000", + "opencensusTraceSampled", + "false"); + } + + @Test + public void rawContextDataWithTracingData() { + OpenCensusTraceContextDataInjector plugin = + new OpenCensusTraceContextDataInjector(SpanSelection.ALL_SPANS); + SpanContext spanContext = + SpanContext.create( + TraceId.fromLowerBase16("e17944156660f55b8cae5ce3f45d4a40"), + SpanId.fromLowerBase16("fc3d2ba0d283b66a"), + TraceOptions.builder().setIsSampled(true).build(), + EMPTY_TRACESTATE); + Scope scope = tracer.withSpan(new TestSpan(spanContext)); + try { + String key = "myTestKey"; + ThreadContext.put(key, "myTestValue"); + try { + assertThat(plugin.rawContextData().toMap()) + .containsExactly( + "myTestKey", + "myTestValue", + "opencensusTraceId", + "e17944156660f55b8cae5ce3f45d4a40", + "opencensusSpanId", + "fc3d2ba0d283b66a", + "opencensusTraceSampled", + "true"); + } finally { + ThreadContext.remove(key); + } + } finally { + scope.close(); + } + } + + @Test + public void rawContextDataWithoutTracingData() { + OpenCensusTraceContextDataInjector plugin = + new OpenCensusTraceContextDataInjector(SpanSelection.NO_SPANS); + SpanContext spanContext = + SpanContext.create( + TraceId.fromLowerBase16("ea236000f6d387fe7c06c5a6d6458b53"), + SpanId.fromLowerBase16("f3b39dbbadb73074"), + TraceOptions.builder().setIsSampled(true).build(), + EMPTY_TRACESTATE); + Scope scope = tracer.withSpan(new TestSpan(spanContext)); + try { + String key = "myTestKey"; + ThreadContext.put(key, "myTestValue"); + try { + assertThat(plugin.rawContextData().toMap()).containsExactly("myTestKey", "myTestValue"); + } finally { + ThreadContext.remove(key); + } + } finally { + scope.close(); + } + } +} diff --git a/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/TestSpan.java b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/TestSpan.java new file mode 100644 index 00000000..7af46064 --- /dev/null +++ b/contrib/log_correlation/log4j2/src/test/java/io/opencensus/contrib/logcorrelation/log4j2/TestSpan.java @@ -0,0 +1,46 @@ +/* + * 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.log4j2; + +import io.opencensus.trace.Annotation; +import io.opencensus.trace.AttributeValue; +import io.opencensus.trace.EndSpanOptions; +import io.opencensus.trace.Link; +import io.opencensus.trace.Span; +import io.opencensus.trace.SpanContext; +import java.util.EnumSet; +import java.util.Map; + +// Simple test Span that holds a SpanContext. The tests cannot use Span directly, since it is +// abstract. +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/settings.gradle b/settings.gradle index 75060d26..7c224edf 100644 --- a/settings.gradle +++ b/settings.gradle @@ -21,6 +21,7 @@ include ":opencensus-contrib-exemplar-util" include ":opencensus-contrib-grpc-metrics" include ":opencensus-contrib-grpc-util" include ":opencensus-contrib-http-util" +include ":opencensus-contrib-log-correlation-log4j2" include ":opencensus-contrib-log-correlation-stackdriver" include ":opencensus-contrib-monitored-resource-util" include ":opencensus-contrib-spring" @@ -39,6 +40,8 @@ project(':opencensus-contrib-exemplar-util').projectDir = "$rootDir/contrib/exem project(':opencensus-contrib-grpc-metrics').projectDir = "$rootDir/contrib/grpc_metrics" as File project(':opencensus-contrib-grpc-util').projectDir = "$rootDir/contrib/grpc_util" as File project(':opencensus-contrib-http-util').projectDir = "$rootDir/contrib/http_util" as File +project(':opencensus-contrib-log-correlation-log4j2').projectDir = + "$rootDir/contrib/log_correlation/log4j2" as File project(':opencensus-contrib-log-correlation-stackdriver').projectDir = "$rootDir/contrib/log_correlation/stackdriver" as File project(':opencensus-contrib-monitored-resource-util').projectDir = |