blob: f24ce6ae8620d491fe5e99213d4a5b305a5368d2 [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"
Brian Silvermanf665d692013-02-17 22:11:39 -080020
Brian Silvermand6974f42014-02-14 13:39:21 -080021namespace aos {
22
Brian Silvermanf7986142014-04-21 17:42:35 -070023struct MessageType;
Brian Silvermand6974f42014-02-14 13:39:21 -080024
25} // namespace aos
26
Brian Silvermanf665d692013-02-17 22:11:39 -080027// This file has all of the logging implementation. It can't be #included by C
28// code like logging.h can.
Brian Silverman1a572cc2013-03-05 19:58:01 -080029// It is useful for the rest of the logging implementation and other C++ code
30// that needs to do special things with logging.
Brian Silvermanb0893882014-02-10 14:48:30 -080031//
32// It is implemented in logging_impl.cc and logging_interface.cc. They are
33// separate so that code used by logging_impl.cc can link in
Brian Silverman6da04272014-05-18 18:47:48 -070034// logging_interface.cc to use logging without creating a circular dependency.
35// However, any executables with such code still need logging_impl.cc linked in.
Brian Silvermanf665d692013-02-17 22:11:39 -080036
37namespace aos {
38namespace logging {
39
40// Unless explicitly stated otherwise, format must always be a string constant,
41// args are printf-style arguments for format, and ap is a va_list of args.
Brian Silverman1a572cc2013-03-05 19:58:01 -080042// The validity of format and args together will be checked at compile time
Brian Silvermanf665d692013-02-17 22:11:39 -080043// using a gcc function attribute.
44
45// The struct that the code uses for making logging calls.
Brian Silverman88471dc2014-02-15 22:35:42 -080046struct LogMessage {
47 enum class Type : uint8_t {
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080048 kString, kStruct, kMatrix
Brian Silverman88471dc2014-02-15 22:35:42 -080049 };
50
51 int32_t seconds, nseconds;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070052 // message_length is just the length of the actual data (which member depends
53 // on the type).
Brian Silverman88471dc2014-02-15 22:35:42 -080054 size_t message_length, name_length;
Brian Silvermanf665d692013-02-17 22:11:39 -080055 pid_t source;
56 static_assert(sizeof(source) == 4, "that's how they get printed");
57 // Per task/thread.
58 uint16_t sequence;
Brian Silverman88471dc2014-02-15 22:35:42 -080059 Type type;
Brian Silvermanf665d692013-02-17 22:11:39 -080060 log_level level;
Brian Silvermanf665d692013-02-17 22:11:39 -080061 char name[100];
Brian Silverman88471dc2014-02-15 22:35:42 -080062 union {
63 char message[LOG_MESSAGE_LEN];
64 struct {
65 uint32_t type_id;
66 size_t string_length;
67 // The message string and then the serialized structure.
68 char serialized[LOG_MESSAGE_LEN - sizeof(type) - sizeof(string_length)];
69 } structure;
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080070 struct {
71 // The type ID of the element type.
72 uint32_t type;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070073 int rows, cols;
74 size_t string_length;
75 // The message string and then the serialized matrix.
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080076 char
Brian Silvermanff12c9f2014-03-19 17:53:29 -070077 data[LOG_MESSAGE_LEN - sizeof(type) - sizeof(rows) - sizeof(cols)];
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080078 } matrix;
Brian Silverman88471dc2014-02-15 22:35:42 -080079 };
Brian Silvermanf665d692013-02-17 22:11:39 -080080};
81static_assert(shm_ok<LogMessage>::value, "it's going in a queue");
82
83// Returns left > right. LOG_UNKNOWN is most important.
84static inline bool log_gt_important(log_level left, log_level right) {
85 if (left == ERROR) left = 3;
86 if (right == ERROR) right = 3;
87 return left > right;
88}
89
90// Returns a string representing level or "unknown".
91static inline const char *log_str(log_level level) {
92#define DECL_LEVEL(name, value) if (level == name) return #name;
93 DECL_LEVELS;
94#undef DECL_LEVEL
95 return "unknown";
96}
97// Returns the log level represented by str or LOG_UNKNOWN.
98static inline log_level str_log(const char *str) {
99#define DECL_LEVEL(name, value) if (!strcmp(str, #name)) return name;
100 DECL_LEVELS;
101#undef DECL_LEVEL
102 return LOG_UNKNOWN;
103}
104
105// Takes a message and logs it. It will set everything up and then call DoLog
106// for the current LogImplementation.
Brian Silvermanf7986142014-04-21 17:42:35 -0700107void VLog(log_level level, const char *format, va_list ap)
108 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800109// Adds to the saved up message.
Brian Silvermanf7986142014-04-21 17:42:35 -0700110void VCork(int line, const char *function, const char *format, va_list ap)
111 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800112// Actually logs the saved up message.
Brian Silvermanf7986142014-04-21 17:42:35 -0700113void VUnCork(int line, const char *function, log_level level, const char *file,
114 const char *format, va_list ap)
115 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 5, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800116
117// Will call VLog with the given arguments for the next logger in the chain.
118void LogNext(log_level level, const char *format, ...)
Brian Silvermanf7986142014-04-21 17:42:35 -0700119 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 3)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800120
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800121// Takes a structure and log it.
Brian Silvermand6974f42014-02-14 13:39:21 -0800122template <class T>
123void DoLogStruct(log_level, const ::std::string &, const T &);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800124// Takes a matrix and logs it.
125template <class T>
126void DoLogMatrix(log_level, const ::std::string &, const T &);
Brian Silvermand6974f42014-02-14 13:39:21 -0800127
Brian Silvermanf665d692013-02-17 22:11:39 -0800128// Represents a system that can actually take log messages and do something
129// useful with them.
130// All of the code (transitively too!) in the DoLog here can make
131// normal LOG and LOG_DYNAMIC calls but can NOT call LOG_CORK/LOG_UNCORK. These
132// calls will not result in DoLog recursing. However, implementations must be
133// safe to call from multiple threads/tasks at the same time. Also, any other
134// overriden methods may end up logging through a given implementation's DoLog.
135class LogImplementation {
136 public:
137 LogImplementation() : next_(NULL) {}
138
139 // The one that this one's implementation logs to.
140 // NULL means that there is no next one.
141 LogImplementation *next() { return next_; }
142 // Virtual in case a subclass wants to perform checks. There will be a valid
143 // logger other than this one available while this is called.
144 virtual void set_next(LogImplementation *next) { next_ = next; }
145
146 private:
147 // Actually logs the given message. Implementations should somehow create a
148 // LogMessage and then call internal::FillInMessage.
Brian Silvermanf7986142014-04-21 17:42:35 -0700149 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silvermanf665d692013-02-17 22:11:39 -0800150 virtual void DoLog(log_level level, const char *format, va_list ap) = 0;
Brian Silvermanf7986142014-04-21 17:42:35 -0700151 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 4)))
Brian Silverman669669f2014-02-14 16:32:56 -0800152 void DoLogVariadic(log_level level, const char *format, ...) {
153 va_list ap;
154 va_start(ap, format);
155 DoLog(level, format, ap);
156 va_end(ap);
157 }
Brian Silvermanf665d692013-02-17 22:11:39 -0800158
Brian Silvermand6974f42014-02-14 13:39:21 -0800159 // Logs the contents of an auto-generated structure. The implementation here
160 // just converts it to a string with PrintMessage and then calls DoLog with
161 // that, however some implementations can be a lot more efficient than that.
162 // size and type are the result of calling Size() and Type() on the type of
163 // the message.
164 // serialize will call Serialize on the message.
165 virtual void LogStruct(log_level level, const ::std::string &message,
166 size_t size, const MessageType *type,
167 const ::std::function<size_t(char *)> &serialize);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800168 // Similiar to LogStruct, except for matrixes.
169 // type_id is the type of the elements of the matrix.
170 // data points to rows*cols*type_id.Size() bytes of data in row-major order.
171 virtual void LogMatrix(log_level level, const ::std::string &message,
172 uint32_t type_id, int rows, int cols,
173 const void *data);
Brian Silvermand6974f42014-02-14 13:39:21 -0800174
175 // These functions call similar methods on the "current" LogImplementation or
176 // Die if they can't find one.
177 // levels is how many LogImplementations to not use off the stack.
Brian Silvermanf7986142014-04-21 17:42:35 -0700178 static void DoVLog(log_level, const char *format, va_list ap, int levels)
179 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
Brian Silvermand6974f42014-02-14 13:39:21 -0800180 // This one is implemented in queue_logging.cc.
181 static void DoLogStruct(log_level level, const ::std::string &message,
182 size_t size, const MessageType *type,
183 const ::std::function<size_t(char *)> &serialize,
184 int levels);
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700185 // This one is implemented in matrix_logging.cc.
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800186 static void DoLogMatrix(log_level level, const ::std::string &message,
187 uint32_t type_id, int rows, int cols,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700188 const void *data, int levels);
Brian Silvermand6974f42014-02-14 13:39:21 -0800189
190 // Friends so that they can access the static Do* functions.
Brian Silvermanf665d692013-02-17 22:11:39 -0800191 friend void VLog(log_level, const char *, va_list);
192 friend void LogNext(log_level, const char *, ...);
Brian Silvermand6974f42014-02-14 13:39:21 -0800193 template <class T>
194 friend void DoLogStruct(log_level, const ::std::string &, const T &);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800195 template <class T>
196 friend void DoLogMatrix(log_level, const ::std::string &, const T &);
Brian Silvermanf665d692013-02-17 22:11:39 -0800197
198 LogImplementation *next_;
199};
200
Brian Silvermanbe858a12014-04-30 17:37:28 -0700201// Implements all of the DoLog* methods in terms of a (pure virtual in this
202// class) HandleMessage method that takes a pointer to the message.
203class HandleMessageLogImplementation : public LogImplementation {
204 public:
205 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
206 virtual void DoLog(log_level level, const char *format, va_list ap) override;
207 virtual void LogStruct(log_level level, const ::std::string &message_string,
208 size_t size, const MessageType *type,
209 const ::std::function<size_t(char *)> &serialize)
210 override;
211 virtual void LogMatrix(log_level level, const ::std::string &message_string,
212 uint32_t type_id, int rows, int cols, const void *data)
213 override;
214
215 virtual void HandleMessage(const LogMessage &message) = 0;
216};
217
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800218// A log implementation that dumps all messages to a C stdio stream.
Brian Silvermanbe858a12014-04-30 17:37:28 -0700219class StreamLogImplementation : public HandleMessageLogImplementation {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800220 public:
221 StreamLogImplementation(FILE *stream);
222
223 private:
Brian Silvermanbe858a12014-04-30 17:37:28 -0700224 virtual void HandleMessage(const LogMessage &message) override;
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800225
226 FILE *const stream_;
227};
228
Brian Silvermanf665d692013-02-17 22:11:39 -0800229// Adds another implementation to the stack of implementations in this
230// task/thread.
231// Any tasks/threads created after this call will also use this implementation.
232// The cutoff is when the state in a given task/thread is created (either lazily
233// when needed or by calling Load()).
234// The logging system takes ownership of implementation. It will delete it if
235// necessary, so it must be created with new.
236void AddImplementation(LogImplementation *implementation);
237
238// Must be called at least once per process/load before anything else is
239// called. This function is safe to call multiple times from multiple
240// tasks/threads.
241void Init();
242
243// Forces all of the state that is usually lazily created when first needed to
244// be created when called. Cleanup() will delete it.
245void Load();
246// Resets all information in this task/thread to its initial state.
247// NOTE: This is not the opposite of Init(). The state that this deletes is
248// lazily created when needed. It is actually the opposite of Load().
249void Cleanup();
250
251// This is where all of the code that is only used by actual LogImplementations
252// goes.
253namespace internal {
254
Brian Silverman6da04272014-05-18 18:47:48 -0700255extern ::std::atomic<LogImplementation *> global_top_implementation;
Brian Silvermanb0893882014-02-10 14:48:30 -0800256
Brian Silvermanf665d692013-02-17 22:11:39 -0800257// An separate instance of this class is accessible from each task/thread.
Brian Silverman1a572cc2013-03-05 19:58:01 -0800258// NOTE: It will get deleted in the child of a fork.
Brian Silverman6da04272014-05-18 18:47:48 -0700259//
260// Get() and Delete() are implemented in the platform-specific interface.cc
261// file.
Brian Silvermanf665d692013-02-17 22:11:39 -0800262struct Context {
263 Context();
264
265 // Gets the Context object for this task/thread. Will create one the first
266 // time it is called.
267 //
268 // The implementation for each platform will lazily instantiate a new instance
269 // and then initialize name the first time.
270 // IMPORTANT: The implementation of this can not use logging.
271 static Context *Get();
272 // Deletes the Context object for this task/thread so that the next Get() is
273 // called it will create a new one.
274 // It is valid to call this when Get() has never been called.
Brian Silverman6da04272014-05-18 18:47:48 -0700275 // This also gets called after a fork(2) in the new process, where it should
276 // still work to clean up any state.
Brian Silvermanf665d692013-02-17 22:11:39 -0800277 static void Delete();
278
279 // Which one to log to right now.
280 // Will be NULL if there is no logging implementation to use right now.
281 LogImplementation *implementation;
282
Brian Silvermanab6615c2013-03-05 20:29:29 -0800283 // A name representing this task/(process and thread).
284 // strlen(name.c_str()) must be <= sizeof(LogMessage::name).
285 ::std::string name;
Brian Silvermanf665d692013-02-17 22:11:39 -0800286
287 // What to assign LogMessage::source to in this task/thread.
288 pid_t source;
289
290 // The sequence value to send out with the next message.
291 uint16_t sequence;
292
293 // Contains all of the information related to implementing LOG_CORK and
294 // LOG_UNCORK.
295 struct {
296 char message[LOG_MESSAGE_LEN];
297 int line_min, line_max;
298 // Sets the data up to record a new series of corked logs.
299 void Reset() {
300 message[0] = '\0'; // make strlen of it 0
301 line_min = INT_MAX;
302 line_max = -1;
303 function = NULL;
304 }
305 // The function that the calls are in.
306 // REMEMBER: While the compiler/linker will probably optimize all of the
307 // identical strings to point to the same data, it might not, so using == to
308 // compare this with another value is a bad idea.
309 const char *function;
310 } cork_data;
311};
312
Brian Silverman88471dc2014-02-15 22:35:42 -0800313// Fills in all the parts of message according to the given inputs (with type
314// kStruct).
315void FillInMessageStructure(log_level level,
316 const ::std::string &message_string, size_t size,
317 const MessageType *type,
318 const ::std::function<size_t(char *)> &serialize,
319 LogMessage *message);
320
Brian Silverman664db1a2014-03-20 17:06:29 -0700321// Fills in all the parts of the message according to the given inputs (with
322// type kMatrix).
323void FillInMessageMatrix(log_level level,
324 const ::std::string &message_string, uint32_t type_id,
325 int rows, int cols, const void *data,
326 LogMessage *message);
327
Brian Silverman88471dc2014-02-15 22:35:42 -0800328// Fills in *message according to the given inputs (with type kString).
329// Used for implementing LogImplementation::DoLog.
Brian Silvermanf665d692013-02-17 22:11:39 -0800330void FillInMessage(log_level level, const char *format, va_list ap,
Brian Silvermanf7986142014-04-21 17:42:35 -0700331 LogMessage *message)
332 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800333
Brian Silvermanf7986142014-04-21 17:42:35 -0700334__attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 4)))
Brian Silverman78968542014-03-05 17:03:43 -0800335static inline void FillInMessageVarargs(log_level level, LogMessage *message,
336 const char *format, ...) {
337 va_list ap;
338 va_start(ap, format);
339 FillInMessage(level, format, ap, message);
340 va_end(ap);
341}
342
Brian Silvermanf665d692013-02-17 22:11:39 -0800343// Prints message to output.
344void PrintMessage(FILE *output, const LogMessage &message);
345
Brian Silvermanb0893882014-02-10 14:48:30 -0800346// Prints format (with ap) into output and correctly deals with the result
347// being too long etc.
Brian Silverman88471dc2014-02-15 22:35:42 -0800348size_t ExecuteFormat(char *output, size_t output_size, const char *format,
Brian Silvermanf7986142014-04-21 17:42:35 -0700349 va_list ap)
350 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
Brian Silvermanb0893882014-02-10 14:48:30 -0800351
Brian Silvermand6974f42014-02-14 13:39:21 -0800352// Runs the given function with the current LogImplementation (handles switching
353// it out while running function etc).
354void RunWithCurrentImplementation(
355 int levels, ::std::function<void(LogImplementation *)> function);
356
Brian Silvermanf665d692013-02-17 22:11:39 -0800357} // namespace internal
358} // namespace logging
359} // namespace aos
360
361#endif // AOS_COMMON_LOGGING_LOGGING_IMPL_H_