Line data Source code
1 : // Copyright (C) 2018 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.logging; 16 : 17 : import com.google.common.collect.ImmutableSetMultimap; 18 : import com.google.common.flogger.FluentLogger; 19 : import java.util.concurrent.Callable; 20 : 21 : /** 22 : * Wrapper for a {@link Callable} that copies the {@link LoggingContext} from the current thread to 23 : * the thread that executes the callable. 24 : * 25 : * <p>The state of the logging context that is copied to the thread that executes the callable is 26 : * fixed at the creation time of this wrapper. If the callable is submitted to an executor and is 27 : * executed later this means that changes that are done to the logging context in between creating 28 : * and executing the callable do not apply. 29 : * 30 : * <p>See {@link LoggingContextAwareRunnable} for an example. 31 : * 32 : * @see LoggingContextAwareRunnable 33 : */ 34 : class LoggingContextAwareCallable<T> implements Callable<T> { 35 87 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 36 : 37 : private final Callable<T> callable; 38 : private final Thread callingThread; 39 : private final ImmutableSetMultimap<String, String> tags; 40 : private final boolean forceLogging; 41 : private final boolean performanceLogging; 42 : private final MutablePerformanceLogRecords mutablePerformanceLogRecords; 43 : private final boolean aclLogging; 44 : private final MutableAclLogRecords mutableAclLogRecords; 45 : 46 : /** 47 : * Creates a LoggingContextAwareCallable that wraps the given {@link Callable}. 48 : * 49 : * @param callable Callable that should be wrapped. 50 : * @param mutablePerformanceLogRecords instance of {@link MutablePerformanceLogRecords} to which 51 : * performance log records that are created from the runnable are added 52 : * @param mutableAclLogRecords instance of {@link MutableAclLogRecords} to which ACL log records 53 : * that are created from the runnable are added 54 : */ 55 : LoggingContextAwareCallable( 56 : Callable<T> callable, 57 : MutablePerformanceLogRecords mutablePerformanceLogRecords, 58 87 : MutableAclLogRecords mutableAclLogRecords) { 59 87 : this.callable = callable; 60 87 : this.callingThread = Thread.currentThread(); 61 87 : this.tags = LoggingContext.getInstance().getTagsAsMap(); 62 87 : this.forceLogging = LoggingContext.getInstance().isLoggingForced(); 63 87 : this.performanceLogging = LoggingContext.getInstance().isPerformanceLogging(); 64 87 : this.mutablePerformanceLogRecords = mutablePerformanceLogRecords; 65 87 : this.aclLogging = LoggingContext.getInstance().isAclLogging(); 66 87 : this.mutableAclLogRecords = mutableAclLogRecords; 67 87 : } 68 : 69 : @Override 70 : public T call() throws Exception { 71 87 : if (callingThread.equals(Thread.currentThread())) { 72 : // propagation of logging context is not needed 73 0 : return callable.call(); 74 : } 75 : 76 87 : LoggingContext loggingCtx = LoggingContext.getInstance(); 77 : 78 87 : if (!loggingCtx.isEmpty()) { 79 0 : logger.atWarning().log("Logging context is not empty: %s", loggingCtx); 80 : } 81 : 82 : // propagate logging context 83 87 : loggingCtx.setTags(tags); 84 87 : loggingCtx.forceLogging(forceLogging); 85 87 : loggingCtx.performanceLogging(performanceLogging); 86 87 : loggingCtx.setMutablePerformanceLogRecords(mutablePerformanceLogRecords); 87 87 : loggingCtx.aclLogging(aclLogging); 88 87 : loggingCtx.setMutableAclLogRecords(mutableAclLogRecords); 89 : try { 90 87 : return callable.call(); 91 : } finally { 92 : // Cleanup logging context. This is important if the thread is pooled and reused. 93 87 : loggingCtx.clear(); 94 : } 95 : } 96 : }