blob: b35414ea5b92fe3f7ffd5c6b887363c70d660c66 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/logging/implementations.h"
Brian Silvermanf665d692013-02-17 22:11:39 -08002
Brian4a424a22014-04-02 11:52:45 -07003#include <inttypes.h>
Tyler Chatow5febd8f2020-01-05 18:25:31 -08004#include <stdarg.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
Tyler Chatow5febd8f2020-01-05 18:25:31 -08009#include "absl/base/call_once.h"
John Park33858a32018-09-28 23:05:48 -070010#include "aos/die.h"
Tyler Chatow5febd8f2020-01-05 18:25:31 -080011#include "aos/ipc_lib/queue.h"
John Park33858a32018-09-28 23:05:48 -070012#include "aos/logging/printf_formats.h"
John Park33858a32018-09-28 23:05:48 -070013#include "aos/time/time.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
Tyler Chatow5febd8f2020-01-05 18:25:31 -080039 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
40 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
Tyler Chatow5febd8f2020-01-05 18:25:31 -080066void NewContext() { internal::Context::Delete(); }
Brian Silvermane5d65692013-02-28 15:15:03 -080067
John Park06da0452019-12-02 22:19:03 -080068void DoInit() {
Brian Silverman2e799732014-06-05 21:50:19 -070069 SetGlobalImplementation(root_implementation = new RootLogImplementation());
Brian Silvermane5d65692013-02-28 15:15:03 -080070
Tyler Chatow5febd8f2020-01-05 18:25:31 -080071 if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/, NewContext /*child*/) !=
72 0) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070073 AOS_LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n", NewContext);
Brian Silvermane5d65692013-02-28 15:15:03 -080074 }
Brian Silvermanf665d692013-02-17 22:11:39 -080075}
76
77} // namespace
78namespace internal {
Brian Silverman88471dc2014-02-15 22:35:42 -080079namespace {
Brian Silvermanf665d692013-02-17 22:11:39 -080080
Austin Schuh82c0c822019-05-27 19:55:20 -070081void FillInMessageBase(log_level level,
82 monotonic_clock::time_point monotonic_now,
83 LogMessage *message) {
Brian Silvermanf665d692013-02-17 22:11:39 -080084 Context *context = Context::Get();
85
Brian Silvermanf665d692013-02-17 22:11:39 -080086 message->level = level;
87 message->source = context->source;
Austin Schuhaebbc342015-01-25 02:25:13 -080088 memcpy(message->name, context->name, context->name_size);
89 message->name_length = context->name_size;
Brian Silvermanf665d692013-02-17 22:11:39 -080090
Austin Schuhf2a50ba2016-12-24 16:16:26 -080091 message->seconds =
92 chrono::duration_cast<chrono::seconds>(monotonic_now.time_since_epoch())
93 .count();
94 message->nseconds =
95 chrono::duration_cast<chrono::nanoseconds>(
96 monotonic_now.time_since_epoch() - chrono::seconds(message->seconds))
97 .count();
Brian Silvermanf665d692013-02-17 22:11:39 -080098
99 message->sequence = context->sequence++;
100}
101
Brian Silverman88471dc2014-02-15 22:35:42 -0800102} // namespace
103
Austin Schuh82c0c822019-05-27 19:55:20 -0700104void FillInMessage(log_level level, monotonic_clock::time_point monotonic_now,
105 const char *format, va_list ap, LogMessage *message) {
106 FillInMessageBase(level, monotonic_now, message);
Brian Silverman88471dc2014-02-15 22:35:42 -0800107
108 message->message_length =
109 ExecuteFormat(message->message, sizeof(message->message), format, ap);
110 message->type = LogMessage::Type::kString;
111}
112
Brian Silvermanf665d692013-02-17 22:11:39 -0800113void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silvermana7234c62014-03-24 20:23:25 -0700114#define BASE_ARGS \
115 AOS_LOGGING_BASE_ARGS( \
116 message.name_length, message.name, static_cast<int32_t>(message.source), \
117 message.sequence, message.level, message.seconds, message.nseconds)
118 switch (message.type) {
Brian Silverman88471dc2014-02-15 22:35:42 -0800119 case LogMessage::Type::kString:
Brian Silvermana7234c62014-03-24 20:23:25 -0700120 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
Brian Silverman88471dc2014-02-15 22:35:42 -0800121 static_cast<int>(message.message_length), message.message);
122 break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800123 }
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800124#undef BASE_ARGS
Brian Silvermanf665d692013-02-17 22:11:39 -0800125}
126
127} // namespace internal
128
Brian Silvermanbe858a12014-04-30 17:37:28 -0700129void HandleMessageLogImplementation::DoLog(log_level level, const char *format,
130 va_list ap) {
131 LogMessage message;
Austin Schuh82c0c822019-05-27 19:55:20 -0700132 internal::FillInMessage(level, monotonic_now(), format, ap, &message);
Brian Silvermanbe858a12014-04-30 17:37:28 -0700133 HandleMessage(message);
134}
135
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800136StreamLogImplementation::StreamLogImplementation(FILE *stream)
137 : stream_(stream) {}
138
Brian Silvermanbe858a12014-04-30 17:37:28 -0700139void StreamLogImplementation::HandleMessage(const LogMessage &message) {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800140 internal::PrintMessage(stream_, message);
141}
142
Brian Silvermanf665d692013-02-17 22:11:39 -0800143void AddImplementation(LogImplementation *implementation) {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500144 internal::Context *context = internal::Context::Get();
Brian Silvermanf665d692013-02-17 22:11:39 -0800145
146 if (implementation->next() != NULL) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700147 AOS_LOG(FATAL,
148 "%p already has a next implementation, but it's not"
149 " being used yet\n",
150 implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -0800151 }
152
153 LogImplementation *old = context->implementation;
154 if (old != NULL) {
155 implementation->set_next(old);
156 }
157 SetGlobalImplementation(implementation);
Brian Silverman2e799732014-06-05 21:50:19 -0700158 root_implementation->have_other_implementation();
Brian Silvermanf665d692013-02-17 22:11:39 -0800159}
160
161void Init() {
John Park06da0452019-12-02 22:19:03 -0800162 static absl::once_flag once;
163 absl::call_once(once, DoInit);
Brian Silvermanf665d692013-02-17 22:11:39 -0800164}
165
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800166void Load() { internal::Context::Get(); }
Brian Silvermanf665d692013-02-17 22:11:39 -0800167
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800168void Cleanup() { internal::Context::Delete(); }
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500169
170namespace {
171
172RawQueue *queue = NULL;
173
174int dropped_messages = 0;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800175monotonic_clock::time_point dropped_start, backoff_start;
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500176// Wait this long after dropping a message before even trying to write any more.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800177constexpr chrono::milliseconds kDropBackoff = chrono::milliseconds(100);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500178
179LogMessage *GetMessageOrDie() {
180 LogMessage *message = static_cast<LogMessage *>(queue->GetMessage());
181 if (message == NULL) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700182 AOS_LOG(FATAL, "%p->GetMessage() failed\n", queue);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500183 } else {
184 return message;
185 }
186}
187
188void Write(LogMessage *msg) {
189 if (__builtin_expect(dropped_messages > 0, false)) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800190 monotonic_clock::time_point message_time(
191 chrono::seconds(msg->seconds) + chrono::nanoseconds(msg->nseconds));
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500192 if (message_time - backoff_start < kDropBackoff) {
193 ++dropped_messages;
194 queue->FreeMessage(msg);
195 return;
196 }
197
198 LogMessage *dropped_message = GetMessageOrDie();
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800199 chrono::seconds dropped_start_sec = chrono::duration_cast<chrono::seconds>(
200 dropped_start.time_since_epoch());
201 chrono::nanoseconds dropped_start_nsec =
202 chrono::duration_cast<chrono::nanoseconds>(
203 dropped_start.time_since_epoch() - dropped_start_sec);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500204 internal::FillInMessageVarargs(
Austin Schuh82c0c822019-05-27 19:55:20 -0700205 ERROR, message_time, dropped_message,
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500206 "%d logs starting at %" PRId32 ".%" PRId32 " dropped\n",
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800207 dropped_messages, static_cast<int32_t>(dropped_start_sec.count()),
208 static_cast<int32_t>(dropped_start_nsec.count()));
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500209 if (queue->WriteMessage(dropped_message, RawQueue::kNonBlock)) {
210 dropped_messages = 0;
211 } else {
212 // Don't even bother trying to write this message because it's not likely
213 // to work and it would be confusing to have one log in the middle of a
214 // string of failures get through.
215 ++dropped_messages;
216 backoff_start = message_time;
217 queue->FreeMessage(msg);
218 return;
219 }
220 }
221 if (!queue->WriteMessage(msg, RawQueue::kNonBlock)) {
222 if (dropped_messages == 0) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800223 monotonic_clock::time_point message_time(
224 chrono::seconds(msg->seconds) + chrono::nanoseconds(msg->nseconds));
225 dropped_start = backoff_start = message_time;
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500226 }
227 ++dropped_messages;
228 }
229}
230
231class LinuxQueueLogImplementation : public LogImplementation {
Austin Schuh82c0c822019-05-27 19:55:20 -0700232 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
233 return ::aos::monotonic_clock::now();
234 }
235
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800236 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
237 log_level level, const char *format, va_list ap) override {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500238 LogMessage *message = GetMessageOrDie();
Austin Schuh82c0c822019-05-27 19:55:20 -0700239 internal::FillInMessage(level, monotonic_now(), format, ap, message);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500240 Write(message);
241 }
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500242};
243
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800244class CallbackLogImplementation : public HandleMessageLogImplementation {
245 public:
246 CallbackLogImplementation(
247 const ::std::function<void(const LogMessage &)> &callback)
248 : callback_(callback) {}
249
250 private:
251 void HandleMessage(const LogMessage &message) override { callback_(message); }
252
253 ::std::function<void(const LogMessage &)> callback_;
254};
255
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500256} // namespace
257
258RawQueue *GetLoggingQueue() {
Austin Schuh3e252e72019-12-29 16:25:58 -0800259 return RawQueue::Fetch("LoggingQueue", sizeof(LogMessage), 1323, 10000);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500260}
261
262void RegisterQueueImplementation() {
263 Init();
264
265 queue = GetLoggingQueue();
266 if (queue == NULL) {
267 Die("logging: couldn't fetch queue\n");
268 }
269
270 AddImplementation(new LinuxQueueLogImplementation());
Brian Silvermanf665d692013-02-17 22:11:39 -0800271}
272
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800273void RegisterCallbackImplementation(
274 const ::std::function<void(const LogMessage &)> &callback) {
275 Init();
276 AddImplementation(new CallbackLogImplementation(callback));
277}
278
Brian Silvermanf665d692013-02-17 22:11:39 -0800279} // namespace logging
280} // namespace aos