blob: 5f7e1c52f967ae86c65f434e26d766a03fb07cb0 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_LOGGING_IMPLEMENTATIONS_H_
2#define AOS_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
John Park33858a32018-09-28 23:05:48 -070016#include "aos/logging/context.h"
17#include "aos/logging/interface.h"
18#include "aos/logging/logging.h"
19#include "aos/logging/sizes.h"
20#include "aos/macros.h"
21#include "aos/mutex/mutex.h"
Sabina Davis2ed5ea22017-09-26 22:27:42 -070022#include "aos/once.h"
Austin Schuh82c0c822019-05-27 19:55:20 -070023#include "aos/time/time.h"
24#include "aos/type_traits/type_traits.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080025
Brian Silvermand6974f42014-02-14 13:39:21 -080026namespace aos {
27
Brian Silvermanf7986142014-04-21 17:42:35 -070028struct MessageType;
Brian Silvermancb5da1f2015-12-05 22:19:58 -050029class RawQueue;
Brian Silvermand6974f42014-02-14 13:39:21 -080030
31} // namespace aos
32
Brian Silvermancb5da1f2015-12-05 22:19:58 -050033// This file has various concrete LogImplementations.
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 Silvermancb5da1f2015-12-05 22:19:58 -050041// using a function attribute.
Brian Silvermanf665d692013-02-17 22:11:39 -080042
Brian Silvermancb5da1f2015-12-05 22:19:58 -050043// Contains all of the information about a given logging call.
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;
Austin Schuh044e18b2015-10-21 20:17:09 -070059 char name[LOG_MESSAGE_NAME_LEN];
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
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500103// A LogImplementation where LogStruct and LogMatrix just create a string with
104// PrintMessage and then forward on to DoLog.
105class SimpleLogImplementation : public LogImplementation {
Austin Schuh82c0c822019-05-27 19:55:20 -0700106 protected:
107 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
108 return ::aos::monotonic_clock::now();
109 }
110
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500111 private:
112 void LogStruct(log_level level, const ::std::string &message, size_t size,
113 const MessageType *type,
114 const ::std::function<size_t(char *)> &serialize) override;
115 void LogMatrix(log_level level, const ::std::string &message,
116 uint32_t type_id, int rows, int cols,
117 const void *data) override;
118};
Brian Silvermanf665d692013-02-17 22:11:39 -0800119
Brian Silvermanbe858a12014-04-30 17:37:28 -0700120// Implements all of the DoLog* methods in terms of a (pure virtual in this
121// class) HandleMessage method that takes a pointer to the message.
122class HandleMessageLogImplementation : public LogImplementation {
Austin Schuh82c0c822019-05-27 19:55:20 -0700123 protected:
124 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
125 return ::aos::monotonic_clock::now();
126 }
127
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500128 private:
Brian Silvermanbe858a12014-04-30 17:37:28 -0700129 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500130 void DoLog(log_level level, const char *format, va_list ap) override;
131 void LogStruct(log_level level, const ::std::string &message_string,
132 size_t size, const MessageType *type,
133 const ::std::function<size_t(char *)> &serialize) override;
134 void LogMatrix(log_level level, const ::std::string &message_string,
135 uint32_t type_id, int rows, int cols,
136 const void *data) override;
Brian Silvermanbe858a12014-04-30 17:37:28 -0700137
138 virtual void HandleMessage(const LogMessage &message) = 0;
139};
140
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800141// A log implementation that dumps all messages to a C stdio stream.
Brian Silvermanbe858a12014-04-30 17:37:28 -0700142class StreamLogImplementation : public HandleMessageLogImplementation {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800143 public:
144 StreamLogImplementation(FILE *stream);
145
146 private:
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500147 void HandleMessage(const LogMessage &message) override;
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800148
149 FILE *const stream_;
150};
151
Brian Silvermanf665d692013-02-17 22:11:39 -0800152// Adds another implementation to the stack of implementations in this
153// task/thread.
154// Any tasks/threads created after this call will also use this implementation.
155// The cutoff is when the state in a given task/thread is created (either lazily
156// when needed or by calling Load()).
157// The logging system takes ownership of implementation. It will delete it if
158// necessary, so it must be created with new.
159void AddImplementation(LogImplementation *implementation);
160
161// Must be called at least once per process/load before anything else is
162// called. This function is safe to call multiple times from multiple
163// tasks/threads.
164void Init();
165
166// Forces all of the state that is usually lazily created when first needed to
167// be created when called. Cleanup() will delete it.
168void Load();
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500169
Brian Silvermanf665d692013-02-17 22:11:39 -0800170// Resets all information in this task/thread to its initial state.
171// NOTE: This is not the opposite of Init(). The state that this deletes is
172// lazily created when needed. It is actually the opposite of Load().
173void Cleanup();
174
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500175// Returns a queue which deals with LogMessage-sized messages.
176// The caller takes ownership.
177RawQueue *GetLoggingQueue();
178
179// Calls AddImplementation to register the standard linux logging implementation
180// which sends the messages through a queue. This implementation relies on
181// another process(es) to read the log messages that it puts into the queue.
182// This function is usually called by aos::Init*.
183void RegisterQueueImplementation();
184
Brian Silvermanf665d692013-02-17 22:11:39 -0800185// This is where all of the code that is only used by actual LogImplementations
186// goes.
187namespace internal {
188
Brian Silverman88471dc2014-02-15 22:35:42 -0800189// Fills in all the parts of message according to the given inputs (with type
190// kStruct).
Austin Schuh82c0c822019-05-27 19:55:20 -0700191void FillInMessageStructure(bool add_to_type_cache, log_level level,
192 ::aos::monotonic_clock::time_point monotonic_now,
Brian Silverman88471dc2014-02-15 22:35:42 -0800193 const ::std::string &message_string, size_t size,
194 const MessageType *type,
195 const ::std::function<size_t(char *)> &serialize,
196 LogMessage *message);
197
Brian Silverman664db1a2014-03-20 17:06:29 -0700198// Fills in all the parts of the message according to the given inputs (with
199// type kMatrix).
200void FillInMessageMatrix(log_level level,
Austin Schuh82c0c822019-05-27 19:55:20 -0700201 ::aos::monotonic_clock::time_point monotonic_now,
Brian Silverman664db1a2014-03-20 17:06:29 -0700202 const ::std::string &message_string, uint32_t type_id,
203 int rows, int cols, const void *data,
204 LogMessage *message);
205
Brian Silverman88471dc2014-02-15 22:35:42 -0800206// Fills in *message according to the given inputs (with type kString).
207// Used for implementing LogImplementation::DoLog.
Austin Schuh82c0c822019-05-27 19:55:20 -0700208void FillInMessage(log_level level,
209 ::aos::monotonic_clock::time_point monotonic_now,
210 const char *format, va_list ap, LogMessage *message)
211 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800212
Austin Schuh82c0c822019-05-27 19:55:20 -0700213__attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 4, 5))) static inline void
214FillInMessageVarargs(log_level level,
215 ::aos::monotonic_clock::time_point monotonic_now,
216 LogMessage *message, const char *format, ...) {
Brian Silverman78968542014-03-05 17:03:43 -0800217 va_list ap;
218 va_start(ap, format);
Austin Schuh82c0c822019-05-27 19:55:20 -0700219 FillInMessage(level, monotonic_now, format, ap, message);
Brian Silverman78968542014-03-05 17:03:43 -0800220 va_end(ap);
221}
222
Brian Silvermanf665d692013-02-17 22:11:39 -0800223// Prints message to output.
224void PrintMessage(FILE *output, const LogMessage &message);
225
Brian Silvermanf665d692013-02-17 22:11:39 -0800226} // namespace internal
227} // namespace logging
228} // namespace aos
229
John Park33858a32018-09-28 23:05:48 -0700230#endif // AOS_LOGGING_IMPLEMENTATIONS_H_