blob: bdc14ecbd9a05da38f7477b52d2b1ff351d1cc10 [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 Silvermanf665d692013-02-17 22:11:39 -080010
11namespace aos {
12namespace logging {
13namespace {
14
15using internal::Context;
Brian Silvermanb0893882014-02-10 14:48:30 -080016using internal::global_top_implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -080017
Brian Silvermanf665d692013-02-17 22:11:39 -080018// The root LogImplementation. It only logs to stderr/stdout.
19// Some of the things specified in the LogImplementation documentation doesn't
20// apply here (mostly the parts about being able to use LOG) because this is the
21// root one.
22class RootLogImplementation : public LogImplementation {
23 virtual void set_next(LogImplementation *) {
24 LOG(FATAL, "can't have a next logger from here\n");
25 }
26
27 virtual void DoLog(log_level level, const char *format, va_list ap) {
28 LogMessage message;
29 internal::FillInMessage(level, format, ap, &message);
30 internal::PrintMessage(stderr, message);
31 fputs("root logger got used, see stderr for message\n", stdout);
32 }
33};
34
35void SetGlobalImplementation(LogImplementation *implementation) {
36 Context *context = Context::Get();
37
38 context->implementation = implementation;
Brian Silvermanb0893882014-02-10 14:48:30 -080039 global_top_implementation = implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -080040}
41
Brian Silvermane5d65692013-02-28 15:15:03 -080042void NewContext() {
43 Context::Delete();
44}
45
Brian Silvermanf665d692013-02-17 22:11:39 -080046void *DoInit() {
47 SetGlobalImplementation(new RootLogImplementation());
Brian Silvermane5d65692013-02-28 15:15:03 -080048
Brian Silvermane5d65692013-02-28 15:15:03 -080049 if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/,
50 NewContext /*child*/) != 0) {
51 LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n",
52 NewContext);
53 }
Brian Silvermane5d65692013-02-28 15:15:03 -080054
Brian Silvermanf665d692013-02-17 22:11:39 -080055 return NULL;
56}
57
58} // namespace
59namespace internal {
60
Brian Silvermanf665d692013-02-17 22:11:39 -080061void FillInMessage(log_level level, const char *format, va_list ap,
62 LogMessage *message) {
63 Context *context = Context::Get();
64
65 ExecuteFormat(message->message, sizeof(message->message), format, ap);
66
67 message->level = level;
68 message->source = context->source;
Brian Silvermanab6615c2013-03-05 20:29:29 -080069 memcpy(message->name, context->name.c_str(), context->name.size() + 1);
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
78void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silverman8efe23e2013-07-07 23:31:37 -070079 fprintf(output, "%s(%" PRId32 ")(%05" PRIu16 "): %s at"
80 " %010" PRId32 ".%09" PRId32 "s: %s",
Brian Silverman7aa971b2013-03-16 14:40:09 -070081 message.name, static_cast<int32_t>(message.source), message.sequence,
Brian Silvermanf665d692013-02-17 22:11:39 -080082 log_str(message.level), message.seconds, message.nseconds,
83 message.message);
84}
85
86} // namespace internal
87
Brian Silverman669669f2014-02-14 16:32:56 -080088void LogImplementation::LogStruct(
89 log_level level, const ::std::string &message, size_t size,
90 const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
91 char serialized[1024];
92 if (size > sizeof(serialized)) {
93 LOG(FATAL, "structure of type %s too big to serialize\n",
94 type->name.c_str());
95 }
96 size_t used = serialize(serialized);
97 char printed[LOG_MESSAGE_LEN];
98 size_t printed_bytes = sizeof(printed);
99 if (!PrintMessage(printed, &printed_bytes, serialized, &used, *type)) {
100 LOG(FATAL, "PrintMessage(%p, %p(=%zd), %p, %p(=%zd), %p(name=%s)) failed\n",
101 printed, &printed_bytes, printed_bytes, serialized, &used, used, type,
102 type->name.c_str());
103 }
104 DoLogVariadic(level, "%.*s: %.*s\n", static_cast<int>(message.size()),
105 message.data(), static_cast<int>(printed_bytes), printed);
106}
107
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800108StreamLogImplementation::StreamLogImplementation(FILE *stream)
109 : stream_(stream) {}
110
111void StreamLogImplementation::DoLog(log_level level, const char *format,
112 va_list ap) {
113 LogMessage message;
114 internal::FillInMessage(level, format, ap, &message);
115 internal::PrintMessage(stream_, message);
116}
117
Brian Silvermanf665d692013-02-17 22:11:39 -0800118void LogNext(log_level level, const char *format, ...) {
119 va_list ap;
120 va_start(ap, format);
121 LogImplementation::DoVLog(level, format, ap, 2);
122 va_end(ap);
123}
124
125void AddImplementation(LogImplementation *implementation) {
126 Context *context = Context::Get();
127
128 if (implementation->next() != NULL) {
129 LOG(FATAL, "%p already has a next implementation, but it's not"
130 " being used yet\n", implementation);
131 }
132
133 LogImplementation *old = context->implementation;
134 if (old != NULL) {
135 implementation->set_next(old);
136 }
137 SetGlobalImplementation(implementation);
138}
139
140void Init() {
141 static Once<void> once(DoInit);
142 once.Get();
143}
144
145void Load() {
146 Context::Get();
147}
148
149void Cleanup() {
150 Context::Delete();
151}
152
153} // namespace logging
154} // namespace aos