blob: 6cf8376de3dd10b729f16f5d6a1e1d36aa477a3e [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
Tyler Chatow5febd8f2020-01-05 18:25:31 -08004#include <limits.h>
5#include <stdarg.h>
6#include <stdint.h>
7#include <stdio.h>
8#include <string.h>
Brian Silvermanf665d692013-02-17 22:11:39 -08009#include <sys/types.h>
10#include <unistd.h>
Brian Silvermanf665d692013-02-17 22:11:39 -080011
Brian Silverman6da04272014-05-18 18:47:48 -070012#include <atomic>
Tyler Chatow5febd8f2020-01-05 18:25:31 -080013#include <functional>
14#include <string>
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 {
Tyler Chatow5febd8f2020-01-05 18:25:31 -080045 enum class Type : uint8_t { kString };
Brian Silverman88471dc2014-02-15 22:35:42 -080046
47 int32_t seconds, nseconds;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070048 // message_length is just the length of the actual data (which member depends
49 // on the type).
Brian Silverman88471dc2014-02-15 22:35:42 -080050 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;
Austin Schuh044e18b2015-10-21 20:17:09 -070057 char name[LOG_MESSAGE_NAME_LEN];
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;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070069 int rows, cols;
70 size_t string_length;
71 // The message string and then the serialized matrix.
Tyler Chatow5febd8f2020-01-05 18:25:31 -080072 char data[LOG_MESSAGE_LEN - sizeof(type) - sizeof(rows) - sizeof(cols)];
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080073 } matrix;
Brian Silverman88471dc2014-02-15 22:35:42 -080074 };
Brian Silvermanf665d692013-02-17 22:11:39 -080075};
76static_assert(shm_ok<LogMessage>::value, "it's going in a queue");
77
78// Returns left > right. LOG_UNKNOWN is most important.
79static inline bool log_gt_important(log_level left, log_level right) {
80 if (left == ERROR) left = 3;
81 if (right == ERROR) right = 3;
82 return left > right;
83}
84
85// Returns a string representing level or "unknown".
86static inline const char *log_str(log_level level) {
Tyler Chatow5febd8f2020-01-05 18:25:31 -080087#define DECL_LEVEL(name, value) \
88 if (level == name) return #name;
Brian Silvermanf665d692013-02-17 22:11:39 -080089 DECL_LEVELS;
90#undef DECL_LEVEL
91 return "unknown";
92}
93// Returns the log level represented by str or LOG_UNKNOWN.
94static inline log_level str_log(const char *str) {
Tyler Chatow5febd8f2020-01-05 18:25:31 -080095#define DECL_LEVEL(name, value) \
96 if (!strcmp(str, #name)) return name;
Brian Silvermanf665d692013-02-17 22:11:39 -080097 DECL_LEVELS;
98#undef DECL_LEVEL
99 return LOG_UNKNOWN;
100}
101
Brian Silvermanbe858a12014-04-30 17:37:28 -0700102// Implements all of the DoLog* methods in terms of a (pure virtual in this
103// class) HandleMessage method that takes a pointer to the message.
104class HandleMessageLogImplementation : public LogImplementation {
Austin Schuh82c0c822019-05-27 19:55:20 -0700105 protected:
106 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
107 return ::aos::monotonic_clock::now();
108 }
109
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500110 private:
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800111 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
112 log_level level, const char *format, va_list ap) override;
Brian Silvermanbe858a12014-04-30 17:37:28 -0700113
114 virtual void HandleMessage(const LogMessage &message) = 0;
115};
116
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800117// A log implementation that dumps all messages to a C stdio stream.
Brian Silvermanbe858a12014-04-30 17:37:28 -0700118class StreamLogImplementation : public HandleMessageLogImplementation {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800119 public:
120 StreamLogImplementation(FILE *stream);
121
122 private:
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500123 void HandleMessage(const LogMessage &message) override;
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800124
125 FILE *const stream_;
126};
127
Brian Silvermanf665d692013-02-17 22:11:39 -0800128// Adds another implementation to the stack of implementations in this
129// task/thread.
130// Any tasks/threads created after this call will also use this implementation.
131// The cutoff is when the state in a given task/thread is created (either lazily
132// when needed or by calling Load()).
133// The logging system takes ownership of implementation. It will delete it if
134// necessary, so it must be created with new.
Tyler Chatow67ddb032020-01-12 14:30:04 -0800135// TODO: Log implementations are never deleted. Need means to safely deregister.
Tyler Chatow4b471e12020-01-05 20:19:36 -0800136void SetImplementation(LogImplementation *implementation,
137 bool update_global = true);
138
139// Updates the log implementation for the current thread, returning the current
140// implementation.
141LogImplementation *SwapImplementation(LogImplementation *implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -0800142
Tyler Chatow67ddb032020-01-12 14:30:04 -0800143LogImplementation *GetImplementation();
144
Brian Silvermanf665d692013-02-17 22:11:39 -0800145// Must be called at least once per process/load before anything else is
146// called. This function is safe to call multiple times from multiple
147// tasks/threads.
148void Init();
149
150// Forces all of the state that is usually lazily created when first needed to
151// be created when called. Cleanup() will delete it.
152void Load();
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500153
Brian Silvermanf665d692013-02-17 22:11:39 -0800154// Resets all information in this task/thread to its initial state.
155// NOTE: This is not the opposite of Init(). The state that this deletes is
156// lazily created when needed. It is actually the opposite of Load().
157void Cleanup();
158
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500159// Returns a queue which deals with LogMessage-sized messages.
160// The caller takes ownership.
161RawQueue *GetLoggingQueue();
162
Tyler Chatow4b471e12020-01-05 20:19:36 -0800163// Calls SetImplementation to register the standard linux logging implementation
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500164// which sends the messages through a queue. This implementation relies on
165// another process(es) to read the log messages that it puts into the queue.
166// This function is usually called by aos::Init*.
167void RegisterQueueImplementation();
168
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800169void RegisterCallbackImplementation(
Tyler Chatow67ddb032020-01-12 14:30:04 -0800170 const ::std::function<void(const LogMessage &)> &callback,
171 bool update_global = true);
172
173class ScopedLogRestorer {
174 public:
175 ScopedLogRestorer() { prev_impl_ = GetImplementation(); }
176
177 ~ScopedLogRestorer() { SetImplementation(prev_impl_); }
178
179 private:
180 LogImplementation *prev_impl_;
181};
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800182
Brian Silvermanf665d692013-02-17 22:11:39 -0800183// This is where all of the code that is only used by actual LogImplementations
184// goes.
185namespace internal {
186
Brian Silverman88471dc2014-02-15 22:35:42 -0800187// Fills in *message according to the given inputs (with type kString).
188// Used for implementing LogImplementation::DoLog.
Austin Schuh82c0c822019-05-27 19:55:20 -0700189void FillInMessage(log_level level,
190 ::aos::monotonic_clock::time_point monotonic_now,
191 const char *format, va_list ap, LogMessage *message)
192 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800193
Austin Schuh82c0c822019-05-27 19:55:20 -0700194__attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 4, 5))) static inline void
195FillInMessageVarargs(log_level level,
196 ::aos::monotonic_clock::time_point monotonic_now,
197 LogMessage *message, const char *format, ...) {
Brian Silverman78968542014-03-05 17:03:43 -0800198 va_list ap;
199 va_start(ap, format);
Austin Schuh82c0c822019-05-27 19:55:20 -0700200 FillInMessage(level, monotonic_now, format, ap, message);
Brian Silverman78968542014-03-05 17:03:43 -0800201 va_end(ap);
202}
203
Brian Silvermanf665d692013-02-17 22:11:39 -0800204// Prints message to output.
205void PrintMessage(FILE *output, const LogMessage &message);
206
Brian Silvermanf665d692013-02-17 22:11:39 -0800207} // namespace internal
208} // namespace logging
209} // namespace aos
210
John Park33858a32018-09-28 23:05:48 -0700211#endif // AOS_LOGGING_IMPLEMENTATIONS_H_