blob: 89fc9048721eee5dd2b5def2554448e75f0dff2f [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"
John Park06da0452019-12-02 22:19:03 -080013#include "absl/base/call_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
John Park06da0452019-12-02 22:19:03 -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 Silvermanf665d692013-02-17 22:11:39 -080077}
78
79} // namespace
80namespace internal {
Brian Silverman88471dc2014-02-15 22:35:42 -080081namespace {
Brian Silvermanf665d692013-02-17 22:11:39 -080082
Austin Schuh82c0c822019-05-27 19:55:20 -070083void FillInMessageBase(log_level level,
84 monotonic_clock::time_point monotonic_now,
85 LogMessage *message) {
Brian Silvermanf665d692013-02-17 22:11:39 -080086 Context *context = Context::Get();
87
Brian Silvermanf665d692013-02-17 22:11:39 -080088 message->level = level;
89 message->source = context->source;
Austin Schuhaebbc342015-01-25 02:25:13 -080090 memcpy(message->name, context->name, context->name_size);
91 message->name_length = context->name_size;
Brian Silvermanf665d692013-02-17 22:11:39 -080092
Austin Schuhf2a50ba2016-12-24 16:16:26 -080093 message->seconds =
94 chrono::duration_cast<chrono::seconds>(monotonic_now.time_since_epoch())
95 .count();
96 message->nseconds =
97 chrono::duration_cast<chrono::nanoseconds>(
98 monotonic_now.time_since_epoch() - chrono::seconds(message->seconds))
99 .count();
Brian Silvermanf665d692013-02-17 22:11:39 -0800100
101 message->sequence = context->sequence++;
102}
103
Brian Silverman88471dc2014-02-15 22:35:42 -0800104} // namespace
105
Austin Schuh82c0c822019-05-27 19:55:20 -0700106void FillInMessage(log_level level, monotonic_clock::time_point monotonic_now,
107 const char *format, va_list ap, LogMessage *message) {
108 FillInMessageBase(level, monotonic_now, message);
Brian Silverman88471dc2014-02-15 22:35:42 -0800109
110 message->message_length =
111 ExecuteFormat(message->message, sizeof(message->message), format, ap);
112 message->type = LogMessage::Type::kString;
113}
114
Brian Silvermanf665d692013-02-17 22:11:39 -0800115void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silvermana7234c62014-03-24 20:23:25 -0700116#define BASE_ARGS \
117 AOS_LOGGING_BASE_ARGS( \
118 message.name_length, message.name, static_cast<int32_t>(message.source), \
119 message.sequence, message.level, message.seconds, message.nseconds)
120 switch (message.type) {
Brian Silverman88471dc2014-02-15 22:35:42 -0800121 case LogMessage::Type::kString:
Brian Silvermana7234c62014-03-24 20:23:25 -0700122 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
Brian Silverman88471dc2014-02-15 22:35:42 -0800123 static_cast<int>(message.message_length), message.message);
124 break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800125 }
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800126#undef BASE_ARGS
Brian Silvermanf665d692013-02-17 22:11:39 -0800127}
128
129} // namespace internal
130
Brian Silvermanbe858a12014-04-30 17:37:28 -0700131void HandleMessageLogImplementation::DoLog(log_level level, const char *format,
132 va_list ap) {
133 LogMessage message;
Austin Schuh82c0c822019-05-27 19:55:20 -0700134 internal::FillInMessage(level, monotonic_now(), format, ap, &message);
Brian Silvermanbe858a12014-04-30 17:37:28 -0700135 HandleMessage(message);
136}
137
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800138StreamLogImplementation::StreamLogImplementation(FILE *stream)
139 : stream_(stream) {}
140
Brian Silvermanbe858a12014-04-30 17:37:28 -0700141void StreamLogImplementation::HandleMessage(const LogMessage &message) {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800142 internal::PrintMessage(stream_, message);
143}
144
Brian Silvermanf665d692013-02-17 22:11:39 -0800145void AddImplementation(LogImplementation *implementation) {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500146 internal::Context *context = internal::Context::Get();
Brian Silvermanf665d692013-02-17 22:11:39 -0800147
148 if (implementation->next() != NULL) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700149 AOS_LOG(FATAL,
150 "%p already has a next implementation, but it's not"
151 " being used yet\n",
152 implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -0800153 }
154
155 LogImplementation *old = context->implementation;
156 if (old != NULL) {
157 implementation->set_next(old);
158 }
159 SetGlobalImplementation(implementation);
Brian Silverman2e799732014-06-05 21:50:19 -0700160 root_implementation->have_other_implementation();
Brian Silvermanf665d692013-02-17 22:11:39 -0800161}
162
163void Init() {
John Park06da0452019-12-02 22:19:03 -0800164 static absl::once_flag once;
165 absl::call_once(once, DoInit);
Brian Silvermanf665d692013-02-17 22:11:39 -0800166}
167
168void Load() {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500169 internal::Context::Get();
Brian Silvermanf665d692013-02-17 22:11:39 -0800170}
171
172void Cleanup() {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500173 internal::Context::Delete();
174}
175
176namespace {
177
178RawQueue *queue = NULL;
179
180int dropped_messages = 0;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800181monotonic_clock::time_point dropped_start, backoff_start;
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500182// Wait this long after dropping a message before even trying to write any more.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800183constexpr chrono::milliseconds kDropBackoff = chrono::milliseconds(100);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500184
185LogMessage *GetMessageOrDie() {
186 LogMessage *message = static_cast<LogMessage *>(queue->GetMessage());
187 if (message == NULL) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700188 AOS_LOG(FATAL, "%p->GetMessage() failed\n", queue);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500189 } else {
190 return message;
191 }
192}
193
194void Write(LogMessage *msg) {
195 if (__builtin_expect(dropped_messages > 0, false)) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800196 monotonic_clock::time_point message_time(
197 chrono::seconds(msg->seconds) + chrono::nanoseconds(msg->nseconds));
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500198 if (message_time - backoff_start < kDropBackoff) {
199 ++dropped_messages;
200 queue->FreeMessage(msg);
201 return;
202 }
203
204 LogMessage *dropped_message = GetMessageOrDie();
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800205 chrono::seconds dropped_start_sec = chrono::duration_cast<chrono::seconds>(
206 dropped_start.time_since_epoch());
207 chrono::nanoseconds dropped_start_nsec =
208 chrono::duration_cast<chrono::nanoseconds>(
209 dropped_start.time_since_epoch() - dropped_start_sec);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500210 internal::FillInMessageVarargs(
Austin Schuh82c0c822019-05-27 19:55:20 -0700211 ERROR, message_time, dropped_message,
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500212 "%d logs starting at %" PRId32 ".%" PRId32 " dropped\n",
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800213 dropped_messages, static_cast<int32_t>(dropped_start_sec.count()),
214 static_cast<int32_t>(dropped_start_nsec.count()));
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500215 if (queue->WriteMessage(dropped_message, RawQueue::kNonBlock)) {
216 dropped_messages = 0;
217 } else {
218 // Don't even bother trying to write this message because it's not likely
219 // to work and it would be confusing to have one log in the middle of a
220 // string of failures get through.
221 ++dropped_messages;
222 backoff_start = message_time;
223 queue->FreeMessage(msg);
224 return;
225 }
226 }
227 if (!queue->WriteMessage(msg, RawQueue::kNonBlock)) {
228 if (dropped_messages == 0) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800229 monotonic_clock::time_point message_time(
230 chrono::seconds(msg->seconds) + chrono::nanoseconds(msg->nseconds));
231 dropped_start = backoff_start = message_time;
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500232 }
233 ++dropped_messages;
234 }
235}
236
237class LinuxQueueLogImplementation : public LogImplementation {
Austin Schuh82c0c822019-05-27 19:55:20 -0700238 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
239 return ::aos::monotonic_clock::now();
240 }
241
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500242 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
243 void DoLog(log_level level, const char *format, va_list ap) override {
244 LogMessage *message = GetMessageOrDie();
Austin Schuh82c0c822019-05-27 19:55:20 -0700245 internal::FillInMessage(level, monotonic_now(), format, ap, message);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500246 Write(message);
247 }
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500248};
249
250} // namespace
251
252RawQueue *GetLoggingQueue() {
Austin Schuh3e252e72019-12-29 16:25:58 -0800253 return RawQueue::Fetch("LoggingQueue", sizeof(LogMessage), 1323, 10000);
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500254}
255
256void RegisterQueueImplementation() {
257 Init();
258
259 queue = GetLoggingQueue();
260 if (queue == NULL) {
261 Die("logging: couldn't fetch queue\n");
262 }
263
264 AddImplementation(new LinuxQueueLogImplementation());
Brian Silvermanf665d692013-02-17 22:11:39 -0800265}
266
267} // namespace logging
268} // namespace aos