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