blob: 094ecbb073911aa0aed44c0422435fe09abe7bad [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"
11#include "aos/logging/printf_formats.h"
John Park33858a32018-09-28 23:05:48 -070012#include "aos/time/time.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080013
14namespace aos {
15namespace logging {
16namespace {
17
Austin Schuhf2a50ba2016-12-24 16:16:26 -080018namespace chrono = ::std::chrono;
19
Brian Silvermanf665d692013-02-17 22:11:39 -080020// The root LogImplementation. It only logs to stderr/stdout.
21// Some of the things specified in the LogImplementation documentation doesn't
Austin Schuhf257f3c2019-10-27 21:00:43 -070022// apply here (mostly the parts about being able to use AOS_LOG) because this is
23// the root one.
Alex Perrycb7da4b2019-08-28 19:35:56 -070024class RootLogImplementation : public LogImplementation {
Alex Perrycb7da4b2019-08-28 19:35:56 -070025 protected:
26 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
27 return ::aos::monotonic_clock::now();
28 }
29
Brian Silverman2e799732014-06-05 21:50:19 -070030 private:
Tyler Chatow5febd8f2020-01-05 18:25:31 -080031 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
32 log_level level, const char *format, va_list ap) override {
Brian Silvermanf665d692013-02-17 22:11:39 -080033 LogMessage message;
Austin Schuh82c0c822019-05-27 19:55:20 -070034 internal::FillInMessage(level, monotonic_now(), format, ap, &message);
Brian Silvermanf665d692013-02-17 22:11:39 -080035 internal::PrintMessage(stderr, message);
Brian Silvermanf665d692013-02-17 22:11:39 -080036 }
37};
38
Brian Silverman2e799732014-06-05 21:50:19 -070039RootLogImplementation *root_implementation = nullptr;
40
Brian Silvermanf665d692013-02-17 22:11:39 -080041void SetGlobalImplementation(LogImplementation *implementation) {
Brian Silverman5c201e22014-06-12 22:40:28 -070042 if (root_implementation == nullptr) {
43 fputs("Somebody didn't call logging::Init()!\n", stderr);
44 abort();
45 }
46
Brian Silvermancb5da1f2015-12-05 22:19:58 -050047 internal::Context *context = internal::Context::Get();
Brian Silvermanf665d692013-02-17 22:11:39 -080048
49 context->implementation = implementation;
Brian Silvermancb5da1f2015-12-05 22:19:58 -050050 internal::global_top_implementation.store(implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -080051}
52
Tyler Chatow5febd8f2020-01-05 18:25:31 -080053void NewContext() { internal::Context::Delete(); }
Brian Silvermane5d65692013-02-28 15:15:03 -080054
John Park06da0452019-12-02 22:19:03 -080055void DoInit() {
Brian Silverman2e799732014-06-05 21:50:19 -070056 SetGlobalImplementation(root_implementation = new RootLogImplementation());
Brian Silvermane5d65692013-02-28 15:15:03 -080057
Tyler Chatow5febd8f2020-01-05 18:25:31 -080058 if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/, NewContext /*child*/) !=
59 0) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070060 AOS_LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n", NewContext);
Brian Silvermane5d65692013-02-28 15:15:03 -080061 }
Brian Silvermanf665d692013-02-17 22:11:39 -080062}
63
64} // namespace
65namespace internal {
Brian Silverman88471dc2014-02-15 22:35:42 -080066namespace {
Brian Silvermanf665d692013-02-17 22:11:39 -080067
Austin Schuh82c0c822019-05-27 19:55:20 -070068void FillInMessageBase(log_level level,
69 monotonic_clock::time_point monotonic_now,
70 LogMessage *message) {
Brian Silvermanf665d692013-02-17 22:11:39 -080071 Context *context = Context::Get();
72
Brian Silvermanf665d692013-02-17 22:11:39 -080073 message->level = level;
74 message->source = context->source;
Austin Schuhaebbc342015-01-25 02:25:13 -080075 memcpy(message->name, context->name, context->name_size);
76 message->name_length = context->name_size;
Brian Silvermanf665d692013-02-17 22:11:39 -080077
Austin Schuhf2a50ba2016-12-24 16:16:26 -080078 message->seconds =
79 chrono::duration_cast<chrono::seconds>(monotonic_now.time_since_epoch())
80 .count();
81 message->nseconds =
82 chrono::duration_cast<chrono::nanoseconds>(
83 monotonic_now.time_since_epoch() - chrono::seconds(message->seconds))
84 .count();
Brian Silvermanf665d692013-02-17 22:11:39 -080085
86 message->sequence = context->sequence++;
87}
88
Brian Silverman88471dc2014-02-15 22:35:42 -080089} // namespace
90
Austin Schuh82c0c822019-05-27 19:55:20 -070091void FillInMessage(log_level level, monotonic_clock::time_point monotonic_now,
92 const char *format, va_list ap, LogMessage *message) {
93 FillInMessageBase(level, monotonic_now, message);
Brian Silverman88471dc2014-02-15 22:35:42 -080094
95 message->message_length =
96 ExecuteFormat(message->message, sizeof(message->message), format, ap);
97 message->type = LogMessage::Type::kString;
98}
99
Brian Silvermanf665d692013-02-17 22:11:39 -0800100void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silvermana7234c62014-03-24 20:23:25 -0700101#define BASE_ARGS \
102 AOS_LOGGING_BASE_ARGS( \
103 message.name_length, message.name, static_cast<int32_t>(message.source), \
104 message.sequence, message.level, message.seconds, message.nseconds)
105 switch (message.type) {
Brian Silverman88471dc2014-02-15 22:35:42 -0800106 case LogMessage::Type::kString:
Brian Silvermana7234c62014-03-24 20:23:25 -0700107 fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
Brian Silverman88471dc2014-02-15 22:35:42 -0800108 static_cast<int>(message.message_length), message.message);
109 break;
Brian Silverman88471dc2014-02-15 22:35:42 -0800110 }
Brian Silvermanc1a244e2014-02-20 14:12:39 -0800111#undef BASE_ARGS
Brian Silvermanf665d692013-02-17 22:11:39 -0800112}
113
114} // namespace internal
115
Brian Silvermanbe858a12014-04-30 17:37:28 -0700116void HandleMessageLogImplementation::DoLog(log_level level, const char *format,
117 va_list ap) {
118 LogMessage message;
Austin Schuh82c0c822019-05-27 19:55:20 -0700119 internal::FillInMessage(level, monotonic_now(), format, ap, &message);
Brian Silvermanbe858a12014-04-30 17:37:28 -0700120 HandleMessage(message);
121}
122
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800123StreamLogImplementation::StreamLogImplementation(FILE *stream)
124 : stream_(stream) {}
125
Brian Silvermanbe858a12014-04-30 17:37:28 -0700126void StreamLogImplementation::HandleMessage(const LogMessage &message) {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800127 internal::PrintMessage(stream_, message);
128}
129
Tyler Chatow4b471e12020-01-05 20:19:36 -0800130void SetImplementation(LogImplementation *implementation, bool update_global) {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500131 internal::Context *context = internal::Context::Get();
Brian Silvermanf665d692013-02-17 22:11:39 -0800132
Tyler Chatow4b471e12020-01-05 20:19:36 -0800133 context->implementation = implementation;
134 if (update_global) {
135 SetGlobalImplementation(implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -0800136 }
Tyler Chatow4b471e12020-01-05 20:19:36 -0800137}
138
139LogImplementation *SwapImplementation(LogImplementation *implementation) {
140 internal::Context *context = internal::Context::Get();
141
142 LogImplementation *old = context->implementation;
143 context->implementation = implementation;
144
145 return old;
Brian Silvermanf665d692013-02-17 22:11:39 -0800146}
147
Tyler Chatow67ddb032020-01-12 14:30:04 -0800148LogImplementation *GetImplementation() {
149 return internal::Context::Get()->implementation;
150}
151
Brian Silvermanf665d692013-02-17 22:11:39 -0800152void Init() {
John Park06da0452019-12-02 22:19:03 -0800153 static absl::once_flag once;
154 absl::call_once(once, DoInit);
Brian Silvermanf665d692013-02-17 22:11:39 -0800155}
156
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800157void Load() { internal::Context::Get(); }
Brian Silvermanf665d692013-02-17 22:11:39 -0800158
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800159void Cleanup() { internal::Context::Delete(); }
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500160
161namespace {
162
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800163class CallbackLogImplementation : public HandleMessageLogImplementation {
164 public:
165 CallbackLogImplementation(
166 const ::std::function<void(const LogMessage &)> &callback)
167 : callback_(callback) {}
168
169 private:
170 void HandleMessage(const LogMessage &message) override { callback_(message); }
171
172 ::std::function<void(const LogMessage &)> callback_;
173};
174
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500175} // namespace
176
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800177void RegisterCallbackImplementation(
Tyler Chatow4b471e12020-01-05 20:19:36 -0800178 const ::std::function<void(const LogMessage &)> &callback,
Tyler Chatow67ddb032020-01-12 14:30:04 -0800179 bool update_global) {
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800180 Init();
Tyler Chatow4b471e12020-01-05 20:19:36 -0800181 SetImplementation(new CallbackLogImplementation(callback), update_global);
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800182}
183
Brian Silvermanf665d692013-02-17 22:11:39 -0800184} // namespace logging
185} // namespace aos