blob: 2220e4e645e933e0d6fba583b1d5eba305e53ae1 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/logging/implementations.h"
Brian Silvermanf665d692013-02-17 22:11:39 -08002
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 Silvermancb5da1f2015-12-05 22:19:58 -05006#include <algorithm>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08007#include <chrono>
Brian Silvermancb5da1f2015-12-05 22:19:58 -05008
John Park33858a32018-09-28 23:05:48 -07009#include "aos/die.h"
10#include "aos/logging/printf_formats.h"
John Park33858a32018-09-28 23:05:48 -070011#include "aos/time/time.h"
John Park398c74a2018-10-20 21:17:39 -070012#include "aos/ipc_lib/queue.h"
Sabina Davis2ed5ea22017-09-26 22:27:42 -070013#include "aos/once.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080014
15namespace aos {
16namespace logging {
17namespace {
18
Austin Schuhf2a50ba2016-12-24 16:16:26 -080019namespace chrono = ::std::chrono;
20
Brian Silvermanf665d692013-02-17 22:11:39 -080021// The root LogImplementation. It only logs to stderr/stdout.
22// Some of the things specified in the LogImplementation documentation doesn't
Austin Schuhf257f3c2019-10-27 21:00:43 -070023// apply here (mostly the parts about being able to use AOS_LOG) because this is
24// the root one.
Alex Perrycb7da4b2019-08-28 19:35:56 -070025class RootLogImplementation : public LogImplementation {
Brian Silverman2e799732014-06-05 21:50:19 -070026 public:
27 void have_other_implementation() { only_implementation_ = false; }
28
Alex Perrycb7da4b2019-08-28 19:35:56 -070029 protected:
30 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
31 return ::aos::monotonic_clock::now();
32 }
33
Brian Silverman2e799732014-06-05 21:50:19 -070034 private:
Brian Silvermancb5da1f2015-12-05 22:19:58 -050035 void set_next(LogImplementation *) override {
Austin Schuhf257f3c2019-10-27 21:00:43 -070036 AOS_LOG(FATAL, "can't have a next logger from here\n");
Brian Silvermanf665d692013-02-17 22:11:39 -080037 }
38
Brian Silvermanf7986142014-04-21 17:42:35 -070039 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silvermancb5da1f2015-12-05 22:19:58 -050040 void DoLog(log_level level, const char *format, va_list ap) override {
Brian Silvermanf665d692013-02-17 22:11:39 -080041 LogMessage message;
Austin Schuh82c0c822019-05-27 19:55:20 -070042 internal::FillInMessage(level, monotonic_now(), format, ap, &message);
Brian Silvermanf665d692013-02-17 22:11:39 -080043 internal::PrintMessage(stderr, message);
Brian Silverman2e799732014-06-05 21:50:19 -070044 if (!only_implementation_) {
45 fputs("root logger got used, see stderr for message\n", stdout);
46 }
Brian Silvermanf665d692013-02-17 22:11:39 -080047 }
Brian Silverman2e799732014-06-05 21:50:19 -070048
49 bool only_implementation_ = true;
Brian Silvermanf665d692013-02-17 22:11:39 -080050};
51
Brian Silverman2e799732014-06-05 21:50:19 -070052RootLogImplementation *root_implementation = nullptr;
53
Brian Silvermanf665d692013-02-17 22:11:39 -080054void SetGlobalImplementation(LogImplementation *implementation) {
Brian Silverman5c201e22014-06-12 22:40:28 -070055 if (root_implementation == nullptr) {
56 fputs("Somebody didn't call logging::Init()!\n", stderr);
57 abort();
58 }
59
Brian Silvermancb5da1f2015-12-05 22:19:58 -050060 internal::Context *context = internal::Context::Get();
Brian Silvermanf665d692013-02-17 22:11:39 -080061
62 context->implementation = implementation;
Brian Silvermancb5da1f2015-12-05 22:19:58 -050063 internal::global_top_implementation.store(implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -080064}
65
Brian Silvermane5d65692013-02-28 15:15:03 -080066void NewContext() {
Brian Silvermancb5da1f2015-12-05 22:19:58 -050067 internal::Context::Delete();
Brian Silvermane5d65692013-02-28 15:15:03 -080068}
69
Brian Silvermanf665d692013-02-17 22:11:39 -080070void *DoInit() {
Brian Silverman2e799732014-06-05 21:50:19 -070071 SetGlobalImplementation(root_implementation = new RootLogImplementation());
Brian Silvermane5d65692013-02-28 15:15:03 -080072
Brian Silvermane5d65692013-02-28 15:15:03 -080073 if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/,
74 NewContext /*child*/) != 0) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070075 AOS_LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n", NewContext);
Brian Silvermane5d65692013-02-28 15:15:03 -080076 }
Brian Silvermane5d65692013-02-28 15:15:03 -080077
Brian Silvermanf665d692013-02-17 22:11:39 -080078 return NULL;
79}
80
81} // namespace
82namespace internal {
Brian Silverman88471dc2014-02-15 22:35:42 -080083namespace {
Brian Silvermanf665d692013-02-17 22:11:39 -080084
Austin Schuh82c0c822019-05-27 19:55:20 -070085void FillInMessageBase(log_level level,
86 monotonic_clock::time_point monotonic_now,
87 LogMessage *message) {
Brian Silvermanf665d692013-02-17 22:11:39 -080088 Context *context = Context::Get();
89
Brian Silvermanf665d692013-02-17 22:11:39 -080090 message->level = level;
91 message->source = context->source;
Austin Schuhaebbc342015-01-25 02:25:13 -080092 memcpy(message->name, context->name, context->name_size);
93 message->name_length = context->name_size;
Brian Silvermanf665d692013-02-17 22:11:39 -080094
Austin Schuhf2a50ba2016-12-24 16:16:26 -080095 message->seconds =
96 chrono::duration_cast<chrono::seconds>(monotonic_now.time_since_epoch())
97 .count();
98 message->nseconds =
99 chrono::duration_cast<chrono::nanoseconds>(
100 monotonic_now.time_since_epoch() - chrono::seconds(message->seconds))
101 .count();
Brian Silvermanf665d692013-02-17 22:11:39 -0800102
103 message->sequence = context->sequence++;
104}
105
Brian Silverman88471dc2014-02-15 22:35:42 -0800106} // namespace
107
Austin Schuh82c0c822019-05-27 19:55:20 -0700108void FillInMessage(log_level level, monotonic_clock::time_point monotonic_now,
109 const char *format, va_list ap, LogMessage *message) {
110 FillInMessageBase(level, monotonic_now, message);
Brian Silverman88471dc2014-02-15 22:35:42 -0800111
112 message->message_length =
113 ExecuteFormat(message->message, sizeof(message->message), format, ap);
114 message->type = LogMessage::Type::kString;
115}
116
Brian Silvermanf665d692013-02-17 22:11:39 -0800117void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silvermana7234c62014-03-24 20:23:25 -0700118#define BASE_ARGS \
119 AOS_LOGGING_BASE_ARGS( \
120 message.name_length, message.name, static_cast<int32_t>(message.source), \
121 message.sequence, message.level, message.seconds, message.nseconds)
122 switch (message.type) {
Brian Silverman88471dc2014-02-15 22:35:42 -0800123 case LogMessage::Type::kString:
Brian Silvermana7234c62014-03-24 20:23:25 -0700124 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
Brian Silverman88471dc2014-02-15 22:35:42 -0800125 static_cast<int>(message.message_length), message.message);
126 break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800127 }
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800128#undef BASE_ARGS
Brian Silvermanf665d692013-02-17 22:11:39 -0800129}
130
131} // namespace internal
132
Brian Silvermanbe858a12014-04-30 17:37:28 -0700133void HandleMessageLogImplementation::DoLog(log_level level, const char *format,
134 va_list ap) {
135 LogMessage message;
Austin Schuh82c0c822019-05-27 19:55:20 -0700136 internal::FillInMessage(level, monotonic_now(), format, ap, &message);
Brian Silvermanbe858a12014-04-30 17:37:28 -0700137 HandleMessage(message);
138}
139
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800140StreamLogImplementation::StreamLogImplementation(FILE *stream)
141 : stream_(stream) {}
142
Brian Silvermanbe858a12014-04-30 17:37:28 -0700143void StreamLogImplementation::HandleMessage(const LogMessage &message) {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800144 internal::PrintMessage(stream_, message);
145}
146
Brian Silvermanf665d692013-02-17 22:11:39 -0800147void AddImplementation(LogImplementation *implementation) {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500148 internal::Context *context = internal::Context::Get();
Brian Silvermanf665d692013-02-17 22:11:39 -0800149
150 if (implementation->next() != NULL) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700151 AOS_LOG(FATAL,
152 "%p already has a next implementation, but it's not"
153 " being used yet\n",
154 implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -0800155 }
156
157 LogImplementation *old = context->implementation;
158 if (old != NULL) {
159 implementation->set_next(old);
160 }
161 SetGlobalImplementation(implementation);
Brian Silverman2e799732014-06-05 21:50:19 -0700162 root_implementation->have_other_implementation();
Brian Silvermanf665d692013-02-17 22:11:39 -0800163}
164
165void Init() {
166 static Once<void> once(DoInit);
167 once.Get();
168}
169
170void Load() {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500171 internal::Context::Get();
Brian Silvermanf665d692013-02-17 22:11:39 -0800172}
173
174void Cleanup() {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500175 internal::Context::Delete();
176}
177
178namespace {
179
180RawQueue *queue = NULL;
181
182int dropped_messages = 0;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800183monotonic_clock::time_point dropped_start, backoff_start;
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500184// Wait this long after dropping a message before even trying to write any more.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800185constexpr chrono::milliseconds kDropBackoff = chrono::milliseconds(100);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500186
187LogMessage *GetMessageOrDie() {
188 LogMessage *message = static_cast<LogMessage *>(queue->GetMessage());
189 if (message == NULL) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700190 AOS_LOG(FATAL, "%p->GetMessage() failed\n", queue);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500191 } else {
192 return message;
193 }
194}
195
196void Write(LogMessage *msg) {
197 if (__builtin_expect(dropped_messages > 0, false)) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800198 monotonic_clock::time_point message_time(
199 chrono::seconds(msg->seconds) + chrono::nanoseconds(msg->nseconds));
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500200 if (message_time - backoff_start < kDropBackoff) {
201 ++dropped_messages;
202 queue->FreeMessage(msg);
203 return;
204 }
205
206 LogMessage *dropped_message = GetMessageOrDie();
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800207 chrono::seconds dropped_start_sec = chrono::duration_cast<chrono::seconds>(
208 dropped_start.time_since_epoch());
209 chrono::nanoseconds dropped_start_nsec =
210 chrono::duration_cast<chrono::nanoseconds>(
211 dropped_start.time_since_epoch() - dropped_start_sec);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500212 internal::FillInMessageVarargs(
Austin Schuh82c0c822019-05-27 19:55:20 -0700213 ERROR, message_time, dropped_message,
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500214 "%d logs starting at %" PRId32 ".%" PRId32 " dropped\n",
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800215 dropped_messages, static_cast<int32_t>(dropped_start_sec.count()),
216 static_cast<int32_t>(dropped_start_nsec.count()));
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500217 if (queue->WriteMessage(dropped_message, RawQueue::kNonBlock)) {
218 dropped_messages = 0;
219 } else {
220 // Don't even bother trying to write this message because it's not likely
221 // to work and it would be confusing to have one log in the middle of a
222 // string of failures get through.
223 ++dropped_messages;
224 backoff_start = message_time;
225 queue->FreeMessage(msg);
226 return;
227 }
228 }
229 if (!queue->WriteMessage(msg, RawQueue::kNonBlock)) {
230 if (dropped_messages == 0) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800231 monotonic_clock::time_point message_time(
232 chrono::seconds(msg->seconds) + chrono::nanoseconds(msg->nseconds));
233 dropped_start = backoff_start = message_time;
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500234 }
235 ++dropped_messages;
236 }
237}
238
239class LinuxQueueLogImplementation : public LogImplementation {
Austin Schuh82c0c822019-05-27 19:55:20 -0700240 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
241 return ::aos::monotonic_clock::now();
242 }
243
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500244 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
245 void DoLog(log_level level, const char *format, va_list ap) override {
246 LogMessage *message = GetMessageOrDie();
Austin Schuh82c0c822019-05-27 19:55:20 -0700247 internal::FillInMessage(level, monotonic_now(), format, ap, message);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500248 Write(message);
249 }
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500250};
251
252} // namespace
253
254RawQueue *GetLoggingQueue() {
255 return RawQueue::Fetch("LoggingQueue", sizeof(LogMessage), 1323, 40000);
256}
257
258void RegisterQueueImplementation() {
259 Init();
260
261 queue = GetLoggingQueue();
262 if (queue == NULL) {
263 Die("logging: couldn't fetch queue\n");
264 }
265
266 AddImplementation(new LinuxQueueLogImplementation());
Brian Silvermanf665d692013-02-17 22:11:39 -0800267}
268
269} // namespace logging
270} // namespace aos