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

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: only keep scoped API 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..1203975cceee9c399d4ffecfc3c8feafb72d24e9 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -49,15 +49,18 @@ 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"
@@ -123,8 +126,13 @@ 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;
+// Log message listeners that get notified of every log message we process
+// before log message handlers.
+base::LazyInstance<std::unordered_set<LogMessageListener*>>::Leaky
grt (UTC plus 2) 2016/07/27 20:38:20 why an unordered set? are there really so many lis
wychen 2016/08/01 16:12:25 The number of listeners should be very low practic
grt (UTC plus 2) 2016/08/01 21:17:44 Ouch. Apologies for the complexity goof. I haven't
wychen 2016/08/01 23:11:03 Unordered set does use a hash table internally. Do
grt (UTC plus 2) 2016/08/02 07:25:46 I'm a bit divided. On the one hand, I prefer callb
wychen 2016/08/04 03:53:55 I meant keeping the single-method interface as is,
+ log_message_listeners = LAZY_INSTANCE_INITIALIZER;
// Helper functions to wrap platform differences.
@@ -342,6 +350,34 @@ void CloseLogFileUnlocked() {
} // namespace
+LogMessageHandler::LogMessageHandler() {
+ log_message_handlers.Get().push_front(this);
+}
+
+LogMessageHandler::~LogMessageHandler() {
+ auto& handlers = log_message_handlers.Get();
+ unsigned count = handlers.size();
grt (UTC plus 2) 2016/07/27 20:38:20 size_t
wychen 2016/08/01 16:12:25 Done.
+ handlers.erase(std::remove(handlers.begin(), handlers.end(), this),
+ handlers.end());
+ DCHECK_EQ(count - 1, handlers.size());
+}
+
+unsigned LogMessageHandlerCountForTesting() {
+ return log_message_handlers.Get().size();
+}
+
+LogMessageListener::LogMessageListener() {
+ log_message_listeners.Get().insert(this);
+}
+
+LogMessageListener::~LogMessageListener() {
+ DCHECK_EQ(1u, log_message_listeners.Get().erase(this));
+}
+
+unsigned LogMessageListenerCountForTesting() {
+ return log_message_listeners.Get().size();
+}
+
LoggingSettings::LoggingSettings()
: logging_dest(LOG_DEFAULT),
log_file(nullptr),
@@ -409,7 +445,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 +481,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 +567,18 @@ 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;
+ // Broadcast to log message listeners first.
+ for (auto* listeners : log_message_listeners.Get()) {
grt (UTC plus 2) 2016/07/27 20:38:20 listeners -> listener
grt (UTC plus 2) 2016/07/28 06:28:47 since logging may happen on any thread at any time
wychen 2016/08/01 16:12:25 I've added Locks.
wychen 2016/08/01 16:12:25 Done.
+ listeners->OnMessage(severity_, file_, line_, message_start_, str_newline);
+ }
+
+ // 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) {

Powered by Google App Engine
This is Rietveld 408576698