rlogconnector.cpp 5.0 KB

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