Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2951)

Unified Diff: base/logging.cc

Issue 2034393004: Allow multiple logging::LogMessage{Handler,Listener}s Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/logging.cc
diff --git a/base/logging.cc b/base/logging.cc
index 0771b47c182e5c18c868f1124a0784bf411d74a9..7caa9d9f5520fb5e05bce4e67c347fd51b7c1bb7 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -49,21 +49,25 @@ typedef pthread_mutex_t* MutexHandle;
#include <algorithm>
#include <cstring>
#include <ctime>
+#include <deque>
#include <iomanip>
#include <ostream>
#include <string>
+#include <unordered_set>
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/alias.h"
#include "base/debug/debugger.h"
#include "base/debug/stack_trace.h"
+#include "base/lazy_instance.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
#include "base/synchronization/lock_impl.h"
#include "base/threading/platform_thread.h"
#include "base/vlog.h"
@@ -123,8 +127,15 @@ bool show_error_dialogs = false;
// An assert handler override specified by the client to be called instead of
// the debug message dialog and process termination.
LogAssertHandlerFunction log_assert_handler = nullptr;
-// A log message handler that gets notified of every log message we process.
-LogMessageHandlerFunction log_message_handler = nullptr;
+// Log message handlers that get notified of every log message we process.
+base::LazyInstance<std::deque<LogMessageHandler*>>::Leaky
+ log_message_handlers = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::Lock>::Leaky log_message_handler_lock;
+// Log message listeners that get notified of every log message we process
+// before log message handlers.
+base::LazyInstance<std::unordered_set<LogMessageListener*>>::Leaky
+ log_message_listeners = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::Lock>::Leaky log_message_listener_lock;
// Helper functions to wrap platform differences.
@@ -342,6 +353,41 @@ void CloseLogFileUnlocked() {
} // namespace
+LogMessageHandler::LogMessageHandler() {
+ base::AutoLock lock(log_message_handler_lock.Get());
+ log_message_handlers.Get().push_front(this);
+}
+
+LogMessageHandler::~LogMessageHandler() {
+ base::AutoLock lock(log_message_handler_lock.Get());
+ auto& handlers = log_message_handlers.Get();
+ size_t count = handlers.size();
+ handlers.erase(std::remove(handlers.begin(), handlers.end(), this),
+ handlers.end());
+ DCHECK_EQ(count - 1, handlers.size());
+}
+
+size_t LogMessageHandlerCountForTesting() {
+ base::AutoLock lock(log_message_handler_lock.Get());
+ return log_message_handlers.Get().size();
+}
+
+LogMessageListener::LogMessageListener() {
+ base::AutoLock lock(log_message_listener_lock.Get());
+ log_message_listeners.Get().insert(this);
+}
+
+LogMessageListener::~LogMessageListener() {
+ base::AutoLock lock(log_message_listener_lock.Get());
+ size_t erased_count = log_message_listeners.Get().erase(this);
+ DCHECK_EQ(1u, erased_count);
+}
+
+size_t LogMessageListenerCountForTesting() {
+ base::AutoLock lock(log_message_listener_lock.Get());
+ return log_message_listeners.Get().size();
+}
+
LoggingSettings::LoggingSettings()
: logging_dest(LOG_DEFAULT),
log_file(nullptr),
@@ -409,7 +455,9 @@ bool ShouldCreateLogMessage(int severity) {
// Return true here unless we know ~LogMessage won't do anything. Note that
// ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even
// when g_logging_destination is LOG_NONE.
- return g_logging_destination != LOG_NONE || log_message_handler ||
+ return g_logging_destination != LOG_NONE ||
+ !log_message_handlers.Get().empty() ||
+ !log_message_listeners.Get().empty() ||
severity >= kAlwaysPrintErrorLevel;
}
@@ -443,14 +491,6 @@ void SetLogAssertHandler(LogAssertHandlerFunction handler) {
log_assert_handler = handler;
}
-void SetLogMessageHandler(LogMessageHandlerFunction handler) {
- log_message_handler = handler;
-}
-
-LogMessageHandlerFunction GetLogMessageHandler() {
- return log_message_handler;
-}
-
// Explicit instantiations for commonly used comparisons.
template std::string* MakeCheckOpString<int, int>(
const int&, const int&, const char* names);
@@ -537,12 +577,24 @@ LogMessage::~LogMessage() {
stream_ << std::endl;
std::string str_newline(stream_.str());
- // Give any log message handler first dibs on the message.
- if (log_message_handler &&
- log_message_handler(severity_, file_, line_,
- message_start_, str_newline)) {
- // The handler took care of it, no further processing.
- return;
+ {
+ base::AutoLock lock(log_message_listener_lock.Get());
+ // Broadcast to log message listeners first.
+ for (auto* listener : log_message_listeners.Get()) {
+ listener->OnMessage(severity_, file_, line_, message_start_, str_newline);
+ }
+ }
+
+ {
+ base::AutoLock lock(log_message_handler_lock.Get());
+ // Give log message handlers first dibs on the message.
+ for (auto* handler : log_message_handlers.Get()) {
+ if (handler->OnMessage(severity_, file_, line_, message_start_,
+ str_newline)) {
+ // The handler took care of it, no further processing.
+ return;
+ }
+ }
}
if ((g_logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) {
« base/logging.h ('K') | « base/logging.h ('k') | base/logging_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698