blob: f520b356d14e161b0094608ab8ef1732996fa298 [file] [log] [blame]
Brian Silvermanf665d692013-02-17 22:11:39 -08001#include "aos/common/logging/logging_impl.h"
2
3#include <assert.h>
Brian Silvermanb0893882014-02-10 14:48:30 -08004#include <stdarg.h>
Brian Silvermanf665d692013-02-17 22:11:39 -08005
Brian Silvermanf665d692013-02-17 22:11:39 -08006#include "aos/common/time.h"
Brian4a424a22014-04-02 11:52:45 -07007#include <inttypes.h>
Brian Silvermanf665d692013-02-17 22:11:39 -08008#include "aos/common/once.h"
Brian Silverman669669f2014-02-14 16:32:56 -08009#include "aos/common/queue_types.h"
Brian Silvermana7234c62014-03-24 20:23:25 -070010#include "aos/common/logging/logging_printf_formats.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080011
12namespace aos {
13namespace logging {
14namespace {
15
16using internal::Context;
Brian Silvermanb0893882014-02-10 14:48:30 -080017using internal::global_top_implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -080018
Brian Silvermanf665d692013-02-17 22:11:39 -080019// The root LogImplementation. It only logs to stderr/stdout.
20// Some of the things specified in the LogImplementation documentation doesn't
21// apply here (mostly the parts about being able to use LOG) because this is the
22// root one.
23class RootLogImplementation : public LogImplementation {
24 virtual void set_next(LogImplementation *) {
25 LOG(FATAL, "can't have a next logger from here\n");
26 }
27
Brian Silvermanf7986142014-04-21 17:42:35 -070028 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silvermanf665d692013-02-17 22:11:39 -080029 virtual void DoLog(log_level level, const char *format, va_list ap) {
30 LogMessage message;
31 internal::FillInMessage(level, format, ap, &message);
32 internal::PrintMessage(stderr, message);
33 fputs("root logger got used, see stderr for message\n", stdout);
34 }
35};
36
37void SetGlobalImplementation(LogImplementation *implementation) {
38 Context *context = Context::Get();
39
40 context->implementation = implementation;
Brian Silvermanb0893882014-02-10 14:48:30 -080041 global_top_implementation = implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -080042}
43
Brian Silvermane5d65692013-02-28 15:15:03 -080044void NewContext() {
45 Context::Delete();
46}
47
Brian Silvermanf665d692013-02-17 22:11:39 -080048void *DoInit() {
49 SetGlobalImplementation(new RootLogImplementation());
Brian Silvermane5d65692013-02-28 15:15:03 -080050
Brian Silvermane5d65692013-02-28 15:15:03 -080051 if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/,
52 NewContext /*child*/) != 0) {
53 LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n",
54 NewContext);
55 }
Brian Silvermane5d65692013-02-28 15:15:03 -080056
Brian Silvermanf665d692013-02-17 22:11:39 -080057 return NULL;
58}
59
60} // namespace
61namespace internal {
Brian Silverman88471dc2014-02-15 22:35:42 -080062namespace {
Brian Silvermanf665d692013-02-17 22:11:39 -080063
Brian Silverman88471dc2014-02-15 22:35:42 -080064void FillInMessageBase(log_level level, LogMessage *message) {
Brian Silvermanf665d692013-02-17 22:11:39 -080065 Context *context = Context::Get();
66
Brian Silvermanf665d692013-02-17 22:11:39 -080067 message->level = level;
68 message->source = context->source;
Brian Silverman88471dc2014-02-15 22:35:42 -080069 memcpy(message->name, context->name.c_str(), context->name.size());
70 message->name_length = context->name.size();
Brian Silvermanf665d692013-02-17 22:11:39 -080071
72 time::Time now = time::Time::Now();
73 message->seconds = now.sec();
74 message->nseconds = now.nsec();
75
76 message->sequence = context->sequence++;
77}
78
Brian Silverman88471dc2014-02-15 22:35:42 -080079} // namespace
80
81void FillInMessageStructure(log_level level,
82 const ::std::string &message_string, size_t size,
83 const MessageType *type,
84 const ::std::function<size_t(char *)> &serialize,
85 LogMessage *message) {
86 type_cache::AddShm(type->id);
87 message->structure.type_id = type->id;
88
89 FillInMessageBase(level, message);
90
91 if (message_string.size() + size > sizeof(message->structure.serialized)) {
92 LOG(FATAL, "serialized struct %s (size %zd) and message %s too big\n",
93 type->name.c_str(), size, message_string.c_str());
94 }
95 message->structure.string_length = message_string.size();
96 memcpy(message->structure.serialized, message_string.data(),
97 message->structure.string_length);
98
99 message->message_length = serialize(
100 &message->structure.serialized[message->structure.string_length]);
101 message->type = LogMessage::Type::kStruct;
102}
103
Brian Silverman664db1a2014-03-20 17:06:29 -0700104void FillInMessageMatrix(log_level level,
105 const ::std::string &message_string, uint32_t type_id,
106 int rows, int cols, const void *data,
107 LogMessage *message) {
108 CHECK(MessageType::IsPrimitive(type_id));
109 message->matrix.type = type_id;
110
111 const auto element_size = MessageType::Sizeof(type_id);
112
113 FillInMessageBase(level, message);
114
115 message->message_length = rows * cols * element_size;
116 if (message_string.size() + message->message_length >
117 sizeof(message->matrix.data)) {
118 LOG(FATAL, "%dx%d matrix of type %" PRIu32
119 " (size %u) and message %s is too big\n",
120 rows, cols, type_id, element_size, message_string.c_str());
121 }
122 message->matrix.string_length = message_string.size();
123 memcpy(message->matrix.data, message_string.data(),
124 message->matrix.string_length);
125
126 message->matrix.rows = rows;
127 message->matrix.cols = cols;
128 SerializeMatrix(type_id, &message->matrix.data[message->matrix.string_length],
129 data, rows, cols);
130 message->type = LogMessage::Type::kMatrix;
131}
132
Brian Silverman88471dc2014-02-15 22:35:42 -0800133void FillInMessage(log_level level, const char *format, va_list ap,
134 LogMessage *message) {
135 FillInMessageBase(level, message);
136
137 message->message_length =
138 ExecuteFormat(message->message, sizeof(message->message), format, ap);
139 message->type = LogMessage::Type::kString;
140}
141
Brian Silvermanf665d692013-02-17 22:11:39 -0800142void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silvermana7234c62014-03-24 20:23:25 -0700143#define BASE_ARGS \
144 AOS_LOGGING_BASE_ARGS( \
145 message.name_length, message.name, static_cast<int32_t>(message.source), \
146 message.sequence, message.level, message.seconds, message.nseconds)
147 switch (message.type) {
Brian Silverman88471dc2014-02-15 22:35:42 -0800148 case LogMessage::Type::kString:
Brian Silvermana7234c62014-03-24 20:23:25 -0700149 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
Brian Silverman88471dc2014-02-15 22:35:42 -0800150 static_cast<int>(message.message_length), message.message);
151 break;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700152 case LogMessage::Type::kStruct: {
Brian Silvermanbe858a12014-04-30 17:37:28 -0700153 char buffer[2048];
Brian Silverman88471dc2014-02-15 22:35:42 -0800154 size_t output_length = sizeof(buffer);
155 size_t input_length = message.message_length;
156 if (!PrintMessage(
157 buffer, &output_length,
158 message.structure.serialized + message.structure.string_length,
159 &input_length, type_cache::Get(message.structure.type_id))) {
160 LOG(FATAL,
161 "printing message (%.*s) of type %s into %zu-byte buffer failed\n",
162 static_cast<int>(message.message_length), message.message,
163 type_cache::Get(message.structure.type_id).name.c_str(),
164 sizeof(buffer));
165 }
166 if (input_length > 0) {
167 LOG(WARNING, "%zu extra bytes on message of type %s\n", input_length,
168 type_cache::Get(message.structure.type_id).name.c_str());
169 }
Brian Silvermana7234c62014-03-24 20:23:25 -0700170 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
Brian Silvermanb263d302014-02-16 00:01:43 -0800171 static_cast<int>(message.structure.string_length),
172 message.structure.serialized,
173 static_cast<int>(sizeof(buffer) - output_length), buffer);
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700174 } break;
175 case LogMessage::Type::kMatrix: {
176 char buffer[1024];
177 size_t output_length = sizeof(buffer);
178 if (message.message_length !=
179 static_cast<size_t>(message.matrix.rows * message.matrix.cols *
180 MessageType::Sizeof(message.matrix.type))) {
181 LOG(FATAL, "expected %d bytes of matrix data but have %zu\n",
182 message.matrix.rows * message.matrix.cols *
183 MessageType::Sizeof(message.matrix.type),
184 message.message_length);
185 }
186 if (!PrintMatrix(buffer, &output_length,
187 message.matrix.data + message.matrix.string_length,
188 message.matrix.type, message.matrix.rows,
189 message.matrix.cols)) {
190 LOG(FATAL, "printing %dx%d matrix of type %" PRIu32 " failed\n",
191 message.matrix.rows, message.matrix.cols, message.matrix.type);
192 }
Brian Silvermana7234c62014-03-24 20:23:25 -0700193 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700194 static_cast<int>(message.matrix.string_length),
Brian Silverman664db1a2014-03-20 17:06:29 -0700195 message.matrix.data,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700196 static_cast<int>(sizeof(buffer) - output_length), buffer);
197 } break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800198 }
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800199#undef BASE_ARGS
Brian Silvermanf665d692013-02-17 22:11:39 -0800200}
201
202} // namespace internal
203
Brian Silverman669669f2014-02-14 16:32:56 -0800204void LogImplementation::LogStruct(
205 log_level level, const ::std::string &message, size_t size,
206 const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
207 char serialized[1024];
208 if (size > sizeof(serialized)) {
209 LOG(FATAL, "structure of type %s too big to serialize\n",
210 type->name.c_str());
211 }
212 size_t used = serialize(serialized);
Brian Silverman2508c082014-02-17 15:45:02 -0800213 char printed[1024];
Brian Silverman669669f2014-02-14 16:32:56 -0800214 size_t printed_bytes = sizeof(printed);
215 if (!PrintMessage(printed, &printed_bytes, serialized, &used, *type)) {
216 LOG(FATAL, "PrintMessage(%p, %p(=%zd), %p, %p(=%zd), %p(name=%s)) failed\n",
217 printed, &printed_bytes, printed_bytes, serialized, &used, used, type,
218 type->name.c_str());
219 }
220 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
Brian Silverman1c7b8192014-02-16 22:37:36 -0800221 message.data(),
222 static_cast<int>(sizeof(printed) - printed_bytes), printed);
Brian Silverman669669f2014-02-14 16:32:56 -0800223}
224
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700225void LogImplementation::LogMatrix(
226 log_level level, const ::std::string &message, uint32_t type_id,
227 int rows, int cols, const void *data) {
228 char serialized[1024];
229 if (static_cast<size_t>(rows * cols * MessageType::Sizeof(type_id)) >
230 sizeof(serialized)) {
231 LOG(FATAL, "matrix of size %u too big to serialize\n",
232 rows * cols * MessageType::Sizeof(type_id));
233 }
234 SerializeMatrix(type_id, serialized, data, rows, cols);
235 char printed[1024];
236 size_t printed_bytes = sizeof(printed);
237 if (!PrintMatrix(printed, &printed_bytes, serialized, type_id, rows, cols)) {
238 LOG(FATAL, "PrintMatrix(%p, %p(=%zd), %p, %" PRIu32 ", %d, %d) failed\n",
239 printed, &printed_bytes, printed_bytes, serialized, type_id, rows,
240 cols);
241 }
242 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
243 message.data(),
244 static_cast<int>(sizeof(printed) - printed_bytes), printed);
245}
246
Brian Silvermanbe858a12014-04-30 17:37:28 -0700247void HandleMessageLogImplementation::DoLog(log_level level, const char *format,
248 va_list ap) {
249 LogMessage message;
250 internal::FillInMessage(level, format, ap, &message);
251 HandleMessage(message);
252}
253
254void HandleMessageLogImplementation::LogStruct(
255 log_level level, const ::std::string &message_string, size_t size,
256 const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
257 LogMessage message;
258 internal::FillInMessageStructure(level, message_string, size, type, serialize,
259 &message);
260 HandleMessage(message);
261}
262
263void HandleMessageLogImplementation::LogMatrix(
264 log_level level, const ::std::string &message_string, uint32_t type_id,
265 int rows, int cols, const void *data) {
266 LogMessage message;
267 internal::FillInMessageMatrix(level, message_string, type_id, rows, cols,
268 data, &message);
269 HandleMessage(message);
270}
271
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800272StreamLogImplementation::StreamLogImplementation(FILE *stream)
273 : stream_(stream) {}
274
Brian Silvermanbe858a12014-04-30 17:37:28 -0700275void StreamLogImplementation::HandleMessage(const LogMessage &message) {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800276 internal::PrintMessage(stream_, message);
277}
278
Brian Silvermanf665d692013-02-17 22:11:39 -0800279void LogNext(log_level level, const char *format, ...) {
280 va_list ap;
281 va_start(ap, format);
282 LogImplementation::DoVLog(level, format, ap, 2);
283 va_end(ap);
284}
285
286void AddImplementation(LogImplementation *implementation) {
287 Context *context = Context::Get();
288
289 if (implementation->next() != NULL) {
290 LOG(FATAL, "%p already has a next implementation, but it's not"
291 " being used yet\n", implementation);
292 }
293
294 LogImplementation *old = context->implementation;
295 if (old != NULL) {
296 implementation->set_next(old);
297 }
298 SetGlobalImplementation(implementation);
299}
300
301void Init() {
302 static Once<void> once(DoInit);
303 once.Get();
304}
305
306void Load() {
307 Context::Get();
308}
309
310void Cleanup() {
311 Context::Delete();
312}
313
314} // namespace logging
315} // namespace aos