• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018, OpenCensus Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.opencensus.contrib.logcorrelation.log4j2;
18 
19 import io.opencensus.common.ExperimentalApi;
20 import java.util.List;
21 import javax.annotation.Nullable;
22 import org.apache.logging.log4j.core.ContextDataInjector;
23 import org.apache.logging.log4j.core.Layout;
24 import org.apache.logging.log4j.core.LogEvent;
25 import org.apache.logging.log4j.core.config.Property;
26 import org.apache.logging.log4j.util.ReadOnlyStringMap;
27 import org.apache.logging.log4j.util.StringMap;
28 
29 /**
30  * A Log4j {@link ContextDataInjector} that adds OpenCensus tracing data to log events.
31  *
32  * <p>This class adds the following key-value pairs:
33  *
34  * <ul>
35  *   <li>{@value #TRACE_ID_CONTEXT_KEY} - the lowercase base16 encoding of the current trace ID
36  *   <li>{@value #SPAN_ID_CONTEXT_KEY} - the lowercase base16 encoding of the current span ID
37  *   <li>{@value #TRACE_SAMPLED_CONTEXT_KEY} - the sampling decision of the current span ({@code
38  *       "true"} or {@code "false"})
39  * </ul>
40  *
41  * <p>The tracing data can be accessed with {@link LogEvent#getContextData} or included in a {@link
42  * Layout}. For example, the following patterns could be used to include the tracing data with a <a
43  * href="https://logging.apache.org/log4j/2.x/manual/layouts.html#Pattern_Layout">Pattern
44  * Layout</a>:
45  *
46  * <ul>
47  *   <li><code>%X{opencensusTraceId}</code>
48  *   <li><code>%X{opencensusSpanId}</code>
49  *   <li><code>%X{opencensusTraceSampled}</code>
50  * </ul>
51  *
52  * <p>This feature is currently experimental.
53  *
54  * @since 0.16
55  * @see <a
56  *     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>
57  */
58 @ExperimentalApi
59 public final class OpenCensusTraceContextDataInjector implements ContextDataInjector {
60   private static final SpanSelection DEFAULT_SPAN_SELECTION = SpanSelection.ALL_SPANS;
61 
62   /**
63    * Context key for the current trace ID. The name is {@value}.
64    *
65    * @since 0.16
66    */
67   public static final String TRACE_ID_CONTEXT_KEY = "opencensusTraceId";
68 
69   /**
70    * Context key for the current span ID. The name is {@value}.
71    *
72    * @since 0.16
73    */
74   public static final String SPAN_ID_CONTEXT_KEY = "opencensusSpanId";
75 
76   /**
77    * Context key for the sampling decision of the current span. The name is {@value}.
78    *
79    * @since 0.16
80    */
81   public static final String TRACE_SAMPLED_CONTEXT_KEY = "opencensusTraceSampled";
82 
83   /**
84    * Name of the property that defines the {@link SpanSelection}. The name is {@value}.
85    *
86    * @since 0.16
87    */
88   public static final String SPAN_SELECTION_PROPERTY_NAME =
89       "io.opencensus.contrib.logcorrelation.log4j2."
90           + "OpenCensusTraceContextDataInjector.spanSelection";
91 
92   private final SpanSelection spanSelection;
93 
94   /**
95    * How to decide whether to add tracing data from the current span to a log entry.
96    *
97    * @since 0.16
98    */
99   public enum SpanSelection {
100 
101     /**
102      * Never add tracing data to log entries. This constant disables the log correlation feature.
103      *
104      * @since 0.16
105      */
106     NO_SPANS,
107 
108     /**
109      * Add tracing data to a log entry iff the current span is sampled.
110      *
111      * @since 0.16
112      */
113     SAMPLED_SPANS,
114 
115     /**
116      * Always add tracing data to log entries, even when the current span is not sampled. This is
117      * the default.
118      *
119      * @since 0.16
120      */
121     ALL_SPANS
122   }
123 
124   /**
125    * Returns the {@code SpanSelection} setting for this instance.
126    *
127    * @return the {@code SpanSelection} setting for this instance.
128    * @since 0.16
129    */
getSpanSelection()130   public SpanSelection getSpanSelection() {
131     return spanSelection;
132   }
133 
134   /**
135    * Constructor to be called by Log4j.
136    *
137    * <p>This constructor looks up the {@link SpanSelection} using the system property {@link
138    * #SPAN_SELECTION_PROPERTY_NAME}.
139    *
140    * @since 0.16
141    */
OpenCensusTraceContextDataInjector()142   public OpenCensusTraceContextDataInjector() {
143     this(lookUpSpanSelectionProperty());
144   }
145 
146   // visible for testing
OpenCensusTraceContextDataInjector(SpanSelection spanSelection)147   OpenCensusTraceContextDataInjector(SpanSelection spanSelection) {
148     this.spanSelection = spanSelection;
149   }
150 
lookUpSpanSelectionProperty()151   private static SpanSelection lookUpSpanSelectionProperty() {
152     String spanSelectionProperty = System.getProperty(SPAN_SELECTION_PROPERTY_NAME);
153     return spanSelectionProperty == null || spanSelectionProperty.isEmpty()
154         ? DEFAULT_SPAN_SELECTION
155         : parseSpanSelection(spanSelectionProperty);
156   }
157 
parseSpanSelection(String spanSelection)158   private static SpanSelection parseSpanSelection(String spanSelection) {
159     try {
160       return SpanSelection.valueOf(spanSelection);
161     } catch (IllegalArgumentException e) {
162       return DEFAULT_SPAN_SELECTION;
163     }
164   }
165 
166   // Note that this method must return an object that can be passed to another thread.
167   @Override
injectContextData(@ullable List<Property> properties, StringMap reusable)168   public StringMap injectContextData(@Nullable List<Property> properties, StringMap reusable) {
169     return ContextDataUtils.injectContextData(spanSelection, properties, reusable);
170   }
171 
172   // Note that this method does not need to return an object that can be passed to another thread.
173   @Override
rawContextData()174   public ReadOnlyStringMap rawContextData() {
175     return ContextDataUtils.nonShareableRawContextData(spanSelection);
176   }
177 }
178