blob: ab4b7289aab8e2081d69ac4ae6bafb716345f130 [file] [log] [blame]
Brian Silvermanf665d692013-02-17 22:11:39 -08001#ifndef AOS_COMMON_LOGGING_LOGGING_IMPL_H_
2#define AOS_COMMON_LOGGING_LOGGING_IMPL_H_
3
4#include <sys/types.h>
5#include <unistd.h>
6#include <stdint.h>
7#include <limits.h>
8#include <string.h>
9#include <stdio.h>
Brian Silverman669669f2014-02-14 16:32:56 -080010#include <stdarg.h>
Brian Silvermanf665d692013-02-17 22:11:39 -080011
12#include <string>
Brian Silvermand6974f42014-02-14 13:39:21 -080013#include <functional>
Brian Silverman6da04272014-05-18 18:47:48 -070014#include <atomic>
Brian Silvermanf665d692013-02-17 22:11:39 -080015
16#include "aos/common/logging/logging.h"
17#include "aos/common/type_traits.h"
18#include "aos/common/mutex.h"
Brian Silvermanf7986142014-04-21 17:42:35 -070019#include "aos/common/macros.h"
Austin Schuh044e18b2015-10-21 20:17:09 -070020#include "aos/common/logging/sizes.h"
21#include "aos/common/logging/logging_interface.h"
22#include "aos/common/logging/context.h"
23#include "aos/common/once.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080024
Brian Silvermand6974f42014-02-14 13:39:21 -080025namespace aos {
26
Brian Silvermanf7986142014-04-21 17:42:35 -070027struct MessageType;
Brian Silvermand6974f42014-02-14 13:39:21 -080028
29} // namespace aos
30
Brian Silvermanf665d692013-02-17 22:11:39 -080031// This file has all of the logging implementation. It can't be #included by C
32// code like logging.h can.
Brian Silverman1a572cc2013-03-05 19:58:01 -080033// It is useful for the rest of the logging implementation and other C++ code
34// that needs to do special things with logging.
Brian Silvermanb0893882014-02-10 14:48:30 -080035//
36// It is implemented in logging_impl.cc and logging_interface.cc. They are
37// separate so that code used by logging_impl.cc can link in
Brian Silverman6da04272014-05-18 18:47:48 -070038// logging_interface.cc to use logging without creating a circular dependency.
39// However, any executables with such code still need logging_impl.cc linked in.
Brian Silvermanf665d692013-02-17 22:11:39 -080040
41namespace aos {
42namespace logging {
43
44// Unless explicitly stated otherwise, format must always be a string constant,
45// args are printf-style arguments for format, and ap is a va_list of args.
Brian Silverman1a572cc2013-03-05 19:58:01 -080046// The validity of format and args together will be checked at compile time
Brian Silvermanf665d692013-02-17 22:11:39 -080047// using a gcc function attribute.
48
49// The struct that the code uses for making logging calls.
Brian Silverman88471dc2014-02-15 22:35:42 -080050struct LogMessage {
51 enum class Type : uint8_t {
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080052 kString, kStruct, kMatrix
Brian Silverman88471dc2014-02-15 22:35:42 -080053 };
54
55 int32_t seconds, nseconds;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070056 // message_length is just the length of the actual data (which member depends
57 // on the type).
Brian Silverman88471dc2014-02-15 22:35:42 -080058 size_t message_length, name_length;
Brian Silvermanf665d692013-02-17 22:11:39 -080059 pid_t source;
60 static_assert(sizeof(source) == 4, "that's how they get printed");
61 // Per task/thread.
62 uint16_t sequence;
Brian Silverman88471dc2014-02-15 22:35:42 -080063 Type type;
Brian Silvermanf665d692013-02-17 22:11:39 -080064 log_level level;
Austin Schuh044e18b2015-10-21 20:17:09 -070065 char name[LOG_MESSAGE_NAME_LEN];
Brian Silverman88471dc2014-02-15 22:35:42 -080066 union {
67 char message[LOG_MESSAGE_LEN];
68 struct {
69 uint32_t type_id;
70 size_t string_length;
71 // The message string and then the serialized structure.
72 char serialized[LOG_MESSAGE_LEN - sizeof(type) - sizeof(string_length)];
73 } structure;
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080074 struct {
75 // The type ID of the element type.
76 uint32_t type;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070077 int rows, cols;
78 size_t string_length;
79 // The message string and then the serialized matrix.
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080080 char
Brian Silvermanff12c9f2014-03-19 17:53:29 -070081 data[LOG_MESSAGE_LEN - sizeof(type) - sizeof(rows) - sizeof(cols)];
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080082 } matrix;
Brian Silverman88471dc2014-02-15 22:35:42 -080083 };
Brian Silvermanf665d692013-02-17 22:11:39 -080084};
85static_assert(shm_ok<LogMessage>::value, "it's going in a queue");
86
87// Returns left > right. LOG_UNKNOWN is most important.
88static inline bool log_gt_important(log_level left, log_level right) {
89 if (left == ERROR) left = 3;
90 if (right == ERROR) right = 3;
91 return left > right;
92}
93
94// Returns a string representing level or "unknown".
95static inline const char *log_str(log_level level) {
96#define DECL_LEVEL(name, value) if (level == name) return #name;
97 DECL_LEVELS;
98#undef DECL_LEVEL
99 return "unknown";
100}
101// Returns the log level represented by str or LOG_UNKNOWN.
102static inline log_level str_log(const char *str) {
103#define DECL_LEVEL(name, value) if (!strcmp(str, #name)) return name;
104 DECL_LEVELS;
105#undef DECL_LEVEL
106 return LOG_UNKNOWN;
107}
108
109// Takes a message and logs it. It will set everything up and then call DoLog
110// for the current LogImplementation.
Brian Silvermanf7986142014-04-21 17:42:35 -0700111void VLog(log_level level, const char *format, va_list ap)
112 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800113// Adds to the saved up message.
Brian Silvermanf7986142014-04-21 17:42:35 -0700114void VCork(int line, const char *function, const char *format, va_list ap)
115 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800116// Actually logs the saved up message.
Brian Silvermanf7986142014-04-21 17:42:35 -0700117void VUnCork(int line, const char *function, log_level level, const char *file,
118 const char *format, va_list ap)
119 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 5, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800120
121// Will call VLog with the given arguments for the next logger in the chain.
122void LogNext(log_level level, const char *format, ...)
Brian Silvermanf7986142014-04-21 17:42:35 -0700123 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 3)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800124
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800125// Takes a structure and log it.
Brian Silvermand6974f42014-02-14 13:39:21 -0800126template <class T>
127void DoLogStruct(log_level, const ::std::string &, const T &);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800128// Takes a matrix and logs it.
129template <class T>
130void DoLogMatrix(log_level, const ::std::string &, const T &);
Brian Silvermand6974f42014-02-14 13:39:21 -0800131
Brian Silvermanf665d692013-02-17 22:11:39 -0800132
Brian Silvermanbe858a12014-04-30 17:37:28 -0700133// Implements all of the DoLog* methods in terms of a (pure virtual in this
134// class) HandleMessage method that takes a pointer to the message.
135class HandleMessageLogImplementation : public LogImplementation {
136 public:
137 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
138 virtual void DoLog(log_level level, const char *format, va_list ap) override;
139 virtual void LogStruct(log_level level, const ::std::string &message_string,
140 size_t size, const MessageType *type,
141 const ::std::function<size_t(char *)> &serialize)
142 override;
143 virtual void LogMatrix(log_level level, const ::std::string &message_string,
144 uint32_t type_id, int rows, int cols, const void *data)
145 override;
146
147 virtual void HandleMessage(const LogMessage &message) = 0;
148};
149
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800150// A log implementation that dumps all messages to a C stdio stream.
Brian Silvermanbe858a12014-04-30 17:37:28 -0700151class StreamLogImplementation : public HandleMessageLogImplementation {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800152 public:
153 StreamLogImplementation(FILE *stream);
154
155 private:
Brian Silvermanbe858a12014-04-30 17:37:28 -0700156 virtual void HandleMessage(const LogMessage &message) override;
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800157
158 FILE *const stream_;
159};
160
Brian Silvermanf665d692013-02-17 22:11:39 -0800161// Adds another implementation to the stack of implementations in this
162// task/thread.
163// Any tasks/threads created after this call will also use this implementation.
164// The cutoff is when the state in a given task/thread is created (either lazily
165// when needed or by calling Load()).
166// The logging system takes ownership of implementation. It will delete it if
167// necessary, so it must be created with new.
168void AddImplementation(LogImplementation *implementation);
169
170// Must be called at least once per process/load before anything else is
171// called. This function is safe to call multiple times from multiple
172// tasks/threads.
173void Init();
174
175// Forces all of the state that is usually lazily created when first needed to
176// be created when called. Cleanup() will delete it.
177void Load();
178// Resets all information in this task/thread to its initial state.
179// NOTE: This is not the opposite of Init(). The state that this deletes is
180// lazily created when needed. It is actually the opposite of Load().
181void Cleanup();
182
183// This is where all of the code that is only used by actual LogImplementations
184// goes.
185namespace internal {
186
Brian Silverman88471dc2014-02-15 22:35:42 -0800187// Fills in all the parts of message according to the given inputs (with type
188// kStruct).
189void FillInMessageStructure(log_level level,
190 const ::std::string &message_string, size_t size,
191 const MessageType *type,
192 const ::std::function<size_t(char *)> &serialize,
193 LogMessage *message);
194
Brian Silverman664db1a2014-03-20 17:06:29 -0700195// Fills in all the parts of the message according to the given inputs (with
196// type kMatrix).
197void FillInMessageMatrix(log_level level,
198 const ::std::string &message_string, uint32_t type_id,
199 int rows, int cols, const void *data,
200 LogMessage *message);
201
Brian Silverman88471dc2014-02-15 22:35:42 -0800202// Fills in *message according to the given inputs (with type kString).
203// Used for implementing LogImplementation::DoLog.
Brian Silvermanf665d692013-02-17 22:11:39 -0800204void FillInMessage(log_level level, const char *format, va_list ap,
Brian Silvermanf7986142014-04-21 17:42:35 -0700205 LogMessage *message)
206 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800207
Brian Silvermanf7986142014-04-21 17:42:35 -0700208__attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 4)))
Brian Silverman78968542014-03-05 17:03:43 -0800209static inline void FillInMessageVarargs(log_level level, LogMessage *message,
210 const char *format, ...) {
211 va_list ap;
212 va_start(ap, format);
213 FillInMessage(level, format, ap, message);
214 va_end(ap);
215}
216
Brian Silvermanf665d692013-02-17 22:11:39 -0800217// Prints message to output.
218void PrintMessage(FILE *output, const LogMessage &message);
219
Brian Silvermanb0893882014-02-10 14:48:30 -0800220// Prints format (with ap) into output and correctly deals with the result
221// being too long etc.
Brian Silverman88471dc2014-02-15 22:35:42 -0800222size_t ExecuteFormat(char *output, size_t output_size, const char *format,
Brian Silvermanf7986142014-04-21 17:42:35 -0700223 va_list ap)
224 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
Brian Silvermanb0893882014-02-10 14:48:30 -0800225
Brian Silvermand6974f42014-02-14 13:39:21 -0800226// Runs the given function with the current LogImplementation (handles switching
227// it out while running function etc).
Brian Silvermanfe457de2014-05-26 22:04:08 -0700228// levels is how many LogImplementations to not use off the stack.
Brian Silvermand6974f42014-02-14 13:39:21 -0800229void RunWithCurrentImplementation(
230 int levels, ::std::function<void(LogImplementation *)> function);
231
Brian Silvermanf665d692013-02-17 22:11:39 -0800232} // namespace internal
233} // namespace logging
234} // namespace aos
235
236#endif // AOS_COMMON_LOGGING_LOGGING_IMPL_H_