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 "mojo/services/log/cpp/log_client.h" | |
6 | |
7 #include <assert.h> | |
8 | |
9 #include <atomic> | |
10 #include <utility> | |
11 | |
12 #include "mojo/public/c/environment/logger.h" | |
13 #include "mojo/public/cpp/bindings/lib/message_builder.h" | |
14 #include "mojo/public/cpp/system/message_pipe.h" | |
15 #include "mojo/services/log/interfaces/entry.mojom.h" | |
16 #include "mojo/services/log/interfaces/log.mojom.h" | |
17 | |
18 namespace mojo { | |
19 namespace { | |
20 | |
21 // Forward declare for constructing |g_logclient_logger|. | |
22 void LogMessage(MojoLogLevel log_level, | |
23 const char* source_file, | |
24 uint32_t source_line, | |
25 const char* message); | |
26 MojoLogLevel GetMinimumLogLevel(); | |
27 void SetMinimumLogLevel(MojoLogLevel level); | |
28 | |
29 // This interface info represents the |mojo::log::Log| service (see log.mojom). | |
30 // This doesn't need to be synchronized, since we only allow one LogClient to be | |
31 // instantiated, so it is only initialized once, and from one thread. | |
32 InterfacePtrInfo<mojo::log::Log>* g_log_interface = nullptr; | |
33 | |
34 // The minimum logging level. | |
35 std::atomic<MojoLogLevel> g_min_log_level; | |
36 | |
37 MojoLogger g_logclient_logger = {&LogMessage, &GetMinimumLogLevel, | |
38 &SetMinimumLogLevel}; | |
39 | |
40 // This fallback logger is also thread-safe. | |
41 const MojoLogger* g_fallback_logger = nullptr; | |
42 | |
43 // We avoid the use of C++ bindings to do interface calls in order to be | |
viettrungluu
2015/11/20 23:21:51
This comment belongs inside the function, not abov
vardhan
2015/12/02 00:06:13
Done.
| |
44 // thread-safe (as of this writing, the bindings are not). Because the AddEntry | |
45 // method of the Log interface does not have a return type, we can easily do | |
viettrungluu
2015/11/20 23:21:51
it's not a "method"
vardhan
2015/12/02 00:06:13
Done.
| |
46 // this by constructing the params for the call | |
47 // (mojo::log::Log_AddEntry_Params), framing it inside a Message using | |
48 // MessageBuilder, writing to the message pipe connecting to the log service. | |
49 void LogMessage(MojoLogLevel log_level, | |
50 const char* source_file, | |
51 uint32_t source_line, | |
52 const char* message) { | |
53 assert(g_log_interface); | |
54 if (!g_log_interface->is_valid()) { | |
55 assert(g_fallback_logger); | |
56 return g_fallback_logger->LogMessage(log_level, source_file, source_line, | |
57 message); | |
58 } | |
59 | |
60 if (log_level < g_min_log_level.load(std::memory_order_relaxed)) | |
61 return; | |
62 | |
63 assert(g_log_interface->is_valid()); | |
64 | |
65 mojo::log::Log_AddEntry_Params request_params; | |
66 request_params.entry = mojo::log::Entry::New(); | |
67 request_params.entry->timestamp = GetTimeTicksNow(); | |
68 request_params.entry->log_level = log_level; | |
69 request_params.entry->source_file = source_file; | |
70 request_params.entry->source_line = source_line; | |
71 request_params.entry->message = message; | |
72 | |
73 size_t params_size = request_params.GetSerializedSize(); | |
74 MessageBuilder builder( | |
75 static_cast<uint32_t>(mojo::log::Log::MessageOrdinals::AddEntry), | |
76 params_size); | |
77 | |
78 request_params.Serialize( | |
79 static_cast<void*>(builder.message()->mutable_payload()), params_size); | |
80 | |
81 auto retval = WriteMessageRaw(g_log_interface->handle().get(), | |
82 builder.message()->data(), | |
83 builder.message()->data_num_bytes(), nullptr, 0, | |
84 MOJO_WRITE_MESSAGE_FLAG_NONE); | |
85 switch (retval) { | |
86 case MOJO_RESULT_OK: | |
87 break; | |
88 | |
89 // This means that the other end of the pipe no longer exists, so it 's time | |
90 // to fall back. | |
91 case MOJO_RESULT_FAILED_PRECONDITION: { | |
92 g_log_interface->PassHandle(); | |
93 return g_fallback_logger->LogMessage(log_level, source_file, source_line, | |
94 message); | |
95 } | |
96 | |
97 default: | |
98 // TODO(vardhan): What other cases are there? | |
viettrungluu
2015/11/20 23:21:51
You should do this.
vardhan
2015/12/02 00:06:13
Done.
| |
99 break; | |
100 } | |
101 | |
102 if (log_level >= MOJO_LOG_LEVEL_FATAL) | |
103 abort(); | |
104 } | |
105 | |
106 MojoLogLevel GetMinimumLogLevel() { | |
107 assert(g_log_interface); | |
108 | |
109 if (!g_log_interface->is_valid()) { | |
110 assert(g_fallback_logger); | |
111 return g_fallback_logger->GetMinimumLogLevel(); | |
112 } | |
113 return g_min_log_level.load(std::memory_order_relaxed); | |
114 } | |
115 | |
116 void SetMinimumLogLevel(MojoLogLevel level) { | |
117 assert(g_log_interface); | |
118 | |
119 if (!g_log_interface->is_valid()) { | |
120 assert(g_fallback_logger); | |
121 g_fallback_logger->SetMinimumLogLevel(level); | |
122 } | |
123 g_min_log_level.store(std::min(level, MOJO_LOG_LEVEL_FATAL), | |
124 std::memory_order_relaxed); | |
125 | |
126 // Keep the fallback logger's level consistent with ours. | |
127 g_fallback_logger->SetMinimumLogLevel(level); | |
128 } | |
129 | |
130 } // namespace | |
131 | |
132 namespace log { | |
133 | |
134 LogClient::LogClient(LogPtr log, const MojoLogger* fallback_logger) { | |
135 assert(!g_log_interface); | |
136 assert(log.is_bound()); | |
137 assert(fallback_logger); | |
138 | |
139 g_min_log_level.store(MOJO_LOG_LEVEL_INFO, std::memory_order_relaxed); | |
140 g_log_interface = new InterfacePtrInfo<Log>(log.PassInterface()); | |
141 | |
142 g_fallback_logger = fallback_logger; | |
143 } | |
144 | |
145 LogClient::~LogClient() { | |
146 g_log_interface->PassHandle(); | |
147 delete g_log_interface; | |
148 g_log_interface = nullptr; | |
149 } | |
150 | |
151 // static | |
152 const MojoLogger* LogClient::GetLogger() { | |
153 return &g_logclient_logger; | |
154 } | |
155 | |
156 } // namespace log | |
157 } // namespace mojo | |
OLD | NEW |