tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

log_sink_set.cc (9363B)


      1 //
      2 // Copyright 2022 The Abseil 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 //      https://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 #include "absl/log/internal/log_sink_set.h"
     17 
     18 #ifndef ABSL_HAVE_THREAD_LOCAL
     19 #include <pthread.h>
     20 #endif
     21 
     22 #ifdef __ANDROID__
     23 #include <android/log.h>
     24 #endif
     25 
     26 #ifdef _WIN32
     27 #include <windows.h>
     28 #endif
     29 
     30 #include <algorithm>
     31 #include <vector>
     32 
     33 #include "absl/base/attributes.h"
     34 #include "absl/base/call_once.h"
     35 #include "absl/base/config.h"
     36 #include "absl/base/internal/raw_logging.h"
     37 #include "absl/base/log_severity.h"
     38 #include "absl/base/no_destructor.h"
     39 #include "absl/base/thread_annotations.h"
     40 #include "absl/cleanup/cleanup.h"
     41 #include "absl/log/globals.h"
     42 #include "absl/log/internal/config.h"
     43 #include "absl/log/internal/globals.h"
     44 #include "absl/log/log_entry.h"
     45 #include "absl/log/log_sink.h"
     46 #include "absl/strings/string_view.h"
     47 #include "absl/synchronization/mutex.h"
     48 #include "absl/types/span.h"
     49 
     50 namespace absl {
     51 ABSL_NAMESPACE_BEGIN
     52 namespace log_internal {
     53 namespace {
     54 
     55 // Returns a mutable reference to a thread-local variable that should be true if
     56 // a globally-registered `LogSink`'s `Send()` is currently being invoked on this
     57 // thread.
     58 bool& ThreadIsLoggingStatus() {
     59 #ifdef ABSL_HAVE_THREAD_LOCAL
     60  ABSL_CONST_INIT thread_local bool thread_is_logging = false;
     61  return thread_is_logging;
     62 #else
     63  ABSL_CONST_INIT static pthread_key_t thread_is_logging_key;
     64  static const bool unused = [] {
     65    if (pthread_key_create(&thread_is_logging_key, [](void* data) {
     66          delete reinterpret_cast<bool*>(data);
     67        })) {
     68      perror("pthread_key_create failed!");
     69      abort();
     70    }
     71    return true;
     72  }();
     73  (void)unused;  // Fixes -wunused-variable warning
     74  bool* thread_is_logging_ptr =
     75      reinterpret_cast<bool*>(pthread_getspecific(thread_is_logging_key));
     76 
     77  if (ABSL_PREDICT_FALSE(!thread_is_logging_ptr)) {
     78    thread_is_logging_ptr = new bool{false};
     79    if (pthread_setspecific(thread_is_logging_key, thread_is_logging_ptr)) {
     80      perror("pthread_setspecific failed");
     81      abort();
     82    }
     83  }
     84  return *thread_is_logging_ptr;
     85 #endif
     86 }
     87 
     88 class StderrLogSink final : public LogSink {
     89 public:
     90  ~StderrLogSink() override = default;
     91 
     92  void Send(const absl::LogEntry& entry) override {
     93    if (entry.log_severity() < absl::StderrThreshold() &&
     94        absl::log_internal::IsInitialized()) {
     95      return;
     96    }
     97 
     98    ABSL_CONST_INIT static absl::once_flag warn_if_not_initialized;
     99    absl::call_once(warn_if_not_initialized, []() {
    100      if (absl::log_internal::IsInitialized()) return;
    101      const char w[] =
    102          "WARNING: All log messages before absl::InitializeLog() is called"
    103          " are written to STDERR\n";
    104      absl::log_internal::WriteToStderr(w, absl::LogSeverity::kWarning);
    105    });
    106 
    107    if (!entry.stacktrace().empty()) {
    108      absl::log_internal::WriteToStderr(entry.stacktrace(),
    109                                        entry.log_severity());
    110    } else {
    111      // TODO(b/226937039): do this outside else condition once we avoid
    112      // ReprintFatalMessage
    113      absl::log_internal::WriteToStderr(
    114          entry.text_message_with_prefix_and_newline(), entry.log_severity());
    115    }
    116  }
    117 };
    118 
    119 #if defined(__ANDROID__)
    120 class AndroidLogSink final : public LogSink {
    121 public:
    122  ~AndroidLogSink() override = default;
    123 
    124  void Send(const absl::LogEntry& entry) override {
    125    const int level = AndroidLogLevel(entry);
    126    const char* const tag = GetAndroidNativeTag();
    127    __android_log_write(level, tag,
    128                        entry.text_message_with_prefix_and_newline_c_str());
    129    if (entry.log_severity() == absl::LogSeverity::kFatal)
    130      __android_log_write(ANDROID_LOG_FATAL, tag, "terminating.\n");
    131  }
    132 
    133 private:
    134  static int AndroidLogLevel(const absl::LogEntry& entry) {
    135    switch (entry.log_severity()) {
    136      case absl::LogSeverity::kFatal:
    137        return ANDROID_LOG_FATAL;
    138      case absl::LogSeverity::kError:
    139        return ANDROID_LOG_ERROR;
    140      case absl::LogSeverity::kWarning:
    141        return ANDROID_LOG_WARN;
    142      default:
    143        if (entry.verbosity() >= 2) return ANDROID_LOG_VERBOSE;
    144        if (entry.verbosity() == 1) return ANDROID_LOG_DEBUG;
    145        return ANDROID_LOG_INFO;
    146    }
    147  }
    148 };
    149 #endif  // !defined(__ANDROID__)
    150 
    151 #if defined(_WIN32)
    152 class WindowsDebuggerLogSink final : public LogSink {
    153 public:
    154  ~WindowsDebuggerLogSink() override = default;
    155 
    156  void Send(const absl::LogEntry& entry) override {
    157    if (entry.log_severity() < absl::StderrThreshold() &&
    158        absl::log_internal::IsInitialized()) {
    159      return;
    160    }
    161    ::OutputDebugStringA(entry.text_message_with_prefix_and_newline_c_str());
    162  }
    163 };
    164 #endif  // !defined(_WIN32)
    165 
    166 class GlobalLogSinkSet final {
    167 public:
    168  GlobalLogSinkSet() {
    169 #if defined(__myriad2__) || defined(__Fuchsia__)
    170    // myriad2 and Fuchsia do not log to stderr by default.
    171 #else
    172    static absl::NoDestructor<StderrLogSink> stderr_log_sink;
    173    AddLogSink(stderr_log_sink.get());
    174 #endif
    175 #ifdef __ANDROID__
    176    static absl::NoDestructor<AndroidLogSink> android_log_sink;
    177    AddLogSink(android_log_sink.get());
    178 #endif
    179 #if defined(_WIN32)
    180    static absl::NoDestructor<WindowsDebuggerLogSink> debugger_log_sink;
    181    AddLogSink(debugger_log_sink.get());
    182 #endif  // !defined(_WIN32)
    183  }
    184 
    185  void LogToSinks(const absl::LogEntry& entry,
    186                  absl::Span<absl::LogSink*> extra_sinks, bool extra_sinks_only)
    187      ABSL_LOCKS_EXCLUDED(guard_) {
    188    SendToSinks(entry, extra_sinks);
    189 
    190    if (!extra_sinks_only) {
    191      if (ThreadIsLoggingToLogSink()) {
    192        absl::log_internal::WriteToStderr(
    193            entry.text_message_with_prefix_and_newline(), entry.log_severity());
    194      } else {
    195        absl::ReaderMutexLock global_sinks_lock(&guard_);
    196        ThreadIsLoggingStatus() = true;
    197        // Ensure the "thread is logging" status is reverted upon leaving the
    198        // scope even in case of exceptions.
    199        auto status_cleanup =
    200            absl::MakeCleanup([] { ThreadIsLoggingStatus() = false; });
    201        SendToSinks(entry, absl::MakeSpan(sinks_));
    202      }
    203    }
    204  }
    205 
    206  void AddLogSink(absl::LogSink* sink) ABSL_LOCKS_EXCLUDED(guard_) {
    207    {
    208      absl::WriterMutexLock global_sinks_lock(&guard_);
    209      auto pos = std::find(sinks_.begin(), sinks_.end(), sink);
    210      if (pos == sinks_.end()) {
    211        sinks_.push_back(sink);
    212        return;
    213      }
    214    }
    215    ABSL_INTERNAL_LOG(FATAL, "Duplicate log sinks are not supported");
    216  }
    217 
    218  void RemoveLogSink(absl::LogSink* sink) ABSL_LOCKS_EXCLUDED(guard_) {
    219    {
    220      absl::WriterMutexLock global_sinks_lock(&guard_);
    221      auto pos = std::find(sinks_.begin(), sinks_.end(), sink);
    222      if (pos != sinks_.end()) {
    223        sinks_.erase(pos);
    224        return;
    225      }
    226    }
    227    ABSL_INTERNAL_LOG(FATAL, "Mismatched log sink being removed");
    228  }
    229 
    230  void FlushLogSinks() ABSL_LOCKS_EXCLUDED(guard_) {
    231    if (ThreadIsLoggingToLogSink()) {
    232      // The thread_local condition demonstrates that we're already holding the
    233      // lock in order to iterate over `sinks_` for dispatch.  The thread-safety
    234      // annotations don't know this, so we use `ABSL_NO_THREAD_SAFETY_ANALYSIS`
    235      guard_.AssertReaderHeld();
    236      FlushLogSinksLocked();
    237    } else {
    238      absl::ReaderMutexLock global_sinks_lock(&guard_);
    239      // In case if LogSink::Flush overload decides to log
    240      ThreadIsLoggingStatus() = true;
    241      // Ensure the "thread is logging" status is reverted upon leaving the
    242      // scope even in case of exceptions.
    243      auto status_cleanup =
    244          absl::MakeCleanup([] { ThreadIsLoggingStatus() = false; });
    245      FlushLogSinksLocked();
    246    }
    247  }
    248 
    249 private:
    250  void FlushLogSinksLocked() ABSL_SHARED_LOCKS_REQUIRED(guard_) {
    251    for (absl::LogSink* sink : sinks_) {
    252      sink->Flush();
    253    }
    254  }
    255 
    256  // Helper routine for LogToSinks.
    257  static void SendToSinks(const absl::LogEntry& entry,
    258                          absl::Span<absl::LogSink*> sinks) {
    259    for (absl::LogSink* sink : sinks) {
    260      sink->Send(entry);
    261    }
    262  }
    263 
    264  using LogSinksSet = std::vector<absl::LogSink*>;
    265  absl::Mutex guard_;
    266  LogSinksSet sinks_ ABSL_GUARDED_BY(guard_);
    267 };
    268 
    269 // Returns reference to the global LogSinks set.
    270 GlobalLogSinkSet& GlobalSinks() {
    271  static absl::NoDestructor<GlobalLogSinkSet> global_sinks;
    272  return *global_sinks;
    273 }
    274 
    275 }  // namespace
    276 
    277 bool ThreadIsLoggingToLogSink() { return ThreadIsLoggingStatus(); }
    278 
    279 void LogToSinks(const absl::LogEntry& entry,
    280                absl::Span<absl::LogSink*> extra_sinks, bool extra_sinks_only) {
    281  log_internal::GlobalSinks().LogToSinks(entry, extra_sinks, extra_sinks_only);
    282 }
    283 
    284 void AddLogSink(absl::LogSink* sink) {
    285  log_internal::GlobalSinks().AddLogSink(sink);
    286 }
    287 
    288 void RemoveLogSink(absl::LogSink* sink) {
    289  log_internal::GlobalSinks().RemoveLogSink(sink);
    290 }
    291 
    292 void FlushLogSinks() { log_internal::GlobalSinks().FlushLogSinks(); }
    293 
    294 }  // namespace log_internal
    295 ABSL_NAMESPACE_END
    296 }  // namespace absl