blob: 9f1168f35b28455418675e001bb27e602c51eb23 [file] [log] [blame]
Brian Silvermanb0893882014-02-10 14:48:30 -08001#include "aos/common/logging/logging_impl.h"
2
3#include <assert.h>
4#include <stdarg.h>
5#include <string.h>
6
7#include "aos/common/die.h"
8
9// This file only contains the code necessary to link (ie no implementations).
10// See logging_impl.h for why this is necessary.
11
12namespace aos {
13namespace logging {
14namespace internal {
15
16LogImplementation *global_top_implementation(NULL);
17
18Context::Context()
19 : implementation(global_top_implementation),
20 sequence(0) {
21 cork_data.Reset();
22}
23
24void ExecuteFormat(char *output, size_t output_size,
25 const char *format, va_list ap) {
26 static const char *continued = "...\n";
27 const size_t size = output_size - strlen(continued);
28 const int ret = vsnprintf(output, size, format, ap);
29 if (ret < 0) {
30 LOG(FATAL, "vsnprintf(%p, %zd, %s, args) failed with %d (%s)\n",
31 output, size, format, errno, strerror(errno));
32 } else if (static_cast<uintmax_t>(ret) >= static_cast<uintmax_t>(size)) {
33 // Overwrite the '\0' at the end of the existing data and
34 // copy in the one on the end of continued.
35 memcpy(&output[size - 1], continued, strlen(continued) + 1);
36 }
37}
38
Brian Silvermand6974f42014-02-14 13:39:21 -080039void RunWithCurrentImplementation(
40 int levels, ::std::function<void(LogImplementation *)> function) {
Brian Silvermanb0893882014-02-10 14:48:30 -080041 Context *context = Context::Get();
42
Brian Silvermand6974f42014-02-14 13:39:21 -080043 LogImplementation *const top_implementation = context->implementation;
Brian Silvermanb0893882014-02-10 14:48:30 -080044 LogImplementation *new_implementation = top_implementation;
45 LogImplementation *implementation = NULL;
46 assert(levels >= 1);
47 for (int i = 0; i < levels; ++i) {
48 implementation = new_implementation;
49 if (new_implementation == NULL) {
50 Die("no logging implementation to use\n");
51 }
52 new_implementation = new_implementation->next();
53 }
54 context->implementation = new_implementation;
Brian Silvermand6974f42014-02-14 13:39:21 -080055 function(implementation);
Brian Silvermanb0893882014-02-10 14:48:30 -080056 context->implementation = top_implementation;
Brian Silvermand6974f42014-02-14 13:39:21 -080057}
Brian Silvermanb0893882014-02-10 14:48:30 -080058
Brian Silvermand6974f42014-02-14 13:39:21 -080059} // namespace internal
60
61using internal::Context;
62
63void LogImplementation::LogStruct(
64 log_level level, const ::std::string &message, size_t size,
65 const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
66 (void)level;
67 (void)message;
68 (void)size;
69 (void)type;
70 (void)serialize;
71}
72
73void LogImplementation::DoVLog(log_level level, const char *format, va_list ap,
74 int levels) {
75 internal::RunWithCurrentImplementation(
76 levels, [&](LogImplementation * implementation) {
77 implementation->DoLog(level, format, ap);
78
79 if (level == FATAL) {
80 VDie(format, ap);
81 }
82 });
Brian Silvermanb0893882014-02-10 14:48:30 -080083}
84
85void VLog(log_level level, const char *format, va_list ap) {
86 LogImplementation::DoVLog(level, format, ap, 1);
87}
88
89void VCork(int line, const char *function, const char *format, va_list ap) {
90 Context *context = Context::Get();
91
92 const size_t message_length = strlen(context->cork_data.message);
93 if (line > context->cork_data.line_max) context->cork_data.line_max = line;
94 if (line < context->cork_data.line_min) context->cork_data.line_min = line;
95
96 if (context->cork_data.function == NULL) {
97 context->cork_data.function = function;
98 } else {
99 if (strcmp(context->cork_data.function, function) != 0) {
100 LOG(FATAL, "started corking data in function %s but then moved to %s\n",
101 context->cork_data.function, function);
102 }
103 }
104
105 internal::ExecuteFormat(context->cork_data.message + message_length,
106 sizeof(context->cork_data.message) - message_length,
107 format, ap);
108}
109
110void VUnCork(int line, const char *function, log_level level, const char *file,
111 const char *format, va_list ap) {
112 Context *context = Context::Get();
113
114 VCork(line, function, format, ap);
115
116 log_do(level, "%s: %d-%d: %s: %s", file,
117 context->cork_data.line_min, context->cork_data.line_max, function,
118 context->cork_data.message);
119
120 context->cork_data.Reset();
121}
122
123} // namespace logging
124} // namespace aos
125
126void log_do(log_level level, const char *format, ...) {
127 va_list ap;
128 va_start(ap, format);
129 aos::logging::VLog(level, format, ap);
130 va_end(ap);
131}
132
133void log_cork(int line, const char *function, const char *format, ...) {
134 va_list ap;
135 va_start(ap, format);
136 aos::logging::VCork(line, function, format, ap);
137 va_end(ap);
138}
139
140void log_uncork(int line, const char *function, log_level level,
141 const char *file, const char *format, ...) {
142 va_list ap;
143 va_start(ap, format);
144 aos::logging::VUnCork(line, function, level, file, format, ap);
145 va_end(ap);
146}