blob: 11b28b0707dd1efbb934537a2500ddab680a9127 [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"
18
Brian Silvermand6974f42014-02-14 13:39:21 -080019namespace aos {
20
21class MessageType;
22
23} // namespace aos
24
Brian Silvermanf665d692013-02-17 22:11:39 -080025// This file has all of the logging implementation. It can't be #included by C
26// code like logging.h can.
Brian Silverman1a572cc2013-03-05 19:58:01 -080027// It is useful for the rest of the logging implementation and other C++ code
28// that needs to do special things with logging.
Brian Silvermanb0893882014-02-10 14:48:30 -080029//
30// It is implemented in logging_impl.cc and logging_interface.cc. They are
31// separate so that code used by logging_impl.cc can link in
32// logging_interface.cc to use logging.
Brian Silvermanf665d692013-02-17 22:11:39 -080033
34namespace aos {
35namespace logging {
36
37// Unless explicitly stated otherwise, format must always be a string constant,
38// args are printf-style arguments for format, and ap is a va_list of args.
Brian Silverman1a572cc2013-03-05 19:58:01 -080039// The validity of format and args together will be checked at compile time
Brian Silvermanf665d692013-02-17 22:11:39 -080040// using a gcc function attribute.
41
42// The struct that the code uses for making logging calls.
Brian Silverman88471dc2014-02-15 22:35:42 -080043struct LogMessage {
44 enum class Type : uint8_t {
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080045 kString, kStruct, kMatrix
Brian Silverman88471dc2014-02-15 22:35:42 -080046 };
47
48 int32_t seconds, nseconds;
49 // message_length is the length of everything in message for all types.
50 size_t message_length, name_length;
Brian Silvermanf665d692013-02-17 22:11:39 -080051 pid_t source;
52 static_assert(sizeof(source) == 4, "that's how they get printed");
53 // Per task/thread.
54 uint16_t sequence;
Brian Silverman88471dc2014-02-15 22:35:42 -080055 Type type;
Brian Silvermanf665d692013-02-17 22:11:39 -080056 log_level level;
Brian Silvermanf665d692013-02-17 22:11:39 -080057 char name[100];
Brian Silverman88471dc2014-02-15 22:35:42 -080058 union {
59 char message[LOG_MESSAGE_LEN];
60 struct {
61 uint32_t type_id;
62 size_t string_length;
63 // The message string and then the serialized structure.
64 char serialized[LOG_MESSAGE_LEN - sizeof(type) - sizeof(string_length)];
65 } structure;
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080066 struct {
67 // The type ID of the element type.
68 uint32_t type;
69 int rows, columns;
70 char
71 data[LOG_MESSAGE_LEN - sizeof(type) - sizeof(rows) - sizeof(columns)];
72 } matrix;
Brian Silverman88471dc2014-02-15 22:35:42 -080073 };
Brian Silvermanf665d692013-02-17 22:11:39 -080074};
75static_assert(shm_ok<LogMessage>::value, "it's going in a queue");
76
77// Returns left > right. LOG_UNKNOWN is most important.
78static inline bool log_gt_important(log_level left, log_level right) {
79 if (left == ERROR) left = 3;
80 if (right == ERROR) right = 3;
81 return left > right;
82}
83
84// Returns a string representing level or "unknown".
85static inline const char *log_str(log_level level) {
86#define DECL_LEVEL(name, value) if (level == name) return #name;
87 DECL_LEVELS;
88#undef DECL_LEVEL
89 return "unknown";
90}
91// Returns the log level represented by str or LOG_UNKNOWN.
92static inline log_level str_log(const char *str) {
93#define DECL_LEVEL(name, value) if (!strcmp(str, #name)) return name;
94 DECL_LEVELS;
95#undef DECL_LEVEL
96 return LOG_UNKNOWN;
97}
98
99// Takes a message and logs it. It will set everything up and then call DoLog
100// for the current LogImplementation.
101void VLog(log_level level, const char *format, va_list ap);
102// Adds to the saved up message.
103void VCork(int line, const char *format, va_list ap);
104// Actually logs the saved up message.
105void VUnCork(int line, log_level level, const char *file,
106 const char *format, va_list ap);
107
108// Will call VLog with the given arguments for the next logger in the chain.
109void LogNext(log_level level, const char *format, ...)
110 __attribute__((format(LOG_PRINTF_FORMAT_TYPE, 2, 3)));
111
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800112// Takes a structure and log it.
Brian Silvermand6974f42014-02-14 13:39:21 -0800113template <class T>
114void DoLogStruct(log_level, const ::std::string &, const T &);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800115// Takes a matrix and logs it.
116template <class T>
117void DoLogMatrix(log_level, const ::std::string &, const T &);
Brian Silvermand6974f42014-02-14 13:39:21 -0800118
Brian Silvermanf665d692013-02-17 22:11:39 -0800119// Represents a system that can actually take log messages and do something
120// useful with them.
121// All of the code (transitively too!) in the DoLog here can make
122// normal LOG and LOG_DYNAMIC calls but can NOT call LOG_CORK/LOG_UNCORK. These
123// calls will not result in DoLog recursing. However, implementations must be
124// safe to call from multiple threads/tasks at the same time. Also, any other
125// overriden methods may end up logging through a given implementation's DoLog.
126class LogImplementation {
127 public:
128 LogImplementation() : next_(NULL) {}
129
130 // The one that this one's implementation logs to.
131 // NULL means that there is no next one.
132 LogImplementation *next() { return next_; }
133 // Virtual in case a subclass wants to perform checks. There will be a valid
134 // logger other than this one available while this is called.
135 virtual void set_next(LogImplementation *next) { next_ = next; }
136
137 private:
138 // Actually logs the given message. Implementations should somehow create a
139 // LogMessage and then call internal::FillInMessage.
140 virtual void DoLog(log_level level, const char *format, va_list ap) = 0;
Brian Silverman669669f2014-02-14 16:32:56 -0800141 void DoLogVariadic(log_level level, const char *format, ...) {
142 va_list ap;
143 va_start(ap, format);
144 DoLog(level, format, ap);
145 va_end(ap);
146 }
Brian Silvermanf665d692013-02-17 22:11:39 -0800147
Brian Silvermand6974f42014-02-14 13:39:21 -0800148 // Logs the contents of an auto-generated structure. The implementation here
149 // just converts it to a string with PrintMessage and then calls DoLog with
150 // that, however some implementations can be a lot more efficient than that.
151 // size and type are the result of calling Size() and Type() on the type of
152 // the message.
153 // serialize will call Serialize on the message.
154 virtual void LogStruct(log_level level, const ::std::string &message,
155 size_t size, const MessageType *type,
156 const ::std::function<size_t(char *)> &serialize);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800157 // Similiar to LogStruct, except for matrixes.
158 // type_id is the type of the elements of the matrix.
159 // data points to rows*cols*type_id.Size() bytes of data in row-major order.
160 virtual void LogMatrix(log_level level, const ::std::string &message,
161 uint32_t type_id, int rows, int cols,
162 const void *data);
Brian Silvermand6974f42014-02-14 13:39:21 -0800163
164 // These functions call similar methods on the "current" LogImplementation or
165 // Die if they can't find one.
166 // levels is how many LogImplementations to not use off the stack.
Brian Silvermanf665d692013-02-17 22:11:39 -0800167 static void DoVLog(log_level, const char *format, va_list ap, int levels);
Brian Silvermand6974f42014-02-14 13:39:21 -0800168 // This one is implemented in queue_logging.cc.
169 static void DoLogStruct(log_level level, const ::std::string &message,
170 size_t size, const MessageType *type,
171 const ::std::function<size_t(char *)> &serialize,
172 int levels);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800173 static void DoLogMatrix(log_level level, const ::std::string &message,
174 uint32_t type_id, int rows, int cols,
175 const void *data);
Brian Silvermand6974f42014-02-14 13:39:21 -0800176
177 // Friends so that they can access the static Do* functions.
Brian Silvermanf665d692013-02-17 22:11:39 -0800178 friend void VLog(log_level, const char *, va_list);
179 friend void LogNext(log_level, const char *, ...);
Brian Silvermand6974f42014-02-14 13:39:21 -0800180 template <class T>
181 friend void DoLogStruct(log_level, const ::std::string &, const T &);
Brian Silvermanfd5e2a32014-02-22 20:02:39 -0800182 template <class T>
183 friend void DoLogMatrix(log_level, const ::std::string &, const T &);
Brian Silvermanf665d692013-02-17 22:11:39 -0800184
185 LogImplementation *next_;
186};
187
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800188// A log implementation that dumps all messages to a C stdio stream.
189class StreamLogImplementation : public LogImplementation {
190 public:
191 StreamLogImplementation(FILE *stream);
192
193 private:
194 virtual void DoLog(log_level level, const char *format, va_list ap);
195
196 FILE *const stream_;
197};
198
Brian Silvermanf665d692013-02-17 22:11:39 -0800199// Adds another implementation to the stack of implementations in this
200// task/thread.
201// Any tasks/threads created after this call will also use this implementation.
202// The cutoff is when the state in a given task/thread is created (either lazily
203// when needed or by calling Load()).
204// The logging system takes ownership of implementation. It will delete it if
205// necessary, so it must be created with new.
206void AddImplementation(LogImplementation *implementation);
207
208// Must be called at least once per process/load before anything else is
209// called. This function is safe to call multiple times from multiple
210// tasks/threads.
211void Init();
212
213// Forces all of the state that is usually lazily created when first needed to
214// be created when called. Cleanup() will delete it.
215void Load();
216// Resets all information in this task/thread to its initial state.
217// NOTE: This is not the opposite of Init(). The state that this deletes is
218// lazily created when needed. It is actually the opposite of Load().
219void Cleanup();
220
221// This is where all of the code that is only used by actual LogImplementations
222// goes.
223namespace internal {
224
Brian Silvermanb0893882014-02-10 14:48:30 -0800225extern LogImplementation *global_top_implementation;
226
Brian Silvermanf665d692013-02-17 22:11:39 -0800227// An separate instance of this class is accessible from each task/thread.
Brian Silverman1a572cc2013-03-05 19:58:01 -0800228// NOTE: It will get deleted in the child of a fork.
Brian Silvermanf665d692013-02-17 22:11:39 -0800229struct Context {
230 Context();
231
232 // Gets the Context object for this task/thread. Will create one the first
233 // time it is called.
234 //
235 // The implementation for each platform will lazily instantiate a new instance
236 // and then initialize name the first time.
237 // IMPORTANT: The implementation of this can not use logging.
238 static Context *Get();
239 // Deletes the Context object for this task/thread so that the next Get() is
240 // called it will create a new one.
241 // It is valid to call this when Get() has never been called.
242 static void Delete();
243
244 // Which one to log to right now.
245 // Will be NULL if there is no logging implementation to use right now.
246 LogImplementation *implementation;
247
Brian Silvermanab6615c2013-03-05 20:29:29 -0800248 // A name representing this task/(process and thread).
249 // strlen(name.c_str()) must be <= sizeof(LogMessage::name).
250 ::std::string name;
Brian Silvermanf665d692013-02-17 22:11:39 -0800251
252 // What to assign LogMessage::source to in this task/thread.
253 pid_t source;
254
255 // The sequence value to send out with the next message.
256 uint16_t sequence;
257
258 // Contains all of the information related to implementing LOG_CORK and
259 // LOG_UNCORK.
260 struct {
261 char message[LOG_MESSAGE_LEN];
262 int line_min, line_max;
263 // Sets the data up to record a new series of corked logs.
264 void Reset() {
265 message[0] = '\0'; // make strlen of it 0
266 line_min = INT_MAX;
267 line_max = -1;
268 function = NULL;
269 }
270 // The function that the calls are in.
271 // REMEMBER: While the compiler/linker will probably optimize all of the
272 // identical strings to point to the same data, it might not, so using == to
273 // compare this with another value is a bad idea.
274 const char *function;
275 } cork_data;
276};
277
Brian Silverman88471dc2014-02-15 22:35:42 -0800278// Fills in all the parts of message according to the given inputs (with type
279// kStruct).
280void FillInMessageStructure(log_level level,
281 const ::std::string &message_string, size_t size,
282 const MessageType *type,
283 const ::std::function<size_t(char *)> &serialize,
284 LogMessage *message);
285
286// Fills in *message according to the given inputs (with type kString).
287// Used for implementing LogImplementation::DoLog.
Brian Silvermanf665d692013-02-17 22:11:39 -0800288void FillInMessage(log_level level, const char *format, va_list ap,
289 LogMessage *message);
290
291// Prints message to output.
292void PrintMessage(FILE *output, const LogMessage &message);
293
Brian Silvermanb0893882014-02-10 14:48:30 -0800294// Prints format (with ap) into output and correctly deals with the result
295// being too long etc.
Brian Silverman88471dc2014-02-15 22:35:42 -0800296size_t ExecuteFormat(char *output, size_t output_size, const char *format,
297 va_list ap);
Brian Silvermanb0893882014-02-10 14:48:30 -0800298
Brian Silvermand6974f42014-02-14 13:39:21 -0800299// Runs the given function with the current LogImplementation (handles switching
300// it out while running function etc).
301void RunWithCurrentImplementation(
302 int levels, ::std::function<void(LogImplementation *)> function);
303
Brian Silvermanf665d692013-02-17 22:11:39 -0800304} // namespace internal
305} // namespace logging
306} // namespace aos
307
308#endif // AOS_COMMON_LOGGING_LOGGING_IMPL_H_