blob: 43a20e0288ff6e7ec92409c24aeceb627788cf78 [file] [log] [blame]
Brian Silvermanf665d692013-02-17 22:11:39 -08001#include "aos/common/logging/logging_impl.h"
2
Brian Silvermanb0893882014-02-10 14:48:30 -08003#include <stdarg.h>
Brian Silvermanf665d692013-02-17 22:11:39 -08004
Brian Silvermanf665d692013-02-17 22:11:39 -08005#include "aos/common/time.h"
Brian4a424a22014-04-02 11:52:45 -07006#include <inttypes.h>
Brian Silvermanf665d692013-02-17 22:11:39 -08007#include "aos/common/once.h"
Brian Silverman669669f2014-02-14 16:32:56 -08008#include "aos/common/queue_types.h"
Brian Silvermana7234c62014-03-24 20:23:25 -07009#include "aos/common/logging/logging_printf_formats.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080010
11namespace aos {
12namespace logging {
13namespace {
14
15using internal::Context;
Brian Silvermanb0893882014-02-10 14:48:30 -080016using internal::global_top_implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -080017
Brian Silvermanf665d692013-02-17 22:11:39 -080018// The root LogImplementation. It only logs to stderr/stdout.
19// Some of the things specified in the LogImplementation documentation doesn't
20// apply here (mostly the parts about being able to use LOG) because this is the
21// root one.
22class RootLogImplementation : public LogImplementation {
Brian Silverman2e799732014-06-05 21:50:19 -070023 public:
24 void have_other_implementation() { only_implementation_ = false; }
25
26 private:
Brian Silvermanf665d692013-02-17 22:11:39 -080027 virtual void set_next(LogImplementation *) {
28 LOG(FATAL, "can't have a next logger from here\n");
29 }
30
Brian Silvermanf7986142014-04-21 17:42:35 -070031 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silvermanf665d692013-02-17 22:11:39 -080032 virtual void DoLog(log_level level, const char *format, va_list ap) {
33 LogMessage message;
34 internal::FillInMessage(level, format, ap, &message);
35 internal::PrintMessage(stderr, message);
Brian Silverman2e799732014-06-05 21:50:19 -070036 if (!only_implementation_) {
37 fputs("root logger got used, see stderr for message\n", stdout);
38 }
Brian Silvermanf665d692013-02-17 22:11:39 -080039 }
Brian Silverman2e799732014-06-05 21:50:19 -070040
41 bool only_implementation_ = true;
Brian Silvermanf665d692013-02-17 22:11:39 -080042};
43
Brian Silverman2e799732014-06-05 21:50:19 -070044RootLogImplementation *root_implementation = nullptr;
45
Brian Silvermanf665d692013-02-17 22:11:39 -080046void SetGlobalImplementation(LogImplementation *implementation) {
47 Context *context = Context::Get();
48
49 context->implementation = implementation;
Brian Silverman6da04272014-05-18 18:47:48 -070050 global_top_implementation.store(implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -080051}
52
Brian Silvermane5d65692013-02-28 15:15:03 -080053void NewContext() {
54 Context::Delete();
55}
56
Brian Silvermanf665d692013-02-17 22:11:39 -080057void *DoInit() {
Brian Silverman2e799732014-06-05 21:50:19 -070058 SetGlobalImplementation(root_implementation = new RootLogImplementation());
Brian Silvermane5d65692013-02-28 15:15:03 -080059
Brian Silvermane5d65692013-02-28 15:15:03 -080060 if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/,
61 NewContext /*child*/) != 0) {
62 LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n",
63 NewContext);
64 }
Brian Silvermane5d65692013-02-28 15:15:03 -080065
Brian Silvermanf665d692013-02-17 22:11:39 -080066 return NULL;
67}
68
69} // namespace
70namespace internal {
Brian Silverman88471dc2014-02-15 22:35:42 -080071namespace {
Brian Silvermanf665d692013-02-17 22:11:39 -080072
Brian Silverman88471dc2014-02-15 22:35:42 -080073void FillInMessageBase(log_level level, LogMessage *message) {
Brian Silvermanf665d692013-02-17 22:11:39 -080074 Context *context = Context::Get();
75
Brian Silvermanf665d692013-02-17 22:11:39 -080076 message->level = level;
77 message->source = context->source;
Brian Silverman88471dc2014-02-15 22:35:42 -080078 memcpy(message->name, context->name.c_str(), context->name.size());
79 message->name_length = context->name.size();
Brian Silvermanf665d692013-02-17 22:11:39 -080080
81 time::Time now = time::Time::Now();
82 message->seconds = now.sec();
83 message->nseconds = now.nsec();
84
85 message->sequence = context->sequence++;
86}
87
Brian Silverman88471dc2014-02-15 22:35:42 -080088} // namespace
89
90void FillInMessageStructure(log_level level,
91 const ::std::string &message_string, size_t size,
92 const MessageType *type,
93 const ::std::function<size_t(char *)> &serialize,
94 LogMessage *message) {
95 type_cache::AddShm(type->id);
96 message->structure.type_id = type->id;
97
98 FillInMessageBase(level, message);
99
100 if (message_string.size() + size > sizeof(message->structure.serialized)) {
101 LOG(FATAL, "serialized struct %s (size %zd) and message %s too big\n",
102 type->name.c_str(), size, message_string.c_str());
103 }
104 message->structure.string_length = message_string.size();
105 memcpy(message->structure.serialized, message_string.data(),
106 message->structure.string_length);
107
108 message->message_length = serialize(
109 &message->structure.serialized[message->structure.string_length]);
110 message->type = LogMessage::Type::kStruct;
111}
112
Brian Silverman664db1a2014-03-20 17:06:29 -0700113void FillInMessageMatrix(log_level level,
114 const ::std::string &message_string, uint32_t type_id,
115 int rows, int cols, const void *data,
116 LogMessage *message) {
117 CHECK(MessageType::IsPrimitive(type_id));
118 message->matrix.type = type_id;
119
120 const auto element_size = MessageType::Sizeof(type_id);
121
122 FillInMessageBase(level, message);
123
124 message->message_length = rows * cols * element_size;
125 if (message_string.size() + message->message_length >
126 sizeof(message->matrix.data)) {
127 LOG(FATAL, "%dx%d matrix of type %" PRIu32
128 " (size %u) and message %s is too big\n",
129 rows, cols, type_id, element_size, message_string.c_str());
130 }
131 message->matrix.string_length = message_string.size();
132 memcpy(message->matrix.data, message_string.data(),
133 message->matrix.string_length);
134
135 message->matrix.rows = rows;
136 message->matrix.cols = cols;
137 SerializeMatrix(type_id, &message->matrix.data[message->matrix.string_length],
138 data, rows, cols);
139 message->type = LogMessage::Type::kMatrix;
140}
141
Brian Silverman88471dc2014-02-15 22:35:42 -0800142void FillInMessage(log_level level, const char *format, va_list ap,
143 LogMessage *message) {
144 FillInMessageBase(level, message);
145
146 message->message_length =
147 ExecuteFormat(message->message, sizeof(message->message), format, ap);
148 message->type = LogMessage::Type::kString;
149}
150
Brian Silvermanf665d692013-02-17 22:11:39 -0800151void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silvermana7234c62014-03-24 20:23:25 -0700152#define BASE_ARGS \
153 AOS_LOGGING_BASE_ARGS( \
154 message.name_length, message.name, static_cast<int32_t>(message.source), \
155 message.sequence, message.level, message.seconds, message.nseconds)
156 switch (message.type) {
Brian Silverman88471dc2014-02-15 22:35:42 -0800157 case LogMessage::Type::kString:
Brian Silvermana7234c62014-03-24 20:23:25 -0700158 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
Brian Silverman88471dc2014-02-15 22:35:42 -0800159 static_cast<int>(message.message_length), message.message);
160 break;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700161 case LogMessage::Type::kStruct: {
Brian Silvermanbe858a12014-04-30 17:37:28 -0700162 char buffer[2048];
Brian Silverman88471dc2014-02-15 22:35:42 -0800163 size_t output_length = sizeof(buffer);
164 size_t input_length = message.message_length;
165 if (!PrintMessage(
166 buffer, &output_length,
167 message.structure.serialized + message.structure.string_length,
168 &input_length, type_cache::Get(message.structure.type_id))) {
169 LOG(FATAL,
170 "printing message (%.*s) of type %s into %zu-byte buffer failed\n",
171 static_cast<int>(message.message_length), message.message,
172 type_cache::Get(message.structure.type_id).name.c_str(),
173 sizeof(buffer));
174 }
175 if (input_length > 0) {
176 LOG(WARNING, "%zu extra bytes on message of type %s\n", input_length,
177 type_cache::Get(message.structure.type_id).name.c_str());
178 }
Brian Silvermana7234c62014-03-24 20:23:25 -0700179 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
Brian Silvermanb263d302014-02-16 00:01:43 -0800180 static_cast<int>(message.structure.string_length),
181 message.structure.serialized,
182 static_cast<int>(sizeof(buffer) - output_length), buffer);
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700183 } break;
184 case LogMessage::Type::kMatrix: {
185 char buffer[1024];
186 size_t output_length = sizeof(buffer);
187 if (message.message_length !=
188 static_cast<size_t>(message.matrix.rows * message.matrix.cols *
189 MessageType::Sizeof(message.matrix.type))) {
190 LOG(FATAL, "expected %d bytes of matrix data but have %zu\n",
191 message.matrix.rows * message.matrix.cols *
192 MessageType::Sizeof(message.matrix.type),
193 message.message_length);
194 }
195 if (!PrintMatrix(buffer, &output_length,
196 message.matrix.data + message.matrix.string_length,
197 message.matrix.type, message.matrix.rows,
198 message.matrix.cols)) {
199 LOG(FATAL, "printing %dx%d matrix of type %" PRIu32 " failed\n",
200 message.matrix.rows, message.matrix.cols, message.matrix.type);
201 }
Brian Silvermana7234c62014-03-24 20:23:25 -0700202 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700203 static_cast<int>(message.matrix.string_length),
Brian Silverman664db1a2014-03-20 17:06:29 -0700204 message.matrix.data,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700205 static_cast<int>(sizeof(buffer) - output_length), buffer);
206 } break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800207 }
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800208#undef BASE_ARGS
Brian Silvermanf665d692013-02-17 22:11:39 -0800209}
210
211} // namespace internal
212
Brian Silverman669669f2014-02-14 16:32:56 -0800213void LogImplementation::LogStruct(
214 log_level level, const ::std::string &message, size_t size,
215 const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
216 char serialized[1024];
217 if (size > sizeof(serialized)) {
218 LOG(FATAL, "structure of type %s too big to serialize\n",
219 type->name.c_str());
220 }
221 size_t used = serialize(serialized);
Brian Silverman2508c082014-02-17 15:45:02 -0800222 char printed[1024];
Brian Silverman669669f2014-02-14 16:32:56 -0800223 size_t printed_bytes = sizeof(printed);
224 if (!PrintMessage(printed, &printed_bytes, serialized, &used, *type)) {
225 LOG(FATAL, "PrintMessage(%p, %p(=%zd), %p, %p(=%zd), %p(name=%s)) failed\n",
226 printed, &printed_bytes, printed_bytes, serialized, &used, used, type,
227 type->name.c_str());
228 }
229 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
Brian Silverman1c7b8192014-02-16 22:37:36 -0800230 message.data(),
231 static_cast<int>(sizeof(printed) - printed_bytes), printed);
Brian Silverman669669f2014-02-14 16:32:56 -0800232}
233
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700234void LogImplementation::LogMatrix(
235 log_level level, const ::std::string &message, uint32_t type_id,
236 int rows, int cols, const void *data) {
237 char serialized[1024];
238 if (static_cast<size_t>(rows * cols * MessageType::Sizeof(type_id)) >
239 sizeof(serialized)) {
240 LOG(FATAL, "matrix of size %u too big to serialize\n",
241 rows * cols * MessageType::Sizeof(type_id));
242 }
243 SerializeMatrix(type_id, serialized, data, rows, cols);
244 char printed[1024];
245 size_t printed_bytes = sizeof(printed);
246 if (!PrintMatrix(printed, &printed_bytes, serialized, type_id, rows, cols)) {
247 LOG(FATAL, "PrintMatrix(%p, %p(=%zd), %p, %" PRIu32 ", %d, %d) failed\n",
248 printed, &printed_bytes, printed_bytes, serialized, type_id, rows,
249 cols);
250 }
251 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
252 message.data(),
253 static_cast<int>(sizeof(printed) - printed_bytes), printed);
254}
255
Brian Silvermanbe858a12014-04-30 17:37:28 -0700256void HandleMessageLogImplementation::DoLog(log_level level, const char *format,
257 va_list ap) {
258 LogMessage message;
259 internal::FillInMessage(level, format, ap, &message);
260 HandleMessage(message);
261}
262
263void HandleMessageLogImplementation::LogStruct(
264 log_level level, const ::std::string &message_string, size_t size,
265 const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
266 LogMessage message;
267 internal::FillInMessageStructure(level, message_string, size, type, serialize,
268 &message);
269 HandleMessage(message);
270}
271
272void HandleMessageLogImplementation::LogMatrix(
273 log_level level, const ::std::string &message_string, uint32_t type_id,
274 int rows, int cols, const void *data) {
275 LogMessage message;
276 internal::FillInMessageMatrix(level, message_string, type_id, rows, cols,
277 data, &message);
278 HandleMessage(message);
279}
280
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800281StreamLogImplementation::StreamLogImplementation(FILE *stream)
282 : stream_(stream) {}
283
Brian Silvermanbe858a12014-04-30 17:37:28 -0700284void StreamLogImplementation::HandleMessage(const LogMessage &message) {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800285 internal::PrintMessage(stream_, message);
286}
287
Brian Silvermanf665d692013-02-17 22:11:39 -0800288void LogNext(log_level level, const char *format, ...) {
289 va_list ap;
290 va_start(ap, format);
291 LogImplementation::DoVLog(level, format, ap, 2);
292 va_end(ap);
293}
294
295void AddImplementation(LogImplementation *implementation) {
296 Context *context = Context::Get();
297
298 if (implementation->next() != NULL) {
299 LOG(FATAL, "%p already has a next implementation, but it's not"
300 " being used yet\n", implementation);
301 }
302
303 LogImplementation *old = context->implementation;
304 if (old != NULL) {
305 implementation->set_next(old);
306 }
307 SetGlobalImplementation(implementation);
Brian Silverman2e799732014-06-05 21:50:19 -0700308 root_implementation->have_other_implementation();
Brian Silvermanf665d692013-02-17 22:11:39 -0800309}
310
311void Init() {
312 static Once<void> once(DoInit);
313 once.Get();
314}
315
316void Load() {
317 Context::Get();
318}
319
320void Cleanup() {
321 Context::Delete();
322}
323
324} // namespace logging
325} // namespace aos