blob: e8a2213b4347480f4ef57a6c289a521518b1650e [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>
Austin Schuha0c41ba2020-09-10 22:59:14 -070014#include <memory>
Tyler Chatow5febd8f2020-01-05 18:25:31 -080015#include <string>
Brian Silvermanf665d692013-02-17 22:11:39 -080016
John Park33858a32018-09-28 23:05:48 -070017#include "aos/logging/context.h"
18#include "aos/logging/interface.h"
19#include "aos/logging/logging.h"
20#include "aos/logging/sizes.h"
21#include "aos/macros.h"
22#include "aos/mutex/mutex.h"
Sabina Davis2ed5ea22017-09-26 22:27:42 -070023#include "aos/once.h"
Austin Schuh82c0c822019-05-27 19:55:20 -070024#include "aos/time/time.h"
25#include "aos/type_traits/type_traits.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080026
Brian Silvermancb5da1f2015-12-05 22:19:58 -050027// This file has various concrete LogImplementations.
Brian Silvermanf665d692013-02-17 22:11:39 -080028
29namespace aos {
30namespace logging {
31
32// Unless explicitly stated otherwise, format must always be a string constant,
33// args are printf-style arguments for format, and ap is a va_list of args.
Brian Silverman1a572cc2013-03-05 19:58:01 -080034// The validity of format and args together will be checked at compile time
Brian Silvermancb5da1f2015-12-05 22:19:58 -050035// using a function attribute.
Brian Silvermanf665d692013-02-17 22:11:39 -080036
Brian Silvermancb5da1f2015-12-05 22:19:58 -050037// Contains all of the information about a given logging call.
Brian Silverman88471dc2014-02-15 22:35:42 -080038struct LogMessage {
Tyler Chatow5febd8f2020-01-05 18:25:31 -080039 enum class Type : uint8_t { kString };
Brian Silverman88471dc2014-02-15 22:35:42 -080040
41 int32_t seconds, nseconds;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070042 // message_length is just the length of the actual data (which member depends
43 // on the type).
Brian Silverman88471dc2014-02-15 22:35:42 -080044 size_t message_length, name_length;
Brian Silvermanf665d692013-02-17 22:11:39 -080045 pid_t source;
46 static_assert(sizeof(source) == 4, "that's how they get printed");
47 // Per task/thread.
48 uint16_t sequence;
Brian Silverman88471dc2014-02-15 22:35:42 -080049 Type type;
Brian Silvermanf665d692013-02-17 22:11:39 -080050 log_level level;
Austin Schuh044e18b2015-10-21 20:17:09 -070051 char name[LOG_MESSAGE_NAME_LEN];
Brian Silverman88471dc2014-02-15 22:35:42 -080052 union {
53 char message[LOG_MESSAGE_LEN];
54 struct {
55 uint32_t type_id;
56 size_t string_length;
57 // The message string and then the serialized structure.
58 char serialized[LOG_MESSAGE_LEN - sizeof(type) - sizeof(string_length)];
59 } structure;
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080060 struct {
61 // The type ID of the element type.
62 uint32_t type;
Brian Silvermanff12c9f2014-03-19 17:53:29 -070063 int rows, cols;
64 size_t string_length;
65 // The message string and then the serialized matrix.
Tyler Chatow5febd8f2020-01-05 18:25:31 -080066 char data[LOG_MESSAGE_LEN - sizeof(type) - sizeof(rows) - sizeof(cols)];
Brian Silvermanfd5e2a32014-02-22 20:02:39 -080067 } matrix;
Brian Silverman88471dc2014-02-15 22:35:42 -080068 };
Brian Silvermanf665d692013-02-17 22:11:39 -080069};
70static_assert(shm_ok<LogMessage>::value, "it's going in a queue");
71
72// Returns left > right. LOG_UNKNOWN is most important.
73static inline bool log_gt_important(log_level left, log_level right) {
74 if (left == ERROR) left = 3;
75 if (right == ERROR) right = 3;
76 return left > right;
77}
78
79// Returns a string representing level or "unknown".
80static inline const char *log_str(log_level level) {
Tyler Chatow5febd8f2020-01-05 18:25:31 -080081#define DECL_LEVEL(name, value) \
82 if (level == name) return #name;
Brian Silvermanf665d692013-02-17 22:11:39 -080083 DECL_LEVELS;
84#undef DECL_LEVEL
85 return "unknown";
86}
87// Returns the log level represented by str or LOG_UNKNOWN.
88static inline log_level str_log(const char *str) {
Tyler Chatow5febd8f2020-01-05 18:25:31 -080089#define DECL_LEVEL(name, value) \
90 if (!strcmp(str, #name)) return name;
Brian Silvermanf665d692013-02-17 22:11:39 -080091 DECL_LEVELS;
92#undef DECL_LEVEL
93 return LOG_UNKNOWN;
94}
95
Brian Silvermanbe858a12014-04-30 17:37:28 -070096// Implements all of the DoLog* methods in terms of a (pure virtual in this
97// class) HandleMessage method that takes a pointer to the message.
98class HandleMessageLogImplementation : public LogImplementation {
Austin Schuh82c0c822019-05-27 19:55:20 -070099 protected:
100 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
101 return ::aos::monotonic_clock::now();
102 }
103
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500104 private:
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800105 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
106 log_level level, const char *format, va_list ap) override;
Brian Silvermanbe858a12014-04-30 17:37:28 -0700107
108 virtual void HandleMessage(const LogMessage &message) = 0;
109};
110
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800111// A log implementation that dumps all messages to a C stdio stream.
Brian Silvermanbe858a12014-04-30 17:37:28 -0700112class StreamLogImplementation : public HandleMessageLogImplementation {
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800113 public:
114 StreamLogImplementation(FILE *stream);
115
116 private:
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500117 void HandleMessage(const LogMessage &message) override;
Brian Silverman1e8ddfe2013-12-19 16:20:53 -0800118
119 FILE *const stream_;
120};
121
Austin Schuha0c41ba2020-09-10 22:59:14 -0700122std::shared_ptr<LogImplementation> GetImplementation();
Tyler Chatow4b471e12020-01-05 20:19:36 -0800123
Austin Schuha0c41ba2020-09-10 22:59:14 -0700124// Sets the current implementation.
125void SetImplementation(std::shared_ptr<LogImplementation> implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -0800126
Austin Schuha0c41ba2020-09-10 22:59:14 -0700127// Updates the log implementation, returning the current implementation.
128std::shared_ptr<LogImplementation> SwapImplementation(
129 std::shared_ptr<LogImplementation> implementation);
Tyler Chatow67ddb032020-01-12 14:30:04 -0800130
Brian Silvermanf665d692013-02-17 22:11:39 -0800131// Must be called at least once per process/load before anything else is
132// called. This function is safe to call multiple times from multiple
133// tasks/threads.
134void Init();
135
Austin Schuha0c41ba2020-09-10 22:59:14 -0700136class CallbackLogImplementation : public HandleMessageLogImplementation {
137 public:
138 CallbackLogImplementation(
139 const ::std::function<void(const LogMessage &)> &callback)
140 : callback_(callback) {}
141
142 private:
143 void HandleMessage(const LogMessage &message) override { callback_(message); }
144
145 ::std::function<void(const LogMessage &)> callback_;
146};
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500147
Brian Silvermanf665d692013-02-17 22:11:39 -0800148// Resets all information in this task/thread to its initial state.
149// NOTE: This is not the opposite of Init(). The state that this deletes is
150// lazily created when needed. It is actually the opposite of Load().
151void Cleanup();
152
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800153void RegisterCallbackImplementation(
Austin Schuha0c41ba2020-09-10 22:59:14 -0700154 const ::std::function<void(const LogMessage &)> &callback);
Tyler Chatow67ddb032020-01-12 14:30:04 -0800155
156class ScopedLogRestorer {
157 public:
Austin Schuha0c41ba2020-09-10 22:59:14 -0700158 ScopedLogRestorer() = default;
Tyler Chatow67ddb032020-01-12 14:30:04 -0800159
Austin Schuha0c41ba2020-09-10 22:59:14 -0700160 ~ScopedLogRestorer() {
161 if (prev_impl_) {
162 SetImplementation(std::move(prev_impl_));
163 }
164 Cleanup();
165 }
166
167 void Swap(std::shared_ptr<LogImplementation> new_impl) {
168 prev_impl_ = SwapImplementation(std::move(new_impl));
169 }
Tyler Chatow67ddb032020-01-12 14:30:04 -0800170
171 private:
Austin Schuha0c41ba2020-09-10 22:59:14 -0700172 std::shared_ptr<LogImplementation> prev_impl_;
Tyler Chatow67ddb032020-01-12 14:30:04 -0800173};
Tyler Chatow5febd8f2020-01-05 18:25:31 -0800174
Brian Silvermanf665d692013-02-17 22:11:39 -0800175// This is where all of the code that is only used by actual LogImplementations
176// goes.
177namespace internal {
178
Brian Silverman88471dc2014-02-15 22:35:42 -0800179// Fills in *message according to the given inputs (with type kString).
180// Used for implementing LogImplementation::DoLog.
Austin Schuh82c0c822019-05-27 19:55:20 -0700181void FillInMessage(log_level level,
182 ::aos::monotonic_clock::time_point monotonic_now,
183 const char *format, va_list ap, LogMessage *message)
184 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
Brian Silvermanf665d692013-02-17 22:11:39 -0800185
Austin Schuh82c0c822019-05-27 19:55:20 -0700186__attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 4, 5))) static inline void
187FillInMessageVarargs(log_level level,
188 ::aos::monotonic_clock::time_point monotonic_now,
189 LogMessage *message, const char *format, ...) {
Brian Silverman78968542014-03-05 17:03:43 -0800190 va_list ap;
191 va_start(ap, format);
Austin Schuh82c0c822019-05-27 19:55:20 -0700192 FillInMessage(level, monotonic_now, format, ap, message);
Brian Silverman78968542014-03-05 17:03:43 -0800193 va_end(ap);
194}
195
Brian Silvermanf665d692013-02-17 22:11:39 -0800196// Prints message to output.
197void PrintMessage(FILE *output, const LogMessage &message);
198
Brian Silvermanf665d692013-02-17 22:11:39 -0800199} // namespace internal
200} // namespace logging
201} // namespace aos
202
John Park33858a32018-09-28 23:05:48 -0700203#endif // AOS_LOGGING_IMPLEMENTATIONS_H_