blob: de1c64aba54cc26eb7d331f8e1d0f38ee7742bb8 [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"
9
10namespace aos {
11namespace logging {
12namespace {
13
14using internal::Context;
Brian Silvermanb0893882014-02-10 14:48:30 -080015using internal::global_top_implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -080016
Brian Silvermanf665d692013-02-17 22:11:39 -080017// The root LogImplementation. It only logs to stderr/stdout.
18// Some of the things specified in the LogImplementation documentation doesn't
19// apply here (mostly the parts about being able to use LOG) because this is the
20// root one.
21class RootLogImplementation : public LogImplementation {
22 virtual void set_next(LogImplementation *) {
23 LOG(FATAL, "can't have a next logger from here\n");
24 }
25
26 virtual void DoLog(log_level level, const char *format, va_list ap) {
27 LogMessage message;
28 internal::FillInMessage(level, format, ap, &message);
29 internal::PrintMessage(stderr, message);
30 fputs("root logger got used, see stderr for message\n", stdout);
31 }
32};
33
34void SetGlobalImplementation(LogImplementation *implementation) {
35 Context *context = Context::Get();
36
37 context->implementation = implementation;
Brian Silvermanb0893882014-02-10 14:48:30 -080038 global_top_implementation = implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -080039}
40
Brian Silvermane5d65692013-02-28 15:15:03 -080041void NewContext() {
42 Context::Delete();
43}
44
Brian Silvermanf665d692013-02-17 22:11:39 -080045void *DoInit() {
46 SetGlobalImplementation(new RootLogImplementation());
Brian Silvermane5d65692013-02-28 15:15:03 -080047
Brian Silvermane5d65692013-02-28 15:15:03 -080048 if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/,
49 NewContext /*child*/) != 0) {
50 LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n",
51 NewContext);
52 }
Brian Silvermane5d65692013-02-28 15:15:03 -080053
Brian Silvermanf665d692013-02-17 22:11:39 -080054 return NULL;
55}
56
57} // namespace
58namespace internal {
59
Brian Silvermanf665d692013-02-17 22:11:39 -080060void FillInMessage(log_level level, const char *format, va_list ap,
61 LogMessage *message) {
62 Context *context = Context::Get();
63
64 ExecuteFormat(message->message, sizeof(message->message), format, ap);
65
66 message->level = level;
67 message->source = context->source;
Brian Silvermanab6615c2013-03-05 20:29:29 -080068 memcpy(message->name, context->name.c_str(), context->name.size() + 1);
Brian Silvermanf665d692013-02-17 22:11:39 -080069
70 time::Time now = time::Time::Now();
71 message->seconds = now.sec();
72 message->nseconds = now.nsec();
73
74 message->sequence = context->sequence++;
75}
76
77void PrintMessage(FILE *output, const LogMessage &message) {
Brian Silverman8efe23e2013-07-07 23:31:37 -070078 fprintf(output, "%s(%" PRId32 ")(%05" PRIu16 "): %s at"
79 " %010" PRId32 ".%09" PRId32 "s: %s",
Brian Silverman7aa971b2013-03-16 14:40:09 -070080 message.name, static_cast<int32_t>(message.source), message.sequence,
Brian Silvermanf665d692013-02-17 22:11:39 -080081 log_str(message.level), message.seconds, message.nseconds,
82 message.message);
83}
84
85} // namespace internal
86
Brian Silverman1e8ddfe2013-12-19 16:20:53 -080087StreamLogImplementation::StreamLogImplementation(FILE *stream)
88 : stream_(stream) {}
89
90void StreamLogImplementation::DoLog(log_level level, const char *format,
91 va_list ap) {
92 LogMessage message;
93 internal::FillInMessage(level, format, ap, &message);
94 internal::PrintMessage(stream_, message);
95}
96
Brian Silvermanf665d692013-02-17 22:11:39 -080097void LogNext(log_level level, const char *format, ...) {
98 va_list ap;
99 va_start(ap, format);
100 LogImplementation::DoVLog(level, format, ap, 2);
101 va_end(ap);
102}
103
104void AddImplementation(LogImplementation *implementation) {
105 Context *context = Context::Get();
106
107 if (implementation->next() != NULL) {
108 LOG(FATAL, "%p already has a next implementation, but it's not"
109 " being used yet\n", implementation);
110 }
111
112 LogImplementation *old = context->implementation;
113 if (old != NULL) {
114 implementation->set_next(old);
115 }
116 SetGlobalImplementation(implementation);
117}
118
119void Init() {
120 static Once<void> once(DoInit);
121 once.Get();
122}
123
124void Load() {
125 Context::Get();
126}
127
128void Cleanup() {
129 Context::Delete();
130}
131
132} // namespace logging
133} // namespace aos