LCOV - code coverage report
Current view: top level - server/logging - LoggingContextAwareRunnable.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 26 27 96.3 %
Date: 2022-11-19 15:00:39 Functions: 4 4 100.0 %

          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             : 
      20             : /**
      21             :  * Wrapper for a {@link Runnable} that copies the {@link LoggingContext} from the current thread to
      22             :  * the thread that executes the runnable.
      23             :  *
      24             :  * <p>The state of the logging context that is copied to the thread that executes the runnable is
      25             :  * fixed at the creation time of this wrapper. If the runnable is submitted to an executor and is
      26             :  * executed later this means that changes that are done to the logging context in between creating
      27             :  * and executing the runnable do not apply.
      28             :  *
      29             :  * <p>Example:
      30             :  *
      31             :  * <pre>{@code
      32             :  * try (TraceContext traceContext = TraceContext.newTrace(true, ...)) {
      33             :  *   executor
      34             :  *       .submit(new LoggingContextAwareRunnable(
      35             :  *           () -> {
      36             :  *             // Tracing is enabled since the runnable is created within the TraceContext.
      37             :  *             // Tracing is even enabled if the executor runs the runnable only after the
      38             :  *             // TraceContext was closed.
      39             :  *
      40             :  *             // The tag "foo=bar" is not set, since it was added to the logging context only
      41             :  *             // after this runnable was created.
      42             :  *
      43             :  *             // do stuff
      44             :  *           }))
      45             :  *       .get();
      46             :  *   traceContext.addTag("foo", "bar");
      47             :  * }
      48             :  * }</pre>
      49             :  *
      50             :  * @see LoggingContextAwareCallable
      51             :  */
      52             : public class LoggingContextAwareRunnable implements Runnable {
      53         148 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      54             : 
      55             :   private final Runnable runnable;
      56             :   private final Thread callingThread;
      57             :   private final ImmutableSetMultimap<String, String> tags;
      58             :   private final boolean forceLogging;
      59             :   private final boolean performanceLogging;
      60             :   private final MutablePerformanceLogRecords mutablePerformanceLogRecords;
      61             :   private final boolean aclLogging;
      62             :   private final MutableAclLogRecords mutableAclLogRecords;
      63             : 
      64             :   /**
      65             :    * Creates a LoggingContextAwareRunnable that wraps the given {@link Runnable}.
      66             :    *
      67             :    * @param runnable Runnable that should be wrapped.
      68             :    * @param mutablePerformanceLogRecords instance of {@link MutablePerformanceLogRecords} to which
      69             :    *     performance log records that are created from the runnable are added
      70             :    * @param mutableAclLogRecords instance of {@link MutableAclLogRecords} to which ACL log records
      71             :    *     that are created from the runnable are added
      72             :    */
      73             :   LoggingContextAwareRunnable(
      74             :       Runnable runnable,
      75             :       MutablePerformanceLogRecords mutablePerformanceLogRecords,
      76         148 :       MutableAclLogRecords mutableAclLogRecords) {
      77         148 :     this.runnable = runnable;
      78         148 :     this.callingThread = Thread.currentThread();
      79         148 :     this.tags = LoggingContext.getInstance().getTagsAsMap();
      80         148 :     this.forceLogging = LoggingContext.getInstance().isLoggingForced();
      81         148 :     this.performanceLogging = LoggingContext.getInstance().isPerformanceLogging();
      82         148 :     this.mutablePerformanceLogRecords = mutablePerformanceLogRecords;
      83         148 :     this.aclLogging = LoggingContext.getInstance().isAclLogging();
      84         148 :     this.mutableAclLogRecords = mutableAclLogRecords;
      85         148 :   }
      86             : 
      87             :   public Runnable unwrap() {
      88         146 :     return runnable;
      89             :   }
      90             : 
      91             :   @Override
      92             :   public void run() {
      93         148 :     if (callingThread.equals(Thread.currentThread())) {
      94             :       // propagation of logging context is not needed
      95          15 :       runnable.run();
      96          15 :       return;
      97             :     }
      98             : 
      99         148 :     LoggingContext loggingCtx = LoggingContext.getInstance();
     100             : 
     101         148 :     if (!loggingCtx.isEmpty()) {
     102           0 :       logger.atWarning().log("Logging context is not empty: %s", loggingCtx);
     103             :     }
     104             : 
     105             :     // propagate logging context
     106         148 :     loggingCtx.setTags(tags);
     107         148 :     loggingCtx.forceLogging(forceLogging);
     108         148 :     loggingCtx.performanceLogging(performanceLogging);
     109         148 :     loggingCtx.setMutablePerformanceLogRecords(mutablePerformanceLogRecords);
     110         148 :     loggingCtx.aclLogging(aclLogging);
     111         148 :     loggingCtx.setMutableAclLogRecords(mutableAclLogRecords);
     112             :     try {
     113         148 :       runnable.run();
     114             :     } finally {
     115             :       // Cleanup logging context. This is important if the thread is pooled and reused.
     116         148 :       loggingCtx.clear();
     117             :     }
     118         148 :   }
     119             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750