blob: 38b1882688d80b1531dfc6135c8a41c1a11bae49 [file] [log] [blame]
/*
* 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);
}
}