blob: 6a201aa4fcbc9215dbd26fd24b35bfd1265b260d [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/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
Austin Schuh044e18b2015-10-21 20:17:09 -07007#include <functional>
Tyler Chatow4b471e12020-01-05 20:19:36 -08008#include <type_traits>
Brian Silverman88471dc2014-02-15 22:35:42 -08009
John Park33858a32018-09-28 23:05:48 -070010#include "aos/die.h"
11#include "aos/logging/context.h"
Brian Silvermanb0893882014-02-10 14:48:30 -080012
Brian Silvermanb0893882014-02-10 14:48:30 -080013namespace aos {
14namespace logging {
15namespace internal {
16
Brian Silverman88471dc2014-02-15 22:35:42 -080017size_t ExecuteFormat(char *output, size_t output_size, const char *format,
18 va_list ap) {
19 static const char *const continued = "...\n";
Brian Silvermanb0893882014-02-10 14:48:30 -080020 const size_t size = output_size - strlen(continued);
21 const int ret = vsnprintf(output, size, format, ap);
Alex Perrycb7da4b2019-08-28 19:35:56 -070022 typedef ::std::common_type<int, size_t>::type RetType;
Brian Silvermanb0893882014-02-10 14:48:30 -080023 if (ret < 0) {
Tyler Chatow4b471e12020-01-05 20:19:36 -080024 AOS_PLOG(FATAL, "vsnprintf(%p, %zd, %s, args) failed", output, size,
25 format);
Brian Silverman88471dc2014-02-15 22:35:42 -080026 } else if (static_cast<RetType>(ret) >= static_cast<RetType>(size)) {
Brian Silvermanb0893882014-02-10 14:48:30 -080027 // Overwrite the '\0' at the end of the existing data and
28 // copy in the one on the end of continued.
29 memcpy(&output[size - 1], continued, strlen(continued) + 1);
30 }
Brian Silverman88471dc2014-02-15 22:35:42 -080031 return ::std::min<RetType>(ret, size);
Brian Silvermanb0893882014-02-10 14:48:30 -080032}
33
Brian Silvermand6974f42014-02-14 13:39:21 -080034void RunWithCurrentImplementation(
Tyler Chatow4b471e12020-01-05 20:19:36 -080035 ::std::function<void(LogImplementation *)> function) {
Brian Silvermanb0893882014-02-10 14:48:30 -080036 Context *context = Context::Get();
37
Austin Schuha0c41ba2020-09-10 22:59:14 -070038 const std::shared_ptr<LogImplementation> implementation =
39 context->implementation;
Tyler Chatow4b471e12020-01-05 20:19:36 -080040 if (implementation == NULL) {
41 Die("no logging implementation to use\n");
Brian Silvermanb0893882014-02-10 14:48:30 -080042 }
Austin Schuha0c41ba2020-09-10 22:59:14 -070043 function(implementation.get());
Brian Silvermand6974f42014-02-14 13:39:21 -080044}
Brian Silvermanb0893882014-02-10 14:48:30 -080045
Brian Silvermand6974f42014-02-14 13:39:21 -080046} // namespace internal
47
48using internal::Context;
49
Tyler Chatow4b471e12020-01-05 20:19:36 -080050void LogImplementation::DoVLog(log_level level, const char *format,
51 va_list ap) {
Austin Schuh39700802016-11-26 21:23:56 -080052 auto log_impl = [&](LogImplementation *implementation) {
Brian Silvermane6335e42014-02-20 20:53:06 -080053 va_list ap1;
54 va_copy(ap1, ap);
55 implementation->DoLog(level, format, ap1);
56 va_end(ap1);
Brian Silvermand6974f42014-02-14 13:39:21 -080057
58 if (level == FATAL) {
59 VDie(format, ap);
60 }
Austin Schuh39700802016-11-26 21:23:56 -080061 };
Tyler Chatow4b471e12020-01-05 20:19:36 -080062 internal::RunWithCurrentImplementation(::std::ref(log_impl));
Brian Silvermanb0893882014-02-10 14:48:30 -080063}
64
65void VLog(log_level level, const char *format, va_list ap) {
Tyler Chatow4b471e12020-01-05 20:19:36 -080066 LogImplementation::DoVLog(level, format, ap);
Brian Silvermanb0893882014-02-10 14:48:30 -080067}
68
69void VCork(int line, const char *function, const char *format, va_list ap) {
70 Context *context = Context::Get();
71
72 const size_t message_length = strlen(context->cork_data.message);
73 if (line > context->cork_data.line_max) context->cork_data.line_max = line;
74 if (line < context->cork_data.line_min) context->cork_data.line_min = line;
75
76 if (context->cork_data.function == NULL) {
77 context->cork_data.function = function;
78 } else {
79 if (strcmp(context->cork_data.function, function) != 0) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070080 AOS_LOG(FATAL,
81 "started corking data in function %s but then moved to %s\n",
82 context->cork_data.function, function);
Brian Silvermanb0893882014-02-10 14:48:30 -080083 }
84 }
85
86 internal::ExecuteFormat(context->cork_data.message + message_length,
87 sizeof(context->cork_data.message) - message_length,
88 format, ap);
89}
90
91void VUnCork(int line, const char *function, log_level level, const char *file,
92 const char *format, va_list ap) {
93 Context *context = Context::Get();
94
95 VCork(line, function, format, ap);
96
Tyler Chatow4b471e12020-01-05 20:19:36 -080097 log_do(level, "%s: %d-%d: %s: %s", file, context->cork_data.line_min,
98 context->cork_data.line_max, function, context->cork_data.message);
Brian Silvermanb0893882014-02-10 14:48:30 -080099
100 context->cork_data.Reset();
101}
102
103} // namespace logging
104} // namespace aos
105
106void log_do(log_level level, const char *format, ...) {
107 va_list ap;
108 va_start(ap, format);
109 aos::logging::VLog(level, format, ap);
110 va_end(ap);
111}
112
113void log_cork(int line, const char *function, const char *format, ...) {
114 va_list ap;
115 va_start(ap, format);
116 aos::logging::VCork(line, function, format, ap);
117 va_end(ap);
118}
119
120void log_uncork(int line, const char *function, log_level level,
121 const char *file, const char *format, ...) {
122 va_list ap;
123 va_start(ap, format);
124 aos::logging::VUnCork(line, function, level, file, format, ap);
125 va_end(ap);
126}