blob: 34c3816cd3cc99eaf4c68fc51964dee54f504a19 [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>
Brian4a424a22014-04-02 11:52:45 -07004#include <inttypes.h>
Austin Schuh044e18b2015-10-21 20:17:09 -07005
Brian Silvermanf665d692013-02-17 22:11:39 -08006#include "aos/common/once.h"
Austin Schuh044e18b2015-10-21 20:17:09 -07007#include "aos/common/time.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) {
Brian Silverman5c201e22014-06-12 22:40:28 -070047 if (root_implementation == nullptr) {
48 fputs("Somebody didn't call logging::Init()!\n", stderr);
49 abort();
50 }
51
Brian Silvermanf665d692013-02-17 22:11:39 -080052 Context *context = Context::Get();
53
54 context->implementation = implementation;
Brian Silverman6da04272014-05-18 18:47:48 -070055 global_top_implementation.store(implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -080056}
57
Brian Silvermane5d65692013-02-28 15:15:03 -080058void NewContext() {
59 Context::Delete();
60}
61
Brian Silvermanf665d692013-02-17 22:11:39 -080062void *DoInit() {
Brian Silverman2e799732014-06-05 21:50:19 -070063 SetGlobalImplementation(root_implementation = new RootLogImplementation());
Brian Silvermane5d65692013-02-28 15:15:03 -080064
Brian Silvermane5d65692013-02-28 15:15:03 -080065 if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/,
66 NewContext /*child*/) != 0) {
67 LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n",
68 NewContext);
69 }
Brian Silvermane5d65692013-02-28 15:15:03 -080070
Brian Silvermanf665d692013-02-17 22:11:39 -080071 return NULL;
72}
73
74} // namespace
75namespace internal {
Brian Silverman88471dc2014-02-15 22:35:42 -080076namespace {
Brian Silvermanf665d692013-02-17 22:11:39 -080077
Brian Silverman88471dc2014-02-15 22:35:42 -080078void FillInMessageBase(log_level level, LogMessage *message) {
Brian Silvermanf665d692013-02-17 22:11:39 -080079 Context *context = Context::Get();
80
Brian Silvermanf665d692013-02-17 22:11:39 -080081 message->level = level;
82 message->source = context->source;
Austin Schuhaebbc342015-01-25 02:25:13 -080083 memcpy(message->name, context->name, context->name_size);
84 message->name_length = context->name_size;
Brian Silvermanf665d692013-02-17 22:11:39 -080085
86 time::Time now = time::Time::Now();
87 message->seconds = now.sec();
88 message->nseconds = now.nsec();
89
90 message->sequence = context->sequence++;
91}
92
Brian Silverman88471dc2014-02-15 22:35:42 -080093} // namespace
94
95void FillInMessageStructure(log_level level,
96 const ::std::string &message_string, size_t size,
97 const MessageType *type,
98 const ::std::function<size_t(char *)> &serialize,
99 LogMessage *message) {
100 type_cache::AddShm(type->id);
101 message->structure.type_id = type->id;
102
103 FillInMessageBase(level, message);
104
105 if (message_string.size() + size > sizeof(message->structure.serialized)) {
106 LOG(FATAL, "serialized struct %s (size %zd) and message %s too big\n",
107 type->name.c_str(), size, message_string.c_str());
108 }
109 message->structure.string_length = message_string.size();
110 memcpy(message->structure.serialized, message_string.data(),
111 message->structure.string_length);
112
113 message->message_length = serialize(
114 &message->structure.serialized[message->structure.string_length]);
115 message->type = LogMessage::Type::kStruct;
116}
117
Brian Silverman664db1a2014-03-20 17:06:29 -0700118void FillInMessageMatrix(log_level level,
119 const ::std::string &message_string, uint32_t type_id,
120 int rows, int cols, const void *data,
121 LogMessage *message) {
122 CHECK(MessageType::IsPrimitive(type_id));
123 message->matrix.type = type_id;
124
125 const auto element_size = MessageType::Sizeof(type_id);
126
127 FillInMessageBase(level, message);
128
129 message->message_length = rows * cols * element_size;
130 if (message_string.size() + message->message_length >
131 sizeof(message->matrix.data)) {
132 LOG(FATAL, "%dx%d matrix of type %" PRIu32
133 " (size %u) and message %s is too big\n",
134 rows, cols, type_id, element_size, message_string.c_str());
135 }
136 message->matrix.string_length = message_string.size();
137 memcpy(message->matrix.data, message_string.data(),
138 message->matrix.string_length);
139
140 message->matrix.rows = rows;
141 message->matrix.cols = cols;
142 SerializeMatrix(type_id, &message->matrix.data[message->matrix.string_length],
143 data, rows, cols);
144 message->type = LogMessage::Type::kMatrix;
145}
146
Brian Silverman88471dc2014-02-15 22:35:42 -0800147void FillInMessage(log_level level, const char *format, va_list ap,
148 LogMessage *message) {
149 FillInMessageBase(level, message);
150
151 message->message_length =
152 ExecuteFormat(message->message, sizeof(message->message), format, ap);
153 message->type = LogMessage::Type::kString;
154}
155
Brian Silvermanf665d692013-02-17 22:11:39 -0800156void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silvermana7234c62014-03-24 20:23:25 -0700157#define BASE_ARGS \
158 AOS_LOGGING_BASE_ARGS( \
159 message.name_length, message.name, static_cast<int32_t>(message.source), \
160 message.sequence, message.level, message.seconds, message.nseconds)
161 switch (message.type) {
Brian Silverman88471dc2014-02-15 22:35:42 -0800162 case LogMessage::Type::kString:
Brian Silvermana7234c62014-03-24 20:23:25 -0700163 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
Brian Silverman88471dc2014-02-15 22:35:42 -0800164 static_cast<int>(message.message_length), message.message);
165 break;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700166 case LogMessage::Type::kStruct: {
Brian Silvermanbe858a12014-04-30 17:37:28 -0700167 char buffer[2048];
Brian Silverman88471dc2014-02-15 22:35:42 -0800168 size_t output_length = sizeof(buffer);
169 size_t input_length = message.message_length;
170 if (!PrintMessage(
171 buffer, &output_length,
172 message.structure.serialized + message.structure.string_length,
173 &input_length, type_cache::Get(message.structure.type_id))) {
174 LOG(FATAL,
175 "printing message (%.*s) of type %s into %zu-byte buffer failed\n",
176 static_cast<int>(message.message_length), message.message,
177 type_cache::Get(message.structure.type_id).name.c_str(),
178 sizeof(buffer));
179 }
180 if (input_length > 0) {
181 LOG(WARNING, "%zu extra bytes on message of type %s\n", input_length,
182 type_cache::Get(message.structure.type_id).name.c_str());
183 }
Brian Silvermana7234c62014-03-24 20:23:25 -0700184 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
Brian Silvermanb263d302014-02-16 00:01:43 -0800185 static_cast<int>(message.structure.string_length),
186 message.structure.serialized,
187 static_cast<int>(sizeof(buffer) - output_length), buffer);
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700188 } break;
189 case LogMessage::Type::kMatrix: {
190 char buffer[1024];
191 size_t output_length = sizeof(buffer);
192 if (message.message_length !=
193 static_cast<size_t>(message.matrix.rows * message.matrix.cols *
194 MessageType::Sizeof(message.matrix.type))) {
195 LOG(FATAL, "expected %d bytes of matrix data but have %zu\n",
196 message.matrix.rows * message.matrix.cols *
197 MessageType::Sizeof(message.matrix.type),
198 message.message_length);
199 }
200 if (!PrintMatrix(buffer, &output_length,
201 message.matrix.data + message.matrix.string_length,
202 message.matrix.type, message.matrix.rows,
203 message.matrix.cols)) {
204 LOG(FATAL, "printing %dx%d matrix of type %" PRIu32 " failed\n",
205 message.matrix.rows, message.matrix.cols, message.matrix.type);
206 }
Brian Silvermana7234c62014-03-24 20:23:25 -0700207 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700208 static_cast<int>(message.matrix.string_length),
Brian Silverman664db1a2014-03-20 17:06:29 -0700209 message.matrix.data,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700210 static_cast<int>(sizeof(buffer) - output_length), buffer);
211 } break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800212 }
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800213#undef BASE_ARGS
Brian Silvermanf665d692013-02-17 22:11:39 -0800214}
215
216} // namespace internal
217
Brian Silverman669669f2014-02-14 16:32:56 -0800218void LogImplementation::LogStruct(
219 log_level level, const ::std::string &message, size_t size,
220 const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
221 char serialized[1024];
222 if (size > sizeof(serialized)) {
223 LOG(FATAL, "structure of type %s too big to serialize\n",
224 type->name.c_str());
225 }
226 size_t used = serialize(serialized);
Brian Silverman2508c082014-02-17 15:45:02 -0800227 char printed[1024];
Brian Silverman669669f2014-02-14 16:32:56 -0800228 size_t printed_bytes = sizeof(printed);
229 if (!PrintMessage(printed, &printed_bytes, serialized, &used, *type)) {
230 LOG(FATAL, "PrintMessage(%p, %p(=%zd), %p, %p(=%zd), %p(name=%s)) failed\n",
231 printed, &printed_bytes, printed_bytes, serialized, &used, used, type,
232 type->name.c_str());
233 }
234 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
Brian Silverman1c7b8192014-02-16 22:37:36 -0800235 message.data(),
236 static_cast<int>(sizeof(printed) - printed_bytes), printed);
Brian Silverman669669f2014-02-14 16:32:56 -0800237}
238
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700239void LogImplementation::LogMatrix(
240 log_level level, const ::std::string &message, uint32_t type_id,
241 int rows, int cols, const void *data) {
242 char serialized[1024];
243 if (static_cast<size_t>(rows * cols * MessageType::Sizeof(type_id)) >
244 sizeof(serialized)) {
245 LOG(FATAL, "matrix of size %u too big to serialize\n",
246 rows * cols * MessageType::Sizeof(type_id));
247 }
248 SerializeMatrix(type_id, serialized, data, rows, cols);
249 char printed[1024];
250 size_t printed_bytes = sizeof(printed);
251 if (!PrintMatrix(printed, &printed_bytes, serialized, type_id, rows, cols)) {
252 LOG(FATAL, "PrintMatrix(%p, %p(=%zd), %p, %" PRIu32 ", %d, %d) failed\n",
253 printed, &printed_bytes, printed_bytes, serialized, type_id, rows,
254 cols);
255 }
256 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
257 message.data(),
258 static_cast<int>(sizeof(printed) - printed_bytes), printed);
259}
260
Brian Silvermanbe858a12014-04-30 17:37:28 -0700261void HandleMessageLogImplementation::DoLog(log_level level, const char *format,
262 va_list ap) {
263 LogMessage message;
264 internal::FillInMessage(level, format, ap, &message);
265 HandleMessage(message);
266}
267
268void HandleMessageLogImplementation::LogStruct(
269 log_level level, const ::std::string &message_string, size_t size,
270 const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
271 LogMessage message;
272 internal::FillInMessageStructure(level, message_string, size, type, serialize,
273 &message);
274 HandleMessage(message);
275}
276
277void HandleMessageLogImplementation::LogMatrix(
278 log_level level, const ::std::string &message_string, uint32_t type_id,
279 int rows, int cols, const void *data) {
280 LogMessage message;
281 internal::FillInMessageMatrix(level, message_string, type_id, rows, cols,
282 data, &message);
283 HandleMessage(message);
284}
285
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800286StreamLogImplementation::StreamLogImplementation(FILE *stream)
287 : stream_(stream) {}
288
Brian Silvermanbe858a12014-04-30 17:37:28 -0700289void StreamLogImplementation::HandleMessage(const LogMessage &message) {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800290 internal::PrintMessage(stream_, message);
291}
292
Brian Silvermanf665d692013-02-17 22:11:39 -0800293void LogNext(log_level level, const char *format, ...) {
294 va_list ap;
295 va_start(ap, format);
296 LogImplementation::DoVLog(level, format, ap, 2);
297 va_end(ap);
298}
299
300void AddImplementation(LogImplementation *implementation) {
301 Context *context = Context::Get();
302
303 if (implementation->next() != NULL) {
304 LOG(FATAL, "%p already has a next implementation, but it's not"
305 " being used yet\n", implementation);
306 }
307
308 LogImplementation *old = context->implementation;
309 if (old != NULL) {
310 implementation->set_next(old);
311 }
312 SetGlobalImplementation(implementation);
Brian Silverman2e799732014-06-05 21:50:19 -0700313 root_implementation->have_other_implementation();
Brian Silvermanf665d692013-02-17 22:11:39 -0800314}
315
316void Init() {
317 static Once<void> once(DoInit);
318 once.Get();
319}
320
321void Load() {
322 Context::Get();
323}
324
325void Cleanup() {
326 Context::Delete();
327}
328
329} // namespace logging
330} // namespace aos