blob: 0a6c968439e7d9c5643109eecccb87a36271d343 [file] [log] [blame]
Austin Schuh044e18b2015-10-21 20:17:09 -07001#include "aos/common/logging/logging_interface.h"
Brian Silvermanb0893882014-02-10 14:48:30 -08002
Brian Silvermanb0893882014-02-10 14:48:30 -08003#include <stdarg.h>
Austin Schuh044e18b2015-10-21 20:17:09 -07004#include <stdio.h>
Brian Silvermanb0893882014-02-10 14:48:30 -08005#include <string.h>
6
Brian Silverman88471dc2014-02-15 22:35:42 -08007#include <type_traits>
Austin Schuh044e18b2015-10-21 20:17:09 -07008#include <functional>
Brian Silverman88471dc2014-02-15 22:35:42 -08009
Brian Silvermanb0893882014-02-10 14:48:30 -080010#include "aos/common/die.h"
Austin Schuh044e18b2015-10-21 20:17:09 -070011#include "aos/common/logging/context.h"
Brian Silvermanb0893882014-02-10 14:48:30 -080012
13// This file only contains the code necessary to link (ie no implementations).
14// See logging_impl.h for why this is necessary.
15
16namespace aos {
17namespace logging {
18namespace internal {
19
Brian Silverman88471dc2014-02-15 22:35:42 -080020size_t ExecuteFormat(char *output, size_t output_size, const char *format,
21 va_list ap) {
22 static const char *const continued = "...\n";
Brian Silvermanb0893882014-02-10 14:48:30 -080023 const size_t size = output_size - strlen(continued);
24 const int ret = vsnprintf(output, size, format, ap);
Brian Silverman88471dc2014-02-15 22:35:42 -080025 typedef ::std::common_type<typeof(ret), typeof(size)>::type RetType;
Brian Silvermanb0893882014-02-10 14:48:30 -080026 if (ret < 0) {
Brian Silverman01be0002014-05-10 15:44:38 -070027 PLOG(FATAL, "vsnprintf(%p, %zd, %s, args) failed",
28 output, size, format);
Brian Silverman88471dc2014-02-15 22:35:42 -080029 } else if (static_cast<RetType>(ret) >= static_cast<RetType>(size)) {
Brian Silvermanb0893882014-02-10 14:48:30 -080030 // Overwrite the '\0' at the end of the existing data and
31 // copy in the one on the end of continued.
32 memcpy(&output[size - 1], continued, strlen(continued) + 1);
33 }
Brian Silverman88471dc2014-02-15 22:35:42 -080034 return ::std::min<RetType>(ret, size);
Brian Silvermanb0893882014-02-10 14:48:30 -080035}
36
Brian Silvermand6974f42014-02-14 13:39:21 -080037void RunWithCurrentImplementation(
38 int levels, ::std::function<void(LogImplementation *)> function) {
Brian Silvermanb0893882014-02-10 14:48:30 -080039 Context *context = Context::Get();
40
Brian Silvermand6974f42014-02-14 13:39:21 -080041 LogImplementation *const top_implementation = context->implementation;
Brian Silvermanb0893882014-02-10 14:48:30 -080042 LogImplementation *new_implementation = top_implementation;
43 LogImplementation *implementation = NULL;
Brian Silvermanb0893882014-02-10 14:48:30 -080044 for (int i = 0; i < levels; ++i) {
45 implementation = new_implementation;
46 if (new_implementation == NULL) {
47 Die("no logging implementation to use\n");
48 }
49 new_implementation = new_implementation->next();
50 }
51 context->implementation = new_implementation;
Brian Silvermand6974f42014-02-14 13:39:21 -080052 function(implementation);
Brian Silvermanb0893882014-02-10 14:48:30 -080053 context->implementation = top_implementation;
Brian Silvermand6974f42014-02-14 13:39:21 -080054}
Brian Silvermanb0893882014-02-10 14:48:30 -080055
Brian Silvermand6974f42014-02-14 13:39:21 -080056} // namespace internal
57
58using internal::Context;
59
Brian Silvermand6974f42014-02-14 13:39:21 -080060void LogImplementation::DoVLog(log_level level, const char *format, va_list ap,
61 int levels) {
62 internal::RunWithCurrentImplementation(
63 levels, [&](LogImplementation * implementation) {
Brian Silvermane6335e42014-02-20 20:53:06 -080064 va_list ap1;
65 va_copy(ap1, ap);
66 implementation->DoLog(level, format, ap1);
67 va_end(ap1);
Brian Silvermand6974f42014-02-14 13:39:21 -080068
69 if (level == FATAL) {
70 VDie(format, ap);
71 }
72 });
Brian Silvermanb0893882014-02-10 14:48:30 -080073}
74
75void VLog(log_level level, const char *format, va_list ap) {
76 LogImplementation::DoVLog(level, format, ap, 1);
77}
78
79void VCork(int line, const char *function, const char *format, va_list ap) {
80 Context *context = Context::Get();
81
82 const size_t message_length = strlen(context->cork_data.message);
83 if (line > context->cork_data.line_max) context->cork_data.line_max = line;
84 if (line < context->cork_data.line_min) context->cork_data.line_min = line;
85
86 if (context->cork_data.function == NULL) {
87 context->cork_data.function = function;
88 } else {
89 if (strcmp(context->cork_data.function, function) != 0) {
90 LOG(FATAL, "started corking data in function %s but then moved to %s\n",
91 context->cork_data.function, function);
92 }
93 }
94
95 internal::ExecuteFormat(context->cork_data.message + message_length,
96 sizeof(context->cork_data.message) - message_length,
97 format, ap);
98}
99
100void VUnCork(int line, const char *function, log_level level, const char *file,
101 const char *format, va_list ap) {
102 Context *context = Context::Get();
103
104 VCork(line, function, format, ap);
105
106 log_do(level, "%s: %d-%d: %s: %s", file,
107 context->cork_data.line_min, context->cork_data.line_max, function,
108 context->cork_data.message);
109
110 context->cork_data.Reset();
111}
112
113} // namespace logging
114} // namespace aos
115
116void log_do(log_level level, const char *format, ...) {
117 va_list ap;
118 va_start(ap, format);
119 aos::logging::VLog(level, format, ap);
120 va_end(ap);
121}
122
123void log_cork(int line, const char *function, const char *format, ...) {
124 va_list ap;
125 va_start(ap, format);
126 aos::logging::VCork(line, function, format, ap);
127 va_end(ap);
128}
129
130void log_uncork(int line, const char *function, log_level level,
131 const char *file, const char *format, ...) {
132 va_list ap;
133 va_start(ap, format);
134 aos::logging::VUnCork(line, function, level, file, format, ap);
135 va_end(ap);
136}