blob: 57f09ec998f9391b4a8d19737095705542b4503c [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 Silvermanf665d692013-02-17 22:11:39 -080014
15#include "aos/common/logging/logging.h"
16#include "aos/common/type_traits.h"
17#include "aos/common/mutex.h"
Brian Silvermanf7986142014-04-21 17:42:35 -070018#include "aos/common/macros.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080019
Brian Silvermand6974f42014-02-14 13:39:21 -080020namespace aos {
21
Brian Silvermanf7986142014-04-21 17:42:35 -070022struct MessageType;
Brian Silvermand6974f42014-02-14 13:39:21 -080023
24} // namespace aos
25
Brian Silvermanf665d692013-02-17 22:11:39 -080026// This file has all of the logging implementation. It can't be #included by C
27// code like logging.h can.
Brian Silverman1a572cc2013-03-05 19:58:01 -080028// It is useful for the rest of the logging implementation and other C++ code
29// that needs to do special things with logging.
Brian Silvermanb0893882014-02-10 14:48:30 -080030//
31// It is implemented in logging_impl.cc and logging_interface.cc. They are
32// separate so that code used by logging_impl.cc can link in
33// logging_interface.cc to use logging.
Brian Silvermanf665d692013-02-17 22:11:39 -080034
35namespace aos {
36namespace logging {
37
38// Unless explicitly stated otherwise, format must always be a string constant,
39// args are printf-style arguments for format, and ap is a va_list of args.
Brian Silverman1a572cc2013-03-05 19:58:01 -080040// The validity of format and args together will be checked at compile time
Brian Silvermanf665d692013-02-17 22:11:39 -080041// using a gcc function attribute.
42
43// The struct that the code uses for making logging calls.
Brian Silverman88471dc2014-02-15 22:35:42 -080044struct LogMessage {
45 enum class Type : uint8_t {
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080046 kString, kStruct, kMatrix
Brian Silverman88471dc2014-02-15 22:35:42 -080047 };
48
49 int32_t seconds, nseconds;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070050 // message_length is just the length of the actual data (which member depends
51 // on the type).
Brian Silverman88471dc2014-02-15 22:35:42 -080052 size_t message_length, name_length;
Brian Silvermanf665d692013-02-17 22:11:39 -080053 pid_t source;
54 static_assert(sizeof(source) == 4, "that's how they get printed");
55 // Per task/thread.
56 uint16_t sequence;
Brian Silverman88471dc2014-02-15 22:35:42 -080057 Type type;
Brian Silvermanf665d692013-02-17 22:11:39 -080058 log_level level;
Brian Silvermanf665d692013-02-17 22:11:39 -080059 char name[100];
Brian Silverman88471dc2014-02-15 22:35:42 -080060 union {
61 char message[LOG_MESSAGE_LEN];
62 struct {
63 uint32_t type_id;
64 size_t string_length;
65 // The message string and then the serialized structure.
66 char serialized[LOG_MESSAGE_LEN - sizeof(type) - sizeof(string_length)];
67 } structure;
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080068 struct {
69 // The type ID of the element type.
70 uint32_t type;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070071 int rows, cols;
72 size_t string_length;
73 // The message string and then the serialized matrix.
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080074 char
Brian Silvermanff12c9f2014-03-19 17:53:29 -070075 data[LOG_MESSAGE_LEN - sizeof(type) - sizeof(rows) - sizeof(cols)];
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080076 } matrix;
Brian Silverman88471dc2014-02-15 22:35:42 -080077 };
Brian Silvermanf665d692013-02-17 22:11:39 -080078};
79static_assert(shm_ok<LogMessage>::value, "it's going in a queue");
80
81// Returns left > right. LOG_UNKNOWN is most important.
82static inline bool log_gt_important(log_level left, log_level right) {
83 if (left == ERROR) left = 3;
84 if (right == ERROR) right = 3;
85 return left > right;
86}
87
88// Returns a string representing level or "unknown".
89static inline const char *log_str(log_level level) {
90#define DECL_LEVEL(name, value) if (level == name) return #name;
91 DECL_LEVELS;
92#undef DECL_LEVEL
93 return "unknown";
94}
95// Returns the log level represented by str or LOG_UNKNOWN.
96static inline log_level str_log(const char *str) {
97#define DECL_LEVEL(name, value) if (!strcmp(str, #name)) return name;
98 DECL_LEVELS;
99#undef DECL_LEVEL
100 return LOG_UNKNOWN;
101}
102
103// Takes a message and logs it. It will set everything up and then call DoLog
104// for the current LogImplementation.
Brian Silvermanf7986142014-04-21 17:42:35 -0700105void VLog(log_level level, const char *format, va_list ap)
106 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800107// Adds to the saved up message.
Brian Silvermanf7986142014-04-21 17:42:35 -0700108void VCork(int line, const char *function, const char *format, va_list ap)
109 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800110// Actually logs the saved up message.
Brian Silvermanf7986142014-04-21 17:42:35 -0700111void VUnCork(int line, const char *function, log_level level, const char *file,
112 const char *format, va_list ap)
113 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 5, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800114
115// Will call VLog with the given arguments for the next logger in the chain.
116void LogNext(log_level level, const char *format, ...)
Brian Silvermanf7986142014-04-21 17:42:35 -0700117 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 3)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800118
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800119// Takes a structure and log it.
Brian Silvermand6974f42014-02-14 13:39:21 -0800120template <class T>
121void DoLogStruct(log_level, const ::std::string &, const T &);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800122// Takes a matrix and logs it.
123template <class T>
124void DoLogMatrix(log_level, const ::std::string &, const T &);
Brian Silvermand6974f42014-02-14 13:39:21 -0800125
Brian Silvermanf665d692013-02-17 22:11:39 -0800126// Represents a system that can actually take log messages and do something
127// useful with them.
128// All of the code (transitively too!) in the DoLog here can make
129// normal LOG and LOG_DYNAMIC calls but can NOT call LOG_CORK/LOG_UNCORK. These
130// calls will not result in DoLog recursing. However, implementations must be
131// safe to call from multiple threads/tasks at the same time. Also, any other
132// overriden methods may end up logging through a given implementation's DoLog.
133class LogImplementation {
134 public:
135 LogImplementation() : next_(NULL) {}
136
137 // The one that this one's implementation logs to.
138 // NULL means that there is no next one.
139 LogImplementation *next() { return next_; }
140 // Virtual in case a subclass wants to perform checks. There will be a valid
141 // logger other than this one available while this is called.
142 virtual void set_next(LogImplementation *next) { next_ = next; }
143
144 private:
145 // Actually logs the given message. Implementations should somehow create a
146 // LogMessage and then call internal::FillInMessage.
Brian Silvermanf7986142014-04-21 17:42:35 -0700147 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silvermanf665d692013-02-17 22:11:39 -0800148 virtual void DoLog(log_level level, const char *format, va_list ap) = 0;
Brian Silvermanf7986142014-04-21 17:42:35 -0700149 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 4)))
Brian Silverman669669f2014-02-14 16:32:56 -0800150 void DoLogVariadic(log_level level, const char *format, ...) {
151 va_list ap;
152 va_start(ap, format);
153 DoLog(level, format, ap);
154 va_end(ap);
155 }
Brian Silvermanf665d692013-02-17 22:11:39 -0800156
Brian Silvermand6974f42014-02-14 13:39:21 -0800157 // Logs the contents of an auto-generated structure. The implementation here
158 // just converts it to a string with PrintMessage and then calls DoLog with
159 // that, however some implementations can be a lot more efficient than that.
160 // size and type are the result of calling Size() and Type() on the type of
161 // the message.
162 // serialize will call Serialize on the message.
163 virtual void LogStruct(log_level level, const ::std::string &message,
164 size_t size, const MessageType *type,
165 const ::std::function<size_t(char *)> &serialize);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800166 // Similiar to LogStruct, except for matrixes.
167 // type_id is the type of the elements of the matrix.
168 // data points to rows*cols*type_id.Size() bytes of data in row-major order.
169 virtual void LogMatrix(log_level level, const ::std::string &message,
170 uint32_t type_id, int rows, int cols,
171 const void *data);
Brian Silvermand6974f42014-02-14 13:39:21 -0800172
173 // These functions call similar methods on the "current" LogImplementation or
174 // Die if they can't find one.
175 // levels is how many LogImplementations to not use off the stack.
Brian Silvermanf7986142014-04-21 17:42:35 -0700176 static void DoVLog(log_level, const char *format, va_list ap, int levels)
177 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
Brian Silvermand6974f42014-02-14 13:39:21 -0800178 // This one is implemented in queue_logging.cc.
179 static void DoLogStruct(log_level level, const ::std::string &message,
180 size_t size, const MessageType *type,
181 const ::std::function<size_t(char *)> &serialize,
182 int levels);
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700183 // This one is implemented in matrix_logging.cc.
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800184 static void DoLogMatrix(log_level level, const ::std::string &message,
185 uint32_t type_id, int rows, int cols,
Brian Silvermanff12c9f2014-03-19 17:53:29 -0700186 const void *data, int levels);
Brian Silvermand6974f42014-02-14 13:39:21 -0800187
188 // Friends so that they can access the static Do* functions.
Brian Silvermanf665d692013-02-17 22:11:39 -0800189 friend void VLog(log_level, const char *, va_list);
190 friend void LogNext(log_level, const char *, ...);
Brian Silvermand6974f42014-02-14 13:39:21 -0800191 template <class T>
192 friend void DoLogStruct(log_level, const ::std::string &, const T &);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800193 template <class T>
194 friend void DoLogMatrix(log_level, const ::std::string &, const T &);
Brian Silvermanf665d692013-02-17 22:11:39 -0800195
196 LogImplementation *next_;
197};
198
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800199// A log implementation that dumps all messages to a C stdio stream.
200class StreamLogImplementation : public LogImplementation {
201 public:
202 StreamLogImplementation(FILE *stream);
203
204 private:
Brian Silvermanf7986142014-04-21 17:42:35 -0700205 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800206 virtual void DoLog(log_level level, const char *format, va_list ap);
207
208 FILE *const stream_;
209};
210
Brian Silvermanf665d692013-02-17 22:11:39 -0800211// Adds another implementation to the stack of implementations in this
212// task/thread.
213// Any tasks/threads created after this call will also use this implementation.
214// The cutoff is when the state in a given task/thread is created (either lazily
215// when needed or by calling Load()).
216// The logging system takes ownership of implementation. It will delete it if
217// necessary, so it must be created with new.
218void AddImplementation(LogImplementation *implementation);
219
220// Must be called at least once per process/load before anything else is
221// called. This function is safe to call multiple times from multiple
222// tasks/threads.
223void Init();
224
225// Forces all of the state that is usually lazily created when first needed to
226// be created when called. Cleanup() will delete it.
227void Load();
228// Resets all information in this task/thread to its initial state.
229// NOTE: This is not the opposite of Init(). The state that this deletes is
230// lazily created when needed. It is actually the opposite of Load().
231void Cleanup();
232
233// This is where all of the code that is only used by actual LogImplementations
234// goes.
235namespace internal {
236
Brian Silvermanb0893882014-02-10 14:48:30 -0800237extern LogImplementation *global_top_implementation;
238
Brian Silvermanf665d692013-02-17 22:11:39 -0800239// An separate instance of this class is accessible from each task/thread.
Brian Silverman1a572cc2013-03-05 19:58:01 -0800240// NOTE: It will get deleted in the child of a fork.
Brian Silvermanf665d692013-02-17 22:11:39 -0800241struct Context {
242 Context();
243
244 // Gets the Context object for this task/thread. Will create one the first
245 // time it is called.
246 //
247 // The implementation for each platform will lazily instantiate a new instance
248 // and then initialize name the first time.
249 // IMPORTANT: The implementation of this can not use logging.
250 static Context *Get();
251 // Deletes the Context object for this task/thread so that the next Get() is
252 // called it will create a new one.
253 // It is valid to call this when Get() has never been called.
254 static void Delete();
255
256 // Which one to log to right now.
257 // Will be NULL if there is no logging implementation to use right now.
258 LogImplementation *implementation;
259
Brian Silvermanab6615c2013-03-05 20:29:29 -0800260 // A name representing this task/(process and thread).
261 // strlen(name.c_str()) must be <= sizeof(LogMessage::name).
262 ::std::string name;
Brian Silvermanf665d692013-02-17 22:11:39 -0800263
264 // What to assign LogMessage::source to in this task/thread.
265 pid_t source;
266
267 // The sequence value to send out with the next message.
268 uint16_t sequence;
269
270 // Contains all of the information related to implementing LOG_CORK and
271 // LOG_UNCORK.
272 struct {
273 char message[LOG_MESSAGE_LEN];
274 int line_min, line_max;
275 // Sets the data up to record a new series of corked logs.
276 void Reset() {
277 message[0] = '\0'; // make strlen of it 0
278 line_min = INT_MAX;
279 line_max = -1;
280 function = NULL;
281 }
282 // The function that the calls are in.
283 // REMEMBER: While the compiler/linker will probably optimize all of the
284 // identical strings to point to the same data, it might not, so using == to
285 // compare this with another value is a bad idea.
286 const char *function;
287 } cork_data;
288};
289
Brian Silverman88471dc2014-02-15 22:35:42 -0800290// Fills in all the parts of message according to the given inputs (with type
291// kStruct).
292void FillInMessageStructure(log_level level,
293 const ::std::string &message_string, size_t size,
294 const MessageType *type,
295 const ::std::function<size_t(char *)> &serialize,
296 LogMessage *message);
297
Brian Silverman664db1a2014-03-20 17:06:29 -0700298// Fills in all the parts of the message according to the given inputs (with
299// type kMatrix).
300void FillInMessageMatrix(log_level level,
301 const ::std::string &message_string, uint32_t type_id,
302 int rows, int cols, const void *data,
303 LogMessage *message);
304
Brian Silverman88471dc2014-02-15 22:35:42 -0800305// Fills in *message according to the given inputs (with type kString).
306// Used for implementing LogImplementation::DoLog.
Brian Silvermanf665d692013-02-17 22:11:39 -0800307void FillInMessage(log_level level, const char *format, va_list ap,
Brian Silvermanf7986142014-04-21 17:42:35 -0700308 LogMessage *message)
309 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800310
Brian Silvermanf7986142014-04-21 17:42:35 -0700311__attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 4)))
Brian Silverman78968542014-03-05 17:03:43 -0800312static inline void FillInMessageVarargs(log_level level, LogMessage *message,
313 const char *format, ...) {
314 va_list ap;
315 va_start(ap, format);
316 FillInMessage(level, format, ap, message);
317 va_end(ap);
318}
319
Brian Silvermanf665d692013-02-17 22:11:39 -0800320// Prints message to output.
321void PrintMessage(FILE *output, const LogMessage &message);
322
Brian Silvermanb0893882014-02-10 14:48:30 -0800323// Prints format (with ap) into output and correctly deals with the result
324// being too long etc.
Brian Silverman88471dc2014-02-15 22:35:42 -0800325size_t ExecuteFormat(char *output, size_t output_size, const char *format,
Brian Silvermanf7986142014-04-21 17:42:35 -0700326 va_list ap)
327 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
Brian Silvermanb0893882014-02-10 14:48:30 -0800328
Brian Silvermand6974f42014-02-14 13:39:21 -0800329// Runs the given function with the current LogImplementation (handles switching
330// it out while running function etc).
331void RunWithCurrentImplementation(
332 int levels, ::std::function<void(LogImplementation *)> function);
333
Brian Silvermanf665d692013-02-17 22:11:39 -0800334} // namespace internal
335} // namespace logging
336} // namespace aos
337
338#endif // AOS_COMMON_LOGGING_LOGGING_IMPL_H_