blob: 48b5f0b733cba39abb531ce5a783cf1bba128907 [file] [log] [blame]
Brian Silvermancb5da1f2015-12-05 22:19:58 -05001#ifndef AOS_COMMON_LOGGING_IMPLEMENTATIONS_H_
2#define AOS_COMMON_LOGGING_IMPLEMENTATIONS_H_
Brian Silvermanf665d692013-02-17 22:11:39 -08003
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"
Brian Silvermancb5da1f2015-12-05 22:19:58 -050021#include "aos/common/logging/interface.h"
Austin Schuh044e18b2015-10-21 20:17:09 -070022#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 Silvermancb5da1f2015-12-05 22:19:58 -050028class RawQueue;
Brian Silvermand6974f42014-02-14 13:39:21 -080029
30} // namespace aos
31
Brian Silvermancb5da1f2015-12-05 22:19:58 -050032// This file has various concrete LogImplementations.
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 Silvermancb5da1f2015-12-05 22:19:58 -050040// using a function attribute.
Brian Silvermanf665d692013-02-17 22:11:39 -080041
Brian Silvermancb5da1f2015-12-05 22:19:58 -050042// Contains all of the information about a given logging call.
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;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070049 // message_length is just the length of the actual data (which member depends
50 // on the type).
Brian Silverman88471dc2014-02-15 22:35:42 -080051 size_t message_length, name_length;
Brian Silvermanf665d692013-02-17 22:11:39 -080052 pid_t source;
53 static_assert(sizeof(source) == 4, "that's how they get printed");
54 // Per task/thread.
55 uint16_t sequence;
Brian Silverman88471dc2014-02-15 22:35:42 -080056 Type type;
Brian Silvermanf665d692013-02-17 22:11:39 -080057 log_level level;
Austin Schuh044e18b2015-10-21 20:17:09 -070058 char name[LOG_MESSAGE_NAME_LEN];
Brian Silverman88471dc2014-02-15 22:35:42 -080059 union {
60 char message[LOG_MESSAGE_LEN];
61 struct {
62 uint32_t type_id;
63 size_t string_length;
64 // The message string and then the serialized structure.
65 char serialized[LOG_MESSAGE_LEN - sizeof(type) - sizeof(string_length)];
66 } structure;
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080067 struct {
68 // The type ID of the element type.
69 uint32_t type;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070070 int rows, cols;
71 size_t string_length;
72 // The message string and then the serialized matrix.
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080073 char
Brian Silvermanff12c9f2014-03-19 17:53:29 -070074 data[LOG_MESSAGE_LEN - sizeof(type) - sizeof(rows) - sizeof(cols)];
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080075 } matrix;
Brian Silverman88471dc2014-02-15 22:35:42 -080076 };
Brian Silvermanf665d692013-02-17 22:11:39 -080077};
78static_assert(shm_ok<LogMessage>::value, "it's going in a queue");
79
80// Returns left > right. LOG_UNKNOWN is most important.
81static inline bool log_gt_important(log_level left, log_level right) {
82 if (left == ERROR) left = 3;
83 if (right == ERROR) right = 3;
84 return left > right;
85}
86
87// Returns a string representing level or "unknown".
88static inline const char *log_str(log_level level) {
89#define DECL_LEVEL(name, value) if (level == name) return #name;
90 DECL_LEVELS;
91#undef DECL_LEVEL
92 return "unknown";
93}
94// Returns the log level represented by str or LOG_UNKNOWN.
95static inline log_level str_log(const char *str) {
96#define DECL_LEVEL(name, value) if (!strcmp(str, #name)) return name;
97 DECL_LEVELS;
98#undef DECL_LEVEL
99 return LOG_UNKNOWN;
100}
101
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500102// A LogImplementation where LogStruct and LogMatrix just create a string with
103// PrintMessage and then forward on to DoLog.
104class SimpleLogImplementation : public LogImplementation {
105 private:
106 void LogStruct(log_level level, const ::std::string &message, size_t size,
107 const MessageType *type,
108 const ::std::function<size_t(char *)> &serialize) override;
109 void LogMatrix(log_level level, const ::std::string &message,
110 uint32_t type_id, int rows, int cols,
111 const void *data) override;
112};
Brian Silvermanf665d692013-02-17 22:11:39 -0800113
Brian Silvermanbe858a12014-04-30 17:37:28 -0700114// Implements all of the DoLog* methods in terms of a (pure virtual in this
115// class) HandleMessage method that takes a pointer to the message.
116class HandleMessageLogImplementation : public LogImplementation {
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500117 private:
Brian Silvermanbe858a12014-04-30 17:37:28 -0700118 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500119 void DoLog(log_level level, const char *format, va_list ap) override;
120 void LogStruct(log_level level, const ::std::string &message_string,
121 size_t size, const MessageType *type,
122 const ::std::function<size_t(char *)> &serialize) override;
123 void LogMatrix(log_level level, const ::std::string &message_string,
124 uint32_t type_id, int rows, int cols,
125 const void *data) override;
Brian Silvermanbe858a12014-04-30 17:37:28 -0700126
127 virtual void HandleMessage(const LogMessage &message) = 0;
128};
129
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800130// A log implementation that dumps all messages to a C stdio stream.
Brian Silvermanbe858a12014-04-30 17:37:28 -0700131class StreamLogImplementation : public HandleMessageLogImplementation {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800132 public:
133 StreamLogImplementation(FILE *stream);
134
135 private:
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500136 void HandleMessage(const LogMessage &message) override;
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800137
138 FILE *const stream_;
139};
140
Brian Silvermanf665d692013-02-17 22:11:39 -0800141// Adds another implementation to the stack of implementations in this
142// task/thread.
143// Any tasks/threads created after this call will also use this implementation.
144// The cutoff is when the state in a given task/thread is created (either lazily
145// when needed or by calling Load()).
146// The logging system takes ownership of implementation. It will delete it if
147// necessary, so it must be created with new.
148void AddImplementation(LogImplementation *implementation);
149
150// Must be called at least once per process/load before anything else is
151// called. This function is safe to call multiple times from multiple
152// tasks/threads.
153void Init();
154
155// Forces all of the state that is usually lazily created when first needed to
156// be created when called. Cleanup() will delete it.
157void Load();
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500158
Brian Silvermanf665d692013-02-17 22:11:39 -0800159// Resets all information in this task/thread to its initial state.
160// NOTE: This is not the opposite of Init(). The state that this deletes is
161// lazily created when needed. It is actually the opposite of Load().
162void Cleanup();
163
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500164// Returns a queue which deals with LogMessage-sized messages.
165// The caller takes ownership.
166RawQueue *GetLoggingQueue();
167
168// Calls AddImplementation to register the standard linux logging implementation
169// which sends the messages through a queue. This implementation relies on
170// another process(es) to read the log messages that it puts into the queue.
171// This function is usually called by aos::Init*.
172void RegisterQueueImplementation();
173
Brian Silvermanf665d692013-02-17 22:11:39 -0800174// This is where all of the code that is only used by actual LogImplementations
175// goes.
176namespace internal {
177
Brian Silverman88471dc2014-02-15 22:35:42 -0800178// Fills in all the parts of message according to the given inputs (with type
179// kStruct).
180void FillInMessageStructure(log_level level,
181 const ::std::string &message_string, size_t size,
182 const MessageType *type,
183 const ::std::function<size_t(char *)> &serialize,
184 LogMessage *message);
185
Brian Silverman664db1a2014-03-20 17:06:29 -0700186// Fills in all the parts of the message according to the given inputs (with
187// type kMatrix).
188void FillInMessageMatrix(log_level level,
189 const ::std::string &message_string, uint32_t type_id,
190 int rows, int cols, const void *data,
191 LogMessage *message);
192
Brian Silverman88471dc2014-02-15 22:35:42 -0800193// Fills in *message according to the given inputs (with type kString).
194// Used for implementing LogImplementation::DoLog.
Brian Silvermanf665d692013-02-17 22:11:39 -0800195void FillInMessage(log_level level, const char *format, va_list ap,
Brian Silvermanf7986142014-04-21 17:42:35 -0700196 LogMessage *message)
197 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800198
Brian Silvermanf7986142014-04-21 17:42:35 -0700199__attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 4)))
Brian Silverman78968542014-03-05 17:03:43 -0800200static inline void FillInMessageVarargs(log_level level, LogMessage *message,
201 const char *format, ...) {
202 va_list ap;
203 va_start(ap, format);
204 FillInMessage(level, format, ap, message);
205 va_end(ap);
206}
207
Brian Silvermanf665d692013-02-17 22:11:39 -0800208// Prints message to output.
209void PrintMessage(FILE *output, const LogMessage &message);
210
Brian Silvermanf665d692013-02-17 22:11:39 -0800211} // namespace internal
212} // namespace logging
213} // namespace aos
214
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500215#endif // AOS_COMMON_LOGGING_IMPLEMENTATIONS_H_