tor-browser

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

rlogconnector.cpp (5170B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 
      4 /* This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      6 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 /* Original author: bcampen@mozilla.com */
      9 
     10 #include "rlogconnector.h"
     11 
     12 #include <cstdarg>
     13 #include <deque>
     14 #include <string>
     15 #include <utility>  // Pinch hitting for <utility> and std::move
     16 #include <vector>
     17 
     18 #include "logging.h"
     19 #include "mozilla/Assertions.h"
     20 #include "mozilla/Mutex.h"
     21 #include "mozilla/Sprintf.h"
     22 
     23 extern "C" {
     24 #include <csi_platform.h>
     25 
     26 #include "r_log.h"
     27 #include "registry.h"
     28 }
     29 
     30 /* Matches r_dest_vlog type defined in r_log.h */
     31 static int ringbuffer_vlog(int facility, int level, const char* format,
     32                           va_list ap) {
     33  if (mozilla::RLogConnector::GetInstance()->ShouldLog(level)) {
     34    // I could be evil and printf right into a std::string, but unless this
     35    // shows up in profiling, it is not worth doing.
     36    char temp[4096];
     37    VsprintfLiteral(temp, format, ap);
     38 
     39    mozilla::RLogConnector::GetInstance()->Log(level, std::string(temp));
     40  }
     41  return 0;
     42 }
     43 
     44 static mozilla::LogLevel rLogLvlToMozLogLvl(int level) {
     45  switch (level) {
     46    case LOG_EMERG:
     47    case LOG_ALERT:
     48    case LOG_CRIT:
     49    case LOG_ERR:
     50      return mozilla::LogLevel::Error;
     51    case LOG_WARNING:
     52      return mozilla::LogLevel::Warning;
     53    case LOG_NOTICE:
     54      return mozilla::LogLevel::Info;
     55    case LOG_INFO:
     56      return mozilla::LogLevel::Debug;
     57    case LOG_DEBUG:
     58    default:
     59      return mozilla::LogLevel::Verbose;
     60  }
     61 }
     62 
     63 MOZ_MTLOG_MODULE("nicer");
     64 
     65 namespace mozilla {
     66 
     67 RLogConnector* RLogConnector::instance;
     68 
     69 RLogConnector::RLogConnector()
     70    : log_limit_(4096), mutex_("RLogConnector::mutex_"), disableCount_(0) {}
     71 
     72 RLogConnector::~RLogConnector() = default;
     73 
     74 void RLogConnector::SetLogLimit(uint32_t new_limit) {
     75  OffTheBooksMutexAutoLock lock(mutex_);
     76  log_limit_ = new_limit;
     77  RemoveOld();
     78 }
     79 
     80 bool RLogConnector::ShouldLog(int level) const {
     81  return level <= LOG_INFO ||
     82         MOZ_LOG_TEST(getLogModule(), rLogLvlToMozLogLvl(level));
     83 }
     84 
     85 void RLogConnector::Log(int level, std::string&& log) {
     86  MOZ_MTLOG(rLogLvlToMozLogLvl(level), log);
     87  OffTheBooksMutexAutoLock lock(mutex_);
     88  if (disableCount_ == 0) {
     89    AddMsg(std::move(log));
     90  }
     91 }
     92 
     93 void RLogConnector::AddMsg(std::string&& msg) {
     94  log_messages_.push_front(std::move(msg));
     95  RemoveOld();
     96 }
     97 
     98 inline void RLogConnector::RemoveOld() {
     99  if (log_messages_.size() > log_limit_) {
    100    log_messages_.resize(log_limit_);
    101  }
    102 }
    103 
    104 RLogConnector* RLogConnector::CreateInstance() {
    105  if (!instance) {
    106    instance = new RLogConnector;
    107    NR_reg_init();
    108    r_log_set_extra_destination(LOG_DEBUG, &ringbuffer_vlog);
    109  }
    110  return instance;
    111 }
    112 
    113 RLogConnector* RLogConnector::GetInstance() { return instance; }
    114 
    115 void RLogConnector::DestroyInstance() {
    116  // First param is ignored when passing null
    117  r_log_set_extra_destination(LOG_DEBUG, nullptr);
    118  delete instance;
    119  instance = nullptr;
    120 }
    121 
    122 // As long as at least one PeerConnection exists in a Private Window rlog
    123 // messages will not be saved in the RLogConnector. This is necessary because
    124 // the log_messages buffer is shared across all instances of
    125 // PeerConnectionImpls. There is no way with the current structure of r_log to
    126 // run separate logs.
    127 
    128 void RLogConnector::EnterPrivateMode() {
    129  OffTheBooksMutexAutoLock lock(mutex_);
    130  ++disableCount_;
    131  MOZ_ASSERT(disableCount_ != 0);
    132 
    133  if (disableCount_ == 1) {
    134    AddMsg("LOGGING SUSPENDED: a connection is active in a Private Window ***");
    135  }
    136 }
    137 
    138 void RLogConnector::ExitPrivateMode() {
    139  OffTheBooksMutexAutoLock lock(mutex_);
    140  MOZ_ASSERT(disableCount_ != 0);
    141 
    142  if (--disableCount_ == 0) {
    143    AddMsg(
    144        "LOGGING RESUMED: no connections are active in a Private Window ***");
    145  }
    146 }
    147 
    148 void RLogConnector::Clear() {
    149  OffTheBooksMutexAutoLock lock(mutex_);
    150  log_messages_.clear();
    151 }
    152 
    153 void RLogConnector::Filter(const std::string& substring, uint32_t limit,
    154                           std::deque<std::string>* matching_logs) {
    155  std::vector<std::string> substrings;
    156  substrings.push_back(substring);
    157  FilterAny(substrings, limit, matching_logs);
    158 }
    159 
    160 inline bool AnySubstringMatches(const std::vector<std::string>& substrings,
    161                                const std::string& string) {
    162  for (auto sub = substrings.begin(); sub != substrings.end(); ++sub) {
    163    if (string.find(*sub) != std::string::npos) {
    164      return true;
    165    }
    166  }
    167  return false;
    168 }
    169 
    170 void RLogConnector::FilterAny(const std::vector<std::string>& substrings,
    171                              uint32_t limit,
    172                              std::deque<std::string>* matching_logs) {
    173  OffTheBooksMutexAutoLock lock(mutex_);
    174  if (limit == 0) {
    175    // At a max, all of the log messages.
    176    limit = log_limit_;
    177  }
    178 
    179  for (auto log = log_messages_.begin();
    180       log != log_messages_.end() && matching_logs->size() < limit; ++log) {
    181    if (AnySubstringMatches(substrings, *log)) {
    182      matching_logs->push_front(*log);
    183    }
    184  }
    185 }
    186 
    187 }  // namespace mozilla