blob: 97587bf2d01e01f9b5d9bada31dd773fe24f8f62 [file] [log] [blame]
Austin Schuh044e18b2015-10-21 20:17:09 -07001#ifndef AOS_COMMON_LOGGING_LOGGING_INTERFACE_H_
2#define AOS_COMMON_LOGGING_LOGGING_INTERFACE_H_
3
4#include <stdarg.h>
5
6#include <string>
7#include <functional>
8
9#include "aos/common/logging/logging.h"
Brian Silverman17291d82015-10-24 22:30:57 -040010#include "aos/common/macros.h"
Austin Schuh044e18b2015-10-21 20:17:09 -070011
12namespace aos {
13
14struct MessageType;
15
16} // namespace aos
17
18namespace aos {
19namespace logging {
20
Brian Silverman17291d82015-10-24 22:30:57 -040021// Takes a message and logs it. It will set everything up and then call DoLog
22// for the current LogImplementation.
23void VLog(log_level level, const char *format, va_list ap)
24 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
25// Adds to the saved up message.
26void VCork(int line, const char *function, const char *format, va_list ap)
27 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
28// Actually logs the saved up message.
29void VUnCork(int line, const char *function, log_level level, const char *file,
30 const char *format, va_list ap)
31 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 5, 0)));
32
Austin Schuh044e18b2015-10-21 20:17:09 -070033// Represents a system that can actually take log messages and do something
34// useful with them.
35// All of the code (transitively too!) in the DoLog here can make
36// normal LOG and LOG_DYNAMIC calls but can NOT call LOG_CORK/LOG_UNCORK. These
37// calls will not result in DoLog recursing. However, implementations must be
38// safe to call from multiple threads/tasks at the same time. Also, any other
39// overriden methods may end up logging through a given implementation's DoLog.
40class LogImplementation {
41 public:
42 LogImplementation() : next_(NULL) {}
43
44 // The one that this one's implementation logs to.
45 // NULL means that there is no next one.
46 LogImplementation *next() { return next_; }
47 // Virtual in case a subclass wants to perform checks. There will be a valid
48 // logger other than this one available while this is called.
49 virtual void set_next(LogImplementation *next) { next_ = next; }
50
51 private:
52 // Actually logs the given message. Implementations should somehow create a
53 // LogMessage and then call internal::FillInMessage.
54 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
55 virtual void DoLog(log_level level, const char *format, va_list ap) = 0;
56 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 4)))
57 void DoLogVariadic(log_level level, const char *format, ...) {
58 va_list ap;
59 va_start(ap, format);
60 DoLog(level, format, ap);
61 va_end(ap);
62 }
63
64 // Logs the contents of an auto-generated structure. The implementation here
65 // just converts it to a string with PrintMessage and then calls DoLog with
66 // that, however some implementations can be a lot more efficient than that.
67 // size and type are the result of calling Size() and Type() on the type of
68 // the message.
69 // serialize will call Serialize on the message.
70 virtual void LogStruct(log_level level, const ::std::string &message,
71 size_t size, const MessageType *type,
72 const ::std::function<size_t(char *)> &serialize);
73 // Similiar to LogStruct, except for matrixes.
74 // type_id is the type of the elements of the matrix.
75 // data points to rows*cols*type_id.Size() bytes of data in row-major order.
76 virtual void LogMatrix(log_level level, const ::std::string &message,
77 uint32_t type_id, int rows, int cols,
78 const void *data);
79
80 // These functions call similar methods on the "current" LogImplementation or
81 // Die if they can't find one.
82 // levels is how many LogImplementations to not use off the stack.
83 static void DoVLog(log_level, const char *format, va_list ap, int levels)
84 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
85 // This one is implemented in queue_logging.cc.
86 static void DoLogStruct(log_level level, const ::std::string &message,
87 size_t size, const MessageType *type,
88 const ::std::function<size_t(char *)> &serialize,
89 int levels);
90 // This one is implemented in matrix_logging.cc.
91 static void DoLogMatrix(log_level level, const ::std::string &message,
92 uint32_t type_id, int rows, int cols,
93 const void *data, int levels);
94
95 // Friends so that they can access the static Do* functions.
96 friend void VLog(log_level, const char *, va_list);
97 friend void LogNext(log_level, const char *, ...);
98 template <class T>
99 friend void DoLogStruct(log_level, const ::std::string &, const T &);
100 template <class T>
101 friend void DoLogMatrix(log_level, const ::std::string &, const T &);
102
103 LogImplementation *next_;
104};
105
Brian Silverman17291d82015-10-24 22:30:57 -0400106namespace internal {
107
108// Prints format (with ap) into output and correctly deals with the result
109// being too long etc.
110size_t ExecuteFormat(char *output, size_t output_size, const char *format,
111 va_list ap)
112 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)));
113
114// Runs the given function with the current LogImplementation (handles switching
115// it out while running function etc).
116// levels is how many LogImplementations to not use off the stack.
117void RunWithCurrentImplementation(
118 int levels, ::std::function<void(LogImplementation *)> function);
119
120} // namespace internal
Austin Schuh044e18b2015-10-21 20:17:09 -0700121} // namespace logging
122} // namespace aos
123
124#endif // AOS_COMMON_LOGGING_LOGGING_INTERFACE_H_