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.
5 #include "remoting/host/native_messaging/log_message_handler.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"
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
;
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;
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.";
39 previous_log_message_handler_
= logging::GetLogMessageHandler();
40 logging::SetLogMessageHandler(&LogMessageHandler::OnLogMessage
);
41 g_log_message_handler
= this;
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.";
50 logging::SetLogMessageHandler(previous_log_message_handler_
);
51 g_log_message_handler
= nullptr;
55 const char* LogMessageHandler::kDebugMessageTypeName
= "_debug_log";
58 bool LogMessageHandler::OnLogMessage(
59 logging::LogSeverity severity
,
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
);
72 void LogMessageHandler::PostLogMessageToCorrectThread(
73 logging::LogSeverity severity
,
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()) {
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.
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(
93 base::Bind(&LogMessageHandler::SendLogMessageToClient
,
94 weak_ptr_factory_
.GetWeakPtr(),
95 severity
, file
, line
, message_start
, str
));
98 void LogMessageHandler::SendLogMessageToClient(
99 logging::LogSeverity severity
,
102 size_t message_start
,
103 const std::string
& str
) {
104 suppress_logging_
= true;
106 std::string severity_string
= "log";
108 case logging::LOG_WARNING
:
109 severity_string
= "warn";
111 case logging::LOG_FATAL
:
112 case logging::LOG_ERROR
:
113 severity_string
= "error";
117 std::string message
= str
.substr(message_start
);
118 base::TrimWhitespaceASCII(message
, base::TRIM_ALL
, &message
);
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
);
127 delegate_
.Run(dictionary
.Pass());
129 suppress_logging_
= false;
132 } // namespace remoting