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