Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 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. | |
|
Sergey Ulanov
2015/08/17 23:06:24
update the comment - it's not weak anymore.
Jamie
2015/08/18 00:05:20
Done.
| |
| 20 base::LazyInstance<base::Lock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER; | |
|
Sergey Ulanov
2015/08/17 23:06:25
nit: maybe rename this to g_log_message_handler_lo
Jamie
2015/08/18 00:05:20
Done.
| |
| 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. | |
|
Sergey Ulanov
2015/08/17 23:06:25
s/a lock/the lock/
Jamie
2015/08/18 00:05:20
Done.
| |
| 24 LogMessageHandler* g_log_message_handler = nullptr; | |
| 25 } // namespace | |
| 26 | |
| 27 LogMessageHandler::LogMessageHandler( | |
| 28 const Delegate& delegate) | |
| 29 : delegate_(delegate), | |
| 30 suppress_logging_(false), | |
| 31 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 32 weak_ptr_factory_(this) { | |
| 33 base::AutoLock lock(g_lock.Get()); | |
| 34 if (g_log_message_handler) { | |
| 35 LOG(FATAL) << "LogMessageHandler is already registered. Only one instance " | |
| 36 << "per process is allowed."; | |
| 37 } | |
| 38 previous_log_message_handler_ = logging::GetLogMessageHandler(); | |
| 39 logging::SetLogMessageHandler(&LogMessageHandler::OnLogMessage); | |
| 40 g_log_message_handler = this; | |
| 41 } | |
| 42 | |
| 43 LogMessageHandler::~LogMessageHandler() { | |
| 44 base::AutoLock lock(g_lock.Get()); | |
| 45 if (logging::GetLogMessageHandler() != &LogMessageHandler::OnLogMessage) { | |
| 46 LOG(FATAL) << "LogMessageHandler is not the top-most message handler. " | |
| 47 << "Cannot unregister."; | |
| 48 } | |
| 49 logging::SetLogMessageHandler(previous_log_message_handler_); | |
| 50 g_log_message_handler = nullptr; | |
| 51 } | |
| 52 | |
| 53 // static | |
| 54 bool LogMessageHandler::OnLogMessage( | |
| 55 logging::LogSeverity severity, | |
| 56 const char* file, | |
| 57 int line, | |
| 58 size_t message_start, | |
| 59 const std::string& str) { | |
| 60 base::AutoLock lock(g_lock.Get()); | |
| 61 if (g_log_message_handler) { | |
| 62 g_log_message_handler->PostLogMessageToCorrectThread( | |
| 63 severity, file, line, message_start, str); | |
| 64 } | |
| 65 return false; | |
| 66 } | |
| 67 | |
| 68 void LogMessageHandler::PostLogMessageToCorrectThread( | |
| 69 logging::LogSeverity severity, | |
| 70 const char* file, | |
| 71 int line, | |
| 72 size_t message_start, | |
| 73 const std::string& str) { | |
| 74 // Don't process this message if we're already logging and on the caller | |
| 75 // thread. This guards against an infinite loop if any code called by this | |
| 76 // class logs something. | |
| 77 if (suppress_logging_ && caller_task_runner_->BelongsToCurrentThread()) { | |
| 78 return; | |
| 79 } | |
| 80 | |
| 81 // This method is always called under the global lock, so post a task to | |
| 82 // handle the log message, even if we're already on the correct thread. | |
| 83 // This alows the lock to be released quickly. | |
| 84 // | |
| 85 // Note that this means that LOG(FATAL) messages will be lost because the | |
| 86 // process will exit before the message is sent to the client. | |
| 87 caller_task_runner_->PostTask( | |
| 88 FROM_HERE, | |
| 89 base::Bind(&LogMessageHandler::SendLogMessageToClient, | |
| 90 weak_ptr_factory_.GetWeakPtr(), | |
| 91 severity, file, line, message_start, str)); | |
| 92 } | |
| 93 | |
| 94 void LogMessageHandler::SendLogMessageToClient( | |
| 95 logging::LogSeverity severity, | |
| 96 const char* file, | |
| 97 int line, | |
| 98 size_t message_start, | |
| 99 const std::string& str) { | |
| 100 suppress_logging_ = true; | |
| 101 | |
| 102 std::string severity_string = "log"; | |
| 103 switch (severity) { | |
| 104 case logging::LOG_WARNING: | |
| 105 severity_string = "warn"; | |
| 106 break; | |
| 107 case logging::LOG_FATAL: | |
| 108 case logging::LOG_ERROR: | |
| 109 severity_string = "error"; | |
| 110 break; | |
| 111 } | |
| 112 | |
| 113 std::string message = str.substr(message_start); | |
| 114 base::TrimWhitespaceASCII(message, base::TRIM_ALL, &message); | |
| 115 | |
| 116 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue); | |
| 117 dictionary->SetString("type", "_debug_log"); | |
| 118 dictionary->SetString("severity", severity_string); | |
| 119 dictionary->SetString("message", message); | |
| 120 dictionary->SetString("file", file); | |
| 121 dictionary->SetInteger("line", line); | |
| 122 | |
| 123 delegate_.Run(dictionary.Pass()); | |
| 124 | |
| 125 suppress_logging_ = false; | |
| 126 } | |
| 127 | |
| 128 } // namespace remoting | |
| OLD | NEW |