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 pointer to the LogMessageHandler instance. |
| 20 base::LazyInstance<base::Lock>::Leaky g_log_message_handler_lock = |
| 21 LAZY_INSTANCE_INITIALIZER; |
| 22 |
| 23 // The singleton LogMessageHandler instance, or null if log messages are not |
| 24 // being intercepted. It must be dereferenced and updated under the above lock. |
| 25 LogMessageHandler* g_log_message_handler = nullptr; |
| 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_log_message_handler_lock.Get()); |
| 35 if (g_log_message_handler) { |
| 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 = this; |
| 42 } |
| 43 |
| 44 LogMessageHandler::~LogMessageHandler() { |
| 45 base::AutoLock lock(g_log_message_handler_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 = nullptr; |
| 52 } |
| 53 |
| 54 // static |
| 55 const char* LogMessageHandler::kDebugMessageTypeName = "_debug_log"; |
| 56 |
| 57 // static |
| 58 bool LogMessageHandler::OnLogMessage( |
| 59 logging::LogSeverity severity, |
| 60 const char* file, |
| 61 int line, |
| 62 size_t message_start, |
| 63 const std::string& str) { |
| 64 base::AutoLock lock(g_log_message_handler_lock.Get()); |
| 65 if (g_log_message_handler) { |
| 66 g_log_message_handler->PostLogMessageToCorrectThread( |
| 67 severity, file, line, message_start, str); |
| 68 } |
| 69 return false; |
| 70 } |
| 71 |
| 72 void LogMessageHandler::PostLogMessageToCorrectThread( |
| 73 logging::LogSeverity severity, |
| 74 const char* file, |
| 75 int line, |
| 76 size_t message_start, |
| 77 const std::string& str) { |
| 78 // Don't process this message if we're already logging and on the caller |
| 79 // thread. This guards against an infinite loop if any code called by this |
| 80 // class logs something. |
| 81 if (suppress_logging_ && caller_task_runner_->BelongsToCurrentThread()) { |
| 82 return; |
| 83 } |
| 84 |
| 85 // This method is always called under the global lock, so post a task to |
| 86 // handle the log message, even if we're already on the correct thread. |
| 87 // This alows the lock to be released quickly. |
| 88 // |
| 89 // Note that this means that LOG(FATAL) messages will be lost because the |
| 90 // process will exit before the message is sent to the client. |
| 91 caller_task_runner_->PostTask( |
| 92 FROM_HERE, |
| 93 base::Bind(&LogMessageHandler::SendLogMessageToClient, |
| 94 weak_ptr_factory_.GetWeakPtr(), |
| 95 severity, file, line, message_start, str)); |
| 96 } |
| 97 |
| 98 void LogMessageHandler::SendLogMessageToClient( |
| 99 logging::LogSeverity severity, |
| 100 const char* file, |
| 101 int line, |
| 102 size_t message_start, |
| 103 const std::string& str) { |
| 104 suppress_logging_ = true; |
| 105 |
| 106 std::string severity_string = "log"; |
| 107 switch (severity) { |
| 108 case logging::LOG_WARNING: |
| 109 severity_string = "warn"; |
| 110 break; |
| 111 case logging::LOG_FATAL: |
| 112 case logging::LOG_ERROR: |
| 113 severity_string = "error"; |
| 114 break; |
| 115 } |
| 116 |
| 117 std::string message = str.substr(message_start); |
| 118 base::TrimWhitespaceASCII(message, base::TRIM_ALL, &message); |
| 119 |
| 120 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue); |
| 121 dictionary->SetString("type", kDebugMessageTypeName); |
| 122 dictionary->SetString("severity", severity_string); |
| 123 dictionary->SetString("message", message); |
| 124 dictionary->SetString("file", file); |
| 125 dictionary->SetInteger("line", line); |
| 126 |
| 127 delegate_.Run(dictionary.Pass()); |
| 128 |
| 129 suppress_logging_ = false; |
| 130 } |
| 131 |
| 132 } // namespace remoting |
OLD | NEW |