blob: e7b0a5ec0221957b2e9ccca1a0e8a3491e3c9802 [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 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
28 virtual void DoLog(log_level level, const char *format, va_list ap) {
29 LogMessage message;
30 internal::FillInMessage(level, format, ap, &message);
31 internal::PrintMessage(stderr, message);
32 fputs("root logger got used, see stderr for message\n", stdout);
33 }
34};
35
36void SetGlobalImplementation(LogImplementation *implementation) {
37 Context *context = Context::Get();
38
39 context->implementation = implementation;
Brian Silvermanb0893882014-02-10 14:48:30 -080040 global_top_implementation = implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -080041}
42
Brian Silvermane5d65692013-02-28 15:15:03 -080043void NewContext() {
44 Context::Delete();
45}
46
Brian Silvermanf665d692013-02-17 22:11:39 -080047void *DoInit() {
48 SetGlobalImplementation(new RootLogImplementation());
Brian Silvermane5d65692013-02-28 15:15:03 -080049
Brian Silvermane5d65692013-02-28 15:15:03 -080050 if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/,
51 NewContext /*child*/) != 0) {
52 LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n",
53 NewContext);
54 }
Brian Silvermane5d65692013-02-28 15:15:03 -080055
Brian Silvermanf665d692013-02-17 22:11:39 -080056 return NULL;
57}
58
59} // namespace
60namespace internal {
Brian Silverman88471dc2014-02-15 22:35:42 -080061namespace {
Brian Silvermanf665d692013-02-17 22:11:39 -080062
Brian Silverman88471dc2014-02-15 22:35:42 -080063void FillInMessageBase(log_level level, LogMessage *message) {
Brian Silvermanf665d692013-02-17 22:11:39 -080064 Context *context = Context::Get();
65
Brian Silvermanf665d692013-02-17 22:11:39 -080066 message->level = level;
67 message->source = context->source;
Brian Silverman88471dc2014-02-15 22:35:42 -080068 memcpy(message->name, context->name.c_str(), context->name.size());
69 message->name_length = context->name.size();
Brian Silvermanf665d692013-02-17 22:11:39 -080070
71 time::Time now = time::Time::Now();
72 message->seconds = now.sec();
73 message->nseconds = now.nsec();
74
75 message->sequence = context->sequence++;
76}
77
Brian Silverman88471dc2014-02-15 22:35:42 -080078} // namespace
79
80void FillInMessageStructure(log_level level,
81 const ::std::string &message_string, size_t size,
82 const MessageType *type,
83 const ::std::function<size_t(char *)> &serialize,
84 LogMessage *message) {
85 type_cache::AddShm(type->id);
86 message->structure.type_id = type->id;
87
88 FillInMessageBase(level, message);
89
90 if (message_string.size() + size > sizeof(message->structure.serialized)) {
91 LOG(FATAL, "serialized struct %s (size %zd) and message %s too big\n",
92 type->name.c_str(), size, message_string.c_str());
93 }
94 message->structure.string_length = message_string.size();
95 memcpy(message->structure.serialized, message_string.data(),
96 message->structure.string_length);
97
98 message->message_length = serialize(
99 &message->structure.serialized[message->structure.string_length]);
100 message->type = LogMessage::Type::kStruct;
101}
102
Brian Silverman664db1a2014-03-20 17:06:29 -0700103void FillInMessageMatrix(log_level level,
104 const ::std::string &message_string, uint32_t type_id,
105 int rows, int cols, const void *data,
106 LogMessage *message) {
107 CHECK(MessageType::IsPrimitive(type_id));
108 message->matrix.type = type_id;
109
110 const auto element_size = MessageType::Sizeof(type_id);
111
112 FillInMessageBase(level, message);
113
114 message->message_length = rows * cols * element_size;
115 if (message_string.size() + message->message_length >
116 sizeof(message->matrix.data)) {
117 LOG(FATAL, "%dx%d matrix of type %" PRIu32
118 " (size %u) and message %s is too big\n",
119 rows, cols, type_id, element_size, message_string.c_str());
120 }
121 message->matrix.string_length = message_string.size();
122 memcpy(message->matrix.data, message_string.data(),
123 message->matrix.string_length);
124
125 message->matrix.rows = rows;
126 message->matrix.cols = cols;
127 SerializeMatrix(type_id, &message->matrix.data[message->matrix.string_length],
128 data, rows, cols);
129 message->type = LogMessage::Type::kMatrix;
130}
131
Brian Silverman88471dc2014-02-15 22:35:42 -0800132void FillInMessage(log_level level, const char *format, va_list ap,
133 LogMessage *message) {
134 FillInMessageBase(level, message);
135
136 message->message_length =
137 ExecuteFormat(message->message, sizeof(message->message), format, ap);
138 message->type = LogMessage::Type::kString;
139}
140
Brian Silvermanf665d692013-02-17 22:11:39 -0800141void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silvermana7234c62014-03-24 20:23:25 -0700142#define BASE_ARGS \
143 AOS_LOGGING_BASE_ARGS( \
144 message.name_length, message.name, static_cast<int32_t>(message.source), \
145 message.sequence, message.level, message.seconds, message.nseconds)
146 switch (message.type) {
Brian Silverman88471dc2014-02-15 22:35:42 -0800147 case LogMessage::Type::kString:
Brian Silvermana7234c62014-03-24 20:23:25 -0700148 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
Brian Silverman88471dc2014-02-15 22:35:42 -0800149 static_cast<int>(message.message_length), message.message);
150 break;
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700151 case LogMessage::Type::kStruct: {
Brian Silverman2508c082014-02-17 15:45:02 -0800152 char buffer[1024];
Brian Silverman88471dc2014-02-15 22:35:42 -0800153 size_t output_length = sizeof(buffer);
154 size_t input_length = message.message_length;
155 if (!PrintMessage(
156 buffer, &output_length,
157 message.structure.serialized + message.structure.string_length,
158 &input_length, type_cache::Get(message.structure.type_id))) {
159 LOG(FATAL,
160 "printing message (%.*s) of type %s into %zu-byte buffer failed\n",
161 static_cast<int>(message.message_length), message.message,
162 type_cache::Get(message.structure.type_id).name.c_str(),
163 sizeof(buffer));
164 }
165 if (input_length > 0) {
166 LOG(WARNING, "%zu extra bytes on message of type %s\n", input_length,
167 type_cache::Get(message.structure.type_id).name.c_str());
168 }
Brian Silvermana7234c62014-03-24 20:23:25 -0700169 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
Brian Silvermanb263d302014-02-16 00:01:43 -0800170 static_cast<int>(message.structure.string_length),
171 message.structure.serialized,
172 static_cast<int>(sizeof(buffer) - output_length), buffer);
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700173 } break;
174 case LogMessage::Type::kMatrix: {
175 char buffer[1024];
176 size_t output_length = sizeof(buffer);
177 if (message.message_length !=
178 static_cast<size_t>(message.matrix.rows * message.matrix.cols *
179 MessageType::Sizeof(message.matrix.type))) {
180 LOG(FATAL, "expected %d bytes of matrix data but have %zu\n",
181 message.matrix.rows * message.matrix.cols *
182 MessageType::Sizeof(message.matrix.type),
183 message.message_length);
184 }
185 if (!PrintMatrix(buffer, &output_length,
186 message.matrix.data + message.matrix.string_length,
187 message.matrix.type, message.matrix.rows,
188 message.matrix.cols)) {
189 LOG(FATAL, "printing %dx%d matrix of type %" PRIu32 " failed\n",
190 message.matrix.rows, message.matrix.cols, message.matrix.type);
191 }
Brian Silvermana7234c62014-03-24 20:23:25 -0700192 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700193 static_cast<int>(message.matrix.string_length),
Brian Silverman664db1a2014-03-20 17:06:29 -0700194 message.matrix.data,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700195 static_cast<int>(sizeof(buffer) - output_length), buffer);
196 } break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800197 }
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800198#undef BASE_ARGS
Brian Silvermanf665d692013-02-17 22:11:39 -0800199}
200
201} // namespace internal
202
Brian Silverman669669f2014-02-14 16:32:56 -0800203void LogImplementation::LogStruct(
204 log_level level, const ::std::string &message, size_t size,
205 const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
206 char serialized[1024];
207 if (size > sizeof(serialized)) {
208 LOG(FATAL, "structure of type %s too big to serialize\n",
209 type->name.c_str());
210 }
211 size_t used = serialize(serialized);
Brian Silverman2508c082014-02-17 15:45:02 -0800212 char printed[1024];
Brian Silverman669669f2014-02-14 16:32:56 -0800213 size_t printed_bytes = sizeof(printed);
214 if (!PrintMessage(printed, &printed_bytes, serialized, &used, *type)) {
215 LOG(FATAL, "PrintMessage(%p, %p(=%zd), %p, %p(=%zd), %p(name=%s)) failed\n",
216 printed, &printed_bytes, printed_bytes, serialized, &used, used, type,
217 type->name.c_str());
218 }
219 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
Brian Silverman1c7b8192014-02-16 22:37:36 -0800220 message.data(),
221 static_cast<int>(sizeof(printed) - printed_bytes), printed);
Brian Silverman669669f2014-02-14 16:32:56 -0800222}
223
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700224void LogImplementation::LogMatrix(
225 log_level level, const ::std::string &message, uint32_t type_id,
226 int rows, int cols, const void *data) {
227 char serialized[1024];
228 if (static_cast<size_t>(rows * cols * MessageType::Sizeof(type_id)) >
229 sizeof(serialized)) {
230 LOG(FATAL, "matrix of size %u too big to serialize\n",
231 rows * cols * MessageType::Sizeof(type_id));
232 }
233 SerializeMatrix(type_id, serialized, data, rows, cols);
234 char printed[1024];
235 size_t printed_bytes = sizeof(printed);
236 if (!PrintMatrix(printed, &printed_bytes, serialized, type_id, rows, cols)) {
237 LOG(FATAL, "PrintMatrix(%p, %p(=%zd), %p, %" PRIu32 ", %d, %d) failed\n",
238 printed, &printed_bytes, printed_bytes, serialized, type_id, rows,
239 cols);
240 }
241 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
242 message.data(),
243 static_cast<int>(sizeof(printed) - printed_bytes), printed);
244}
245
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800246StreamLogImplementation::StreamLogImplementation(FILE *stream)
247 : stream_(stream) {}
248
249void StreamLogImplementation::DoLog(log_level level, const char *format,
250 va_list ap) {
251 LogMessage message;
252 internal::FillInMessage(level, format, ap, &message);
253 internal::PrintMessage(stream_, message);
254}
255
Brian Silvermanf665d692013-02-17 22:11:39 -0800256void LogNext(log_level level, const char *format, ...) {
257 va_list ap;
258 va_start(ap, format);
259 LogImplementation::DoVLog(level, format, ap, 2);
260 va_end(ap);
261}
262
263void AddImplementation(LogImplementation *implementation) {
264 Context *context = Context::Get();
265
266 if (implementation->next() != NULL) {
267 LOG(FATAL, "%p already has a next implementation, but it's not"
268 " being used yet\n", implementation);
269 }
270
271 LogImplementation *old = context->implementation;
272 if (old != NULL) {
273 implementation->set_next(old);
274 }
275 SetGlobalImplementation(implementation);
276}
277
278void Init() {
279 static Once<void> once(DoInit);
280 once.Get();
281}
282
283void Load() {
284 Context::Get();
285}
286
287void Cleanup() {
288 Context::Delete();
289}
290
291} // namespace logging
292} // namespace aos