Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | |
|
Sergey Ulanov
2015/08/16 23:22:02
nit: remove (c)
Jamie
2015/08/17 17:32:23
Done.
| |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "remoting/host/native_messaging/log_message_handler.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/lazy_instance.h" | |
| 9 #include "base/strings/string_util.h" | |
| 10 #include "base/synchronization/lock.h" | |
| 11 #include "base/thread_task_runner_handle.h" | |
| 12 #include "base/tracked_objects.h" | |
| 13 | |
| 14 namespace remoting { | |
| 15 | |
| 16 namespace { | |
| 17 // Log message handler registration and deregistration is not thread-safe. | |
| 18 // This lock must be held in order to set or restore a log message handler, | |
| 19 // and when accessing the weak pointer to the LogMessageHandler instance. | |
| 20 base::LazyInstance<base::Lock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER; | |
| 21 | |
| 22 // The singleton LogMessageHandler instance, or null if log messages are | |
| 23 // not being intercepted. It must be dereferenced and updated under a lock. | |
| 24 base::LazyInstance<base::WeakPtr<LogMessageHandler> >::Leaky | |
| 25 g_log_message_handler = LAZY_INSTANCE_INITIALIZER; | |
| 26 } // namespace | |
| 27 | |
| 28 LogMessageHandler::LogMessageHandler( | |
| 29 const Delegate& delegate) | |
| 30 : delegate_(delegate), | |
| 31 suppress_logging_(false), | |
| 32 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 33 weak_ptr_factory_(this) { | |
| 34 base::AutoLock lock(g_lock.Get()); | |
| 35 if (g_log_message_handler.Get()) { | |
| 36 LOG(FATAL) << "LogMessageHandler is already registered. Only one instance " | |
| 37 << "per process is allowed."; | |
| 38 } | |
| 39 previous_log_message_handler_ = logging::GetLogMessageHandler(); | |
| 40 logging::SetLogMessageHandler(&LogMessageHandler::OnLogMessage); | |
| 41 g_log_message_handler.Get() = weak_ptr_factory_.GetWeakPtr(); | |
| 42 } | |
| 43 | |
| 44 LogMessageHandler::~LogMessageHandler() { | |
| 45 base::AutoLock lock(g_lock.Get()); | |
| 46 if (logging::GetLogMessageHandler() != &LogMessageHandler::OnLogMessage) { | |
| 47 LOG(FATAL) << "LogMessageHandler is not the top-most message handler. " | |
| 48 << "Cannot unregister."; | |
| 49 } | |
| 50 logging::SetLogMessageHandler(previous_log_message_handler_); | |
| 51 g_log_message_handler.Get().reset(); | |
| 52 } | |
| 53 | |
| 54 bool LogMessageHandler::OnLogMessage( | |
|
Sergey Ulanov
2015/08/16 23:22:02
add //static comment to make clear that this is a
Jamie
2015/08/17 17:32:23
Done.
| |
| 55 logging::LogSeverity severity, const char* file, int line, | |
| 56 size_t message_start, const std::string& str) { | |
| 57 base::AutoLock lock(g_lock.Get()); | |
| 58 if (g_log_message_handler.Get()) { | |
|
Sergey Ulanov
2015/08/16 23:22:02
WeakPtr can be deferenced only on one thread, so y
Jamie
2015/08/17 17:32:23
Doesn't that introduce a race if the LogMessageHan
Sergey Ulanov
2015/08/17 21:01:16
You can still post the task using weak pointer. Po
Jamie
2015/08/17 21:23:35
Done.
| |
| 59 g_log_message_handler.Get()->PostLogMessageToCorrectThread( | |
| 60 severity, file, line, message_start, str); | |
| 61 } | |
| 62 return false; | |
| 63 } | |
| 64 | |
| 65 void LogMessageHandler::PostLogMessageToCorrectThread( | |
| 66 logging::LogSeverity severity, const char* file, int line, | |
| 67 size_t message_start, const std::string& str) { | |
|
Sergey Ulanov
2015/08/16 23:22:02
nit: one parameter per line please
Jamie
2015/08/17 17:32:23
Done.
| |
| 68 // Don't process this message if we're already logging. This guards against | |
| 69 // an infinite loop if any code called by this class logs something. Note | |
| 70 // that this will also suppress messages logged on other threads while any | |
| 71 // message is being processed; this is an acceptable trade-off. | |
| 72 if (suppress_logging_) { | |
|
Sergey Ulanov
2015/08/16 23:22:02
I think this is necessary only on the caller threa
Jamie
2015/08/17 17:32:24
Done.
| |
| 73 return; | |
| 74 } | |
| 75 | |
| 76 // This method is always called under the global lock, so post a task to | |
| 77 // handle the log message, even if we're already on the correct thread. | |
| 78 // This alows the lock to be released quickly. | |
|
Sergey Ulanov
2015/08/16 23:22:02
One downside of this approach is that LOG_FATAL er
Jamie
2015/08/17 17:32:23
Done.
| |
| 79 caller_task_runner_->PostTask( | |
| 80 FROM_HERE, | |
| 81 base::Bind(&LogMessageHandler::SendLogMessageToClient, | |
| 82 weak_ptr_factory_.GetWeakPtr(), | |
| 83 severity, file, line, message_start, str)); | |
| 84 } | |
| 85 | |
| 86 void LogMessageHandler::SendLogMessageToClient( | |
| 87 logging::LogSeverity severity, const char* file, int line, | |
| 88 size_t message_start, const std::string& str) { | |
| 89 suppress_logging_ = true; | |
| 90 | |
| 91 std::string severity_string = "log"; | |
| 92 switch (severity) { | |
| 93 case logging::LOG_WARNING: | |
| 94 severity_string = "warn"; | |
| 95 break; | |
| 96 case logging::LOG_FATAL: | |
| 97 case logging::LOG_ERROR: | |
| 98 severity_string = "error"; | |
| 99 break; | |
| 100 } | |
| 101 | |
| 102 std::string message = str.c_str() + message_start; | |
|
Sergey Ulanov
2015/08/16 23:22:02
message = std.substr(message_start);
Jamie
2015/08/17 17:32:23
Done.
| |
| 103 base::TrimWhitespaceASCII(message, base::TRIM_ALL, &message); | |
| 104 | |
| 105 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue); | |
| 106 dictionary->SetString("type", "_debug_log"); | |
| 107 dictionary->SetString("severity", severity_string); | |
| 108 dictionary->SetString("message", message); | |
| 109 dictionary->SetString("file", file); | |
| 110 dictionary->SetInteger("line", line); | |
| 111 | |
| 112 delegate_.Run(dictionary.Pass()); | |
| 113 | |
| 114 suppress_logging_ = false; | |
| 115 } | |
| 116 | |
| 117 } // namespace remoting | |
| OLD | NEW |