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 |