blob: b74b69dfd8d8cf814ecbfe260cb652025fe2803e [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"
7#include "aos/common/inttypes.h"
8#include "aos/common/once.h"
Brian Silverman669669f2014-02-14 16:32:56 -08009#include "aos/common/queue_types.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 {
23 virtual void set_next(LogImplementation *) {
24 LOG(FATAL, "can't have a next logger from here\n");
25 }
26
27 virtual void DoLog(log_level level, const char *format, va_list ap) {
28 LogMessage message;
29 internal::FillInMessage(level, format, ap, &message);
30 internal::PrintMessage(stderr, message);
31 fputs("root logger got used, see stderr for message\n", stdout);
32 }
33};
34
35void SetGlobalImplementation(LogImplementation *implementation) {
36 Context *context = Context::Get();
37
38 context->implementation = implementation;
Brian Silvermanb0893882014-02-10 14:48:30 -080039 global_top_implementation = implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -080040}
41
Brian Silvermane5d65692013-02-28 15:15:03 -080042void NewContext() {
43 Context::Delete();
44}
45
Brian Silvermanf665d692013-02-17 22:11:39 -080046void *DoInit() {
47 SetGlobalImplementation(new RootLogImplementation());
Brian Silvermane5d65692013-02-28 15:15:03 -080048
Brian Silvermane5d65692013-02-28 15:15:03 -080049 if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/,
50 NewContext /*child*/) != 0) {
51 LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n",
52 NewContext);
53 }
Brian Silvermane5d65692013-02-28 15:15:03 -080054
Brian Silvermanf665d692013-02-17 22:11:39 -080055 return NULL;
56}
57
58} // namespace
59namespace internal {
Brian Silverman88471dc2014-02-15 22:35:42 -080060namespace {
Brian Silvermanf665d692013-02-17 22:11:39 -080061
Brian Silverman88471dc2014-02-15 22:35:42 -080062void FillInMessageBase(log_level level, LogMessage *message) {
Brian Silvermanf665d692013-02-17 22:11:39 -080063 Context *context = Context::Get();
64
Brian Silvermanf665d692013-02-17 22:11:39 -080065 message->level = level;
66 message->source = context->source;
Brian Silverman88471dc2014-02-15 22:35:42 -080067 memcpy(message->name, context->name.c_str(), context->name.size());
68 message->name_length = context->name.size();
Brian Silvermanf665d692013-02-17 22:11:39 -080069
70 time::Time now = time::Time::Now();
71 message->seconds = now.sec();
72 message->nseconds = now.nsec();
73
74 message->sequence = context->sequence++;
75}
76
Brian Silverman88471dc2014-02-15 22:35:42 -080077} // namespace
78
79void FillInMessageStructure(log_level level,
80 const ::std::string &message_string, size_t size,
81 const MessageType *type,
82 const ::std::function<size_t(char *)> &serialize,
83 LogMessage *message) {
84 type_cache::AddShm(type->id);
85 message->structure.type_id = type->id;
86
87 FillInMessageBase(level, message);
88
89 if (message_string.size() + size > sizeof(message->structure.serialized)) {
90 LOG(FATAL, "serialized struct %s (size %zd) and message %s too big\n",
91 type->name.c_str(), size, message_string.c_str());
92 }
93 message->structure.string_length = message_string.size();
94 memcpy(message->structure.serialized, message_string.data(),
95 message->structure.string_length);
96
97 message->message_length = serialize(
98 &message->structure.serialized[message->structure.string_length]);
99 message->type = LogMessage::Type::kStruct;
100}
101
Brian Silverman664db1a2014-03-20 17:06:29 -0700102void FillInMessageMatrix(log_level level,
103 const ::std::string &message_string, uint32_t type_id,
104 int rows, int cols, const void *data,
105 LogMessage *message) {
106 CHECK(MessageType::IsPrimitive(type_id));
107 message->matrix.type = type_id;
108
109 const auto element_size = MessageType::Sizeof(type_id);
110
111 FillInMessageBase(level, message);
112
113 message->message_length = rows * cols * element_size;
114 if (message_string.size() + message->message_length >
115 sizeof(message->matrix.data)) {
116 LOG(FATAL, "%dx%d matrix of type %" PRIu32
117 " (size %u) and message %s is too big\n",
118 rows, cols, type_id, element_size, message_string.c_str());
119 }
120 message->matrix.string_length = message_string.size();
121 memcpy(message->matrix.data, message_string.data(),
122 message->matrix.string_length);
123
124 message->matrix.rows = rows;
125 message->matrix.cols = cols;
126 SerializeMatrix(type_id, &message->matrix.data[message->matrix.string_length],
127 data, rows, cols);
128 message->type = LogMessage::Type::kMatrix;
129}
130
Brian Silverman88471dc2014-02-15 22:35:42 -0800131void FillInMessage(log_level level, const char *format, va_list ap,
132 LogMessage *message) {
133 FillInMessageBase(level, message);
134
135 message->message_length =
136 ExecuteFormat(message->message, sizeof(message->message), format, ap);
137 message->type = LogMessage::Type::kString;
138}
139
Brian Silvermanf665d692013-02-17 22:11:39 -0800140void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800141#define NSECONDS_DIGITS 5
142#define BASE_FORMAT \
Brian Silverman6c3ee992014-02-21 09:27:50 -0800143 "%.*s(%" PRId32 ")(%05" PRIu16 "): %-7s at %010" PRId32 \
Brian Silverman05f27832014-02-25 13:30:22 -0800144 ".%0" STRINGIFY(NSECONDS_DIGITS) PRId32 "s: "
Brian Silverman88471dc2014-02-15 22:35:42 -0800145#define BASE_ARGS \
146 static_cast<int>(message.name_length), message.name, \
147 static_cast<int32_t>(message.source), message.sequence, \
Brian Silverman6c3ee992014-02-21 09:27:50 -0800148 log_str(message.level), message.seconds, (message.nseconds + 5000) / 10000
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800149 switch (message.type) {
Brian Silverman88471dc2014-02-15 22:35:42 -0800150 case LogMessage::Type::kString:
151 fprintf(output, BASE_FORMAT "%.*s", BASE_ARGS,
152 static_cast<int>(message.message_length), message.message);
153 break;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700154 case LogMessage::Type::kStruct: {
Brian Silverman2508c082014-02-17 15:45:02 -0800155 char buffer[1024];
Brian Silverman88471dc2014-02-15 22:35:42 -0800156 size_t output_length = sizeof(buffer);
157 size_t input_length = message.message_length;
158 if (!PrintMessage(
159 buffer, &output_length,
160 message.structure.serialized + message.structure.string_length,
161 &input_length, type_cache::Get(message.structure.type_id))) {
162 LOG(FATAL,
163 "printing message (%.*s) of type %s into %zu-byte buffer failed\n",
164 static_cast<int>(message.message_length), message.message,
165 type_cache::Get(message.structure.type_id).name.c_str(),
166 sizeof(buffer));
167 }
168 if (input_length > 0) {
169 LOG(WARNING, "%zu extra bytes on message of type %s\n", input_length,
170 type_cache::Get(message.structure.type_id).name.c_str());
171 }
172 fprintf(output, BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
Brian Silvermanb263d302014-02-16 00:01:43 -0800173 static_cast<int>(message.structure.string_length),
174 message.structure.serialized,
175 static_cast<int>(sizeof(buffer) - output_length), buffer);
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700176 } break;
177 case LogMessage::Type::kMatrix: {
178 char buffer[1024];
179 size_t output_length = sizeof(buffer);
180 if (message.message_length !=
181 static_cast<size_t>(message.matrix.rows * message.matrix.cols *
182 MessageType::Sizeof(message.matrix.type))) {
183 LOG(FATAL, "expected %d bytes of matrix data but have %zu\n",
184 message.matrix.rows * message.matrix.cols *
185 MessageType::Sizeof(message.matrix.type),
186 message.message_length);
187 }
188 if (!PrintMatrix(buffer, &output_length,
189 message.matrix.data + message.matrix.string_length,
190 message.matrix.type, message.matrix.rows,
191 message.matrix.cols)) {
192 LOG(FATAL, "printing %dx%d matrix of type %" PRIu32 " failed\n",
193 message.matrix.rows, message.matrix.cols, message.matrix.type);
194 }
195 fprintf(output, BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
196 static_cast<int>(message.matrix.string_length),
Brian Silverman664db1a2014-03-20 17:06:29 -0700197 message.matrix.data,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700198 static_cast<int>(sizeof(buffer) - output_length), buffer);
199 } break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800200 }
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800201#undef NSECONDS_DIGITS
202#undef BASE_FORMAT
203#undef BASE_ARGS
Brian Silvermanf665d692013-02-17 22:11:39 -0800204}
205
206} // namespace internal
207
Brian Silverman669669f2014-02-14 16:32:56 -0800208void LogImplementation::LogStruct(
209 log_level level, const ::std::string &message, size_t size,
210 const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
211 char serialized[1024];
212 if (size > sizeof(serialized)) {
213 LOG(FATAL, "structure of type %s too big to serialize\n",
214 type->name.c_str());
215 }
216 size_t used = serialize(serialized);
Brian Silverman2508c082014-02-17 15:45:02 -0800217 char printed[1024];
Brian Silverman669669f2014-02-14 16:32:56 -0800218 size_t printed_bytes = sizeof(printed);
219 if (!PrintMessage(printed, &printed_bytes, serialized, &used, *type)) {
220 LOG(FATAL, "PrintMessage(%p, %p(=%zd), %p, %p(=%zd), %p(name=%s)) failed\n",
221 printed, &printed_bytes, printed_bytes, serialized, &used, used, type,
222 type->name.c_str());
223 }
224 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
Brian Silverman1c7b8192014-02-16 22:37:36 -0800225 message.data(),
226 static_cast<int>(sizeof(printed) - printed_bytes), printed);
Brian Silverman669669f2014-02-14 16:32:56 -0800227}
228
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700229void LogImplementation::LogMatrix(
230 log_level level, const ::std::string &message, uint32_t type_id,
231 int rows, int cols, const void *data) {
232 char serialized[1024];
233 if (static_cast<size_t>(rows * cols * MessageType::Sizeof(type_id)) >
234 sizeof(serialized)) {
235 LOG(FATAL, "matrix of size %u too big to serialize\n",
236 rows * cols * MessageType::Sizeof(type_id));
237 }
238 SerializeMatrix(type_id, serialized, data, rows, cols);
239 char printed[1024];
240 size_t printed_bytes = sizeof(printed);
241 if (!PrintMatrix(printed, &printed_bytes, serialized, type_id, rows, cols)) {
242 LOG(FATAL, "PrintMatrix(%p, %p(=%zd), %p, %" PRIu32 ", %d, %d) failed\n",
243 printed, &printed_bytes, printed_bytes, serialized, type_id, rows,
244 cols);
245 }
246 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
247 message.data(),
248 static_cast<int>(sizeof(printed) - printed_bytes), printed);
249}
250
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800251StreamLogImplementation::StreamLogImplementation(FILE *stream)
252 : stream_(stream) {}
253
254void StreamLogImplementation::DoLog(log_level level, const char *format,
255 va_list ap) {
256 LogMessage message;
257 internal::FillInMessage(level, format, ap, &message);
258 internal::PrintMessage(stream_, message);
259}
260
Brian Silvermanf665d692013-02-17 22:11:39 -0800261void LogNext(log_level level, const char *format, ...) {
262 va_list ap;
263 va_start(ap, format);
264 LogImplementation::DoVLog(level, format, ap, 2);
265 va_end(ap);
266}
267
268void AddImplementation(LogImplementation *implementation) {
269 Context *context = Context::Get();
270
271 if (implementation->next() != NULL) {
272 LOG(FATAL, "%p already has a next implementation, but it's not"
273 " being used yet\n", implementation);
274 }
275
276 LogImplementation *old = context->implementation;
277 if (old != NULL) {
278 implementation->set_next(old);
279 }
280 SetGlobalImplementation(implementation);
281}
282
283void Init() {
284 static Once<void> once(DoInit);
285 once.Get();
286}
287
288void Load() {
289 Context::Get();
290}
291
292void Cleanup() {
293 Context::Delete();
294}
295
296} // namespace logging
297} // namespace aos