• 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.stackdriver;
18 
19 import com.google.cloud.ServiceOptions;
20 import com.google.cloud.logging.LogEntry;
21 import com.google.cloud.logging.LoggingEnhancer;
22 import io.opencensus.trace.Span;
23 import io.opencensus.trace.SpanContext;
24 import io.opencensus.trace.TraceId;
25 import io.opencensus.trace.unsafe.ContextHandleUtils;
26 import java.util.logging.LogManager;
27 import javax.annotation.Nullable;
28 
29 /**
30  * Stackdriver {@link LoggingEnhancer} that adds OpenCensus tracing data to log entries.
31  *
32  * @since 0.17
33  */
34 public final class OpenCensusTraceLoggingEnhancer implements LoggingEnhancer {
35 
36   /**
37    * Name of the property that overrides the default project ID (overrides the value returned by
38    * {@code com.google.cloud.ServiceOptions.getDefaultProjectId()}). The name is {@value}.
39    *
40    * @since 0.17
41    */
42   public static final String PROJECT_ID_PROPERTY_NAME =
43       "io.opencensus.contrib.logcorrelation.stackdriver.OpenCensusTraceLoggingEnhancer.projectId";
44 
45   @Nullable private final String projectId;
46 
47   // This field caches the prefix used for the LogEntry.trace field and is derived from projectId.
48   private final String tracePrefix;
49 
50   /**
51    * Constructor to be called by reflection, e.g., by a google-cloud-java {@code LoggingHandler} or
52    * google-cloud-logging-logback {@code LoggingAppender}.
53    *
54    * <p>This constructor looks up the project ID from the environment. It uses the default project
55    * ID (the value returned by {@code com.google.cloud.ServiceOptions.getDefaultProjectId()}),
56    * unless the ID is overridden by the property {@value #PROJECT_ID_PROPERTY_NAME}. The property
57    * can be specified with a {@link java.util.logging} property or a system property, with
58    * preference given to the logging property.
59    *
60    * @since 0.17
61    */
OpenCensusTraceLoggingEnhancer()62   public OpenCensusTraceLoggingEnhancer() {
63     this(lookUpProjectId());
64   }
65 
66   // visible for testing
OpenCensusTraceLoggingEnhancer(@ullable String projectId)67   OpenCensusTraceLoggingEnhancer(@Nullable String projectId) {
68     this.projectId = projectId;
69     this.tracePrefix = "projects/" + (projectId == null ? "" : projectId) + "/traces/";
70   }
71 
72   @Nullable
lookUpProjectId()73   private static String lookUpProjectId() {
74     String projectIdProperty = lookUpProperty(PROJECT_ID_PROPERTY_NAME);
75     return projectIdProperty == null || projectIdProperty.isEmpty()
76         ? ServiceOptions.getDefaultProjectId()
77         : projectIdProperty;
78   }
79 
80   // An OpenCensusTraceLoggingEnhancer property can be set with a logging property or a system
81   // property.
82   @Nullable
lookUpProperty(String name)83   private static String lookUpProperty(String name) {
84     String property = LogManager.getLogManager().getProperty(name);
85     return property == null || property.isEmpty() ? System.getProperty(name) : property;
86   }
87 
88   // visible for testing
89   @Nullable
getProjectId()90   String getProjectId() {
91     return projectId;
92   }
93 
94   // This method avoids getting the current span when the feature is disabled, for efficiency.
95   @Override
enhanceLogEntry(LogEntry.Builder builder)96   public void enhanceLogEntry(LogEntry.Builder builder) {
97     addTracingData(tracePrefix, getCurrentSpanContext(), builder);
98   }
99 
getCurrentSpanContext()100   private static SpanContext getCurrentSpanContext() {
101     Span span = ContextHandleUtils.getValue(ContextHandleUtils.currentContext());
102     return span == null ? SpanContext.INVALID : span.getContext();
103   }
104 
addTracingData( String tracePrefix, SpanContext span, LogEntry.Builder builder)105   private static void addTracingData(
106       String tracePrefix, SpanContext span, LogEntry.Builder builder) {
107     builder.setTrace(formatTraceId(tracePrefix, span.getTraceId()));
108     builder.setSpanId(span.getSpanId().toLowerBase16());
109     builder.setTraceSampled(span.getTraceOptions().isSampled());
110   }
111 
formatTraceId(String tracePrefix, TraceId traceId)112   private static String formatTraceId(String tracePrefix, TraceId traceId) {
113     return tracePrefix + traceId.toLowerBase16();
114   }
115 }
116