log_sink_set.cc 9.1 KB

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