My Project
log.h
1 /*
2  * uuid-log - Microcontroller logging framework
3  * Copyright 2019,2021-2024 Simon Arlott
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef UUID_LOG_H_
20 #define UUID_LOG_H_
21 
22 #include <Arduino.h>
23 
24 #include <algorithm>
25 #include <atomic>
26 #include <cstdarg>
27 #include <cstdint>
28 #include <list>
29 #include <map>
30 #include <memory>
31 #include <string>
32 #include <vector>
33 
34 #include <uuid/common.h>
35 
36 #ifndef UUID_COMMON_THREAD_SAFE
37 # define UUID_COMMON_THREAD_SAFE 0
38 #endif
39 
40 #ifndef UUID_COMMON_STD_MUTEX_AVAILABLE
41 # define UUID_COMMON_STD_MUTEX_AVAILABLE 0
42 #endif
43 
44 #if defined(DOXYGEN) || UUID_COMMON_STD_MUTEX_AVAILABLE
45 # define UUID_LOG_THREAD_SAFE 1
46 #else
47 # define UUID_LOG_THREAD_SAFE 0
48 #endif
49 
50 #if UUID_LOG_THREAD_SAFE
51 # include <mutex>
52 #endif
53 
54 namespace uuid {
55 
66 namespace log {
67 
73 #if UUID_COMMON_THREAD_SAFE && UUID_LOG_THREAD_SAFE
74 static constexpr bool thread_safe = true;
75 #else
76 static constexpr bool thread_safe = false;
77 #endif
78 
84 enum Level : int8_t {
85  OFF = -1,
86  EMERG = 0,
88  CRIT,
89  ERR,
92  INFO,
95  ALL,
96 };
97 
103 enum Facility : uint8_t {
104  KERN = 0,
110  LPR,
115  FTP,
116  NTP,
128 };
129 
140 std::string format_timestamp_ms(uint64_t timestamp_ms, unsigned int days_width = 1);
141 
149 std::vector<Level> levels();
150 
161 char format_level_char(Level level);
162 
170 const __FlashStringHelper *format_level_uppercase(Level level);
171 
180 std::vector<std::string> levels_uppercase();
181 
190 bool parse_level_uppercase(const std::string &name, Level &level);
191 
199 const __FlashStringHelper *format_level_lowercase(Level level);
200 
209 std::vector<std::string> levels_lowercase();
210 
219 bool parse_level_lowercase(const std::string &name, Level &level);
220 
229 struct Message {
240  Message(uint64_t uptime_ms, Level level, Facility facility, const __FlashStringHelper *name, const std::string &&text);
241  ~Message() = default;
242 
249  const uint64_t uptime_ms;
250 
256  const Level level;
257 
264 
270  const __FlashStringHelper *name;
271 
280  const std::string text;
281 };
282 
283 class Logger;
284 
290 class Handler {
297  friend Logger;
298 public:
299  virtual ~Handler();
300 
325  virtual void operator<<(std::shared_ptr<Message> message) = 0;
326 
327 protected:
328  Handler() = default;
329 
330 private:
339  std::weak_ptr<std::map<Handler*,Level>> handlers_;
340 };
341 
347 class Logger {
348 public:
357  static constexpr size_t MAX_LOG_LENGTH = 255;
358 
367  explicit Logger(const __FlashStringHelper *name, Facility facility = Facility::LOCAL0);
368  ~Logger() = default;
369 
381  static void register_handler(Handler *handler, Level level);
382 
392  static void unregister_handler(Handler *handler);
393 
404  static Level get_log_level(const Handler *handler);
405 
412  static Level global_level() { return global_level_; };
413 
422  inline bool enabled(Level level) const { return level <= global_level_ && level <= local_level_; }
423 
430  inline Facility facility() const { return facility_; }
431 
440  inline Level level() const { return local_level_; }
441 
450  inline void level(Level level) { local_level_ = level; }
451 
458  Level effective_level() const { return std::min(global_level(), local_level_); };
459 
467  void emerg(const char *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
475  void emerg(const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
476 
484  void alert(const char *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
492  void alert(const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
493 
501  void crit(const char *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
509  void crit(const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
510 
518  void err(const char *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
526  void err(const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
527 
535  void warning(const char *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
543  void warning(const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
544 
552  void notice(const char *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
560  void notice(const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
561 
569  void info(const char *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
576  void info(const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
577 
585  void debug(const char *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
593  void debug(const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
594 
602  void trace(const char *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
610  void trace(const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 2, 3))) */;
611 
620  void log(Level level, const char *format, ...) const /* __attribute__((format (printf, 3, 4))) */;
629  void log(Level level, const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 3, 4))) */;
630 
640  void log(Level level, Facility facility, const char *format, ...) const /* __attribute__((format (printf, 4, 5))) */;
650  void log(Level level, Facility facility, const __FlashStringHelper *format, ...) const /* __attribute__((format (printf, 4, 5))) */;
651 
660  void vlog(Level level, const char *format, va_list ap) const;
669  void vlog(Level level, const __FlashStringHelper *format, va_list ap) const;
670 
680  void vlog(Level level, Facility facility, const char *format, va_list ap) const;
690  void vlog(Level level, Facility facility, const __FlashStringHelper *format, va_list ap) const;
691 
699  void logp(Level level, const char *text) const;
709  void logp(Level level, Facility facility, const char *text) const;
710 
711 private:
722  void vlog_internal(Level level, Facility facility, const char *format, va_list ap) const;
733  void vlog_internal(Level level, Facility facility, const __FlashStringHelper *format, va_list ap) const;
734 
740  static void refresh_log_level();
747  static std::shared_ptr<std::map<Handler*,Level>>& registered_handlers();
748 
761  void dispatch(Level level, Facility facility, std::vector<char> &text) const;
762 
770  void dispatch(const std::shared_ptr<Message> &message) const;
771 
772  static std::atomic<Level> global_level_;
773 #if UUID_LOG_THREAD_SAFE
774  static std::mutex mutex_;
775 #endif
776 
777  const __FlashStringHelper *name_;
779  Level local_level_{Level::ALL};
780 };
781 
793 public:
794  static constexpr size_t MAX_LOG_MESSAGES = 50;
802  explicit PrintHandler(Print &print);
803  ~PrintHandler() = default;
804 
811  size_t maximum_log_messages() const;
819  void maximum_log_messages(size_t count);
820 
827  void loop(size_t count = SIZE_MAX);
828 
840  void operator<<(std::shared_ptr<Message> message) override;
841 
842 private:
843  Print &print_;
844 #if UUID_LOG_THREAD_SAFE
845  mutable std::mutex mutex_;
846 #endif
848  std::list<std::shared_ptr<Message>> log_messages_;
849 };
850 
851 } // namespace log
852 
853 } // namespace uuid
854 
855 #endif
uuid::log::Message::level
const Level level
Severity level of the message.
Definition: log.h:256
uuid::log::Logger
Logger instance used to make log messages.
Definition: log.h:347
uuid::log::PrintHandler
Basic log handler for writing messages to any object supporting the Print interface.
Definition: log.h:792
uuid::log::Handler::handlers_
std::weak_ptr< std::map< Handler *, Level > > handlers_
Reference to registered log handlers.
Definition: log.h:339
uuid::log::LPR
@ LPR
Definition: log.h:110
uuid::log::format_level_lowercase
const __FlashStringHelper * format_level_lowercase(Level level)
Format a log level as a lowercase string.
Definition: format_level_lowercase.cpp:61
uuid::log::NTP
@ NTP
Definition: log.h:116
uuid::log::Logger::err
void err(const char *format,...) const
Log a message at level Level::ERR.
Definition: log.cpp:170
uuid::log::FTP
@ FTP
Definition: log.h:115
uuid::log::Message
Log message text with timestamp and logger attributes.
Definition: log.h:229
uuid::log::KERN
@ KERN
Definition: log.h:104
uuid::log::Logger::effective_level
Level effective_level() const
Get the effective log level.
Definition: log.h:458
uuid::log::PrintHandler::PrintHandler
PrintHandler(Print &print)
Create a new Print log handler.
Definition: print_handler.cpp:32
uuid::log::LOCAL4
@ LOCAL4
Definition: log.h:124
uuid::log::AUTH
@ AUTH
Definition: log.h:108
uuid::log::format_level_uppercase
const __FlashStringHelper * format_level_uppercase(Level level)
Format a log level as an uppercase string.
Definition: format_level_uppercase.cpp:61
uuid::log::PrintHandler::loop
void loop(size_t count=SIZE_MAX)
Dispatch queued log messages.
Definition: print_handler.cpp:55
uuid::log::Logger::notice
void notice(const char *format,...) const
Log a message at level Level::NOTICE.
Definition: log.cpp:210
uuid::log::Logger::name_
const __FlashStringHelper * name_
Definition: log.h:777
uuid::log::Logger::trace
void trace(const char *format,...) const
Log a message at level Level::TRACE.
Definition: log.cpp:270
uuid::log::OFF
@ OFF
Definition: log.h:85
uuid::log::LOCAL3
@ LOCAL3
Definition: log.h:123
uuid::log::Facility
Facility
Facility type of the process logging a message.
Definition: log.h:103
uuid::log::CRIT
@ CRIT
Definition: log.h:88
uuid::log::Logger::dispatch
void dispatch(Level level, Facility facility, std::vector< char > &text) const
Dispatch a log message to all handlers that are registered to handle messages of the specified level.
Definition: log.cpp:403
uuid::log::levels_lowercase
std::vector< std::string > levels_lowercase()
Get all log levels as lowercase strings.
Definition: levels_lowercase.cpp:29
uuid::log::PrintHandler::MAX_LOG_MESSAGES
static constexpr size_t MAX_LOG_MESSAGES
Definition: log.h:794
uuid::log::LOCAL7
@ LOCAL7
Definition: log.h:127
uuid::log::Logger::Logger
Logger(const __FlashStringHelper *name, Facility facility=Facility::LOCAL0)
Create a new logger with the given name and logging facility.
Definition: log.cpp:60
uuid::log::CONSOLE
@ CONSOLE
Definition: log.h:118
uuid::log::Logger::info
void info(const char *format,...) const
Log a message at level Level::INFO.
Definition: log.cpp:230
uuid::log::Logger::level
Level level() const
Get the log level.
Definition: log.h:440
uuid::log::Logger::facility_
const Facility facility_
Definition: log.h:778
uuid::log::SECURITY
@ SECURITY
Definition: log.h:117
uuid::log::Message::name
const __FlashStringHelper * name
Name of the logger used (flash string).
Definition: log.h:270
uuid::log::NEWS
@ NEWS
Definition: log.h:111
uuid::log::NOTICE
@ NOTICE
Definition: log.h:91
uuid::log::PrintHandler::maximum_log_messages_
size_t maximum_log_messages_
Definition: log.h:847
uuid::log::DEBUG
@ DEBUG
Definition: log.h:93
uuid::log::Message::Message
Message(uint64_t uptime_ms, Level level, Facility facility, const __FlashStringHelper *name, const std::string &&text)
Create a new log message (not directly useful).
Definition: log.cpp:56
uuid::log::INFO
@ INFO
Definition: log.h:92
uuid::log::Level
Level
Severity level of log messages.
Definition: log.h:84
uuid::log::WARNING
@ WARNING
Definition: log.h:90
uuid::log::EMERG
@ EMERG
Definition: log.h:86
uuid::log::Logger::refresh_log_level
static void refresh_log_level()
Refresh the minimum global log level across all handlers.
Definition: log.cpp:423
uuid::log::Logger::logp
void logp(Level level, const char *text) const
Log a plain message (without formatting) at the specified level.
Definition: log.cpp:390
uuid::log::levels
std::vector< Level > levels()
Get all log levels.
Definition: levels.cpp:27
uuid::log::AUTHPRIV
@ AUTHPRIV
Definition: log.h:114
uuid::log::Handler
Logger handler used to process log messages.
Definition: log.h:290
uuid::log::Logger::register_handler
static void register_handler(Handler *handler, Level level)
Register a log handler.
Definition: log.cpp:71
uuid::log::Logger::facility
Facility facility() const
Get the default logging facility for new messages of this logger.
Definition: log.h:430
uuid::log::PrintHandler::print_
Print & print_
Definition: log.h:843
uuid::log::Logger::debug
void debug(const char *format,...) const
Log a message at level Level::DEBUG.
Definition: log.cpp:250
uuid::log::Logger::get_log_level
static Level get_log_level(const Handler *handler)
Get the current log level of a handler.
Definition: log.cpp:96
uuid::log::PrintHandler::maximum_log_messages
size_t maximum_log_messages() const
Get the maximum number of queued log messages.
Definition: print_handler.cpp:35
uuid::log::Logger::local_level_
Level local_level_
Definition: log.h:779
uuid::log::TRACE
@ TRACE
Definition: log.h:94
uuid::log::LOCAL0
@ LOCAL0
Definition: log.h:120
uuid::log::Logger::global_level
static Level global_level()
Get the current global log level.
Definition: log.h:412
uuid::log::MAIL
@ MAIL
Definition: log.h:106
uuid::log::ERR
@ ERR
Definition: log.h:89
uuid::log::Logger::global_level_
static std::atomic< Level > global_level_
Definition: log.h:772
uuid::log::Message::facility
const Facility facility
Facility type of the process that logged the message.
Definition: log.h:263
uuid::log::parse_level_uppercase
bool parse_level_uppercase(const std::string &name, Level &level)
Parse an uppercase string to a log level.
Definition: parse_level_uppercase.cpp:29
uuid::log::DAEMON
@ DAEMON
Definition: log.h:107
uuid::log::Logger::vlog
void vlog(Level level, const char *format, va_list ap) const
Log a message at the specified level.
Definition: log.cpp:338
uuid::log::Logger::unregister_handler
static void unregister_handler(Handler *handler)
Unregister a log handler.
Definition: log.cpp:82
uuid::log::UUCP
@ UUCP
Definition: log.h:112
uuid::log::thread_safe
static constexpr bool thread_safe
Thread-safe status of the library.
Definition: log.h:76
uuid::log::Logger::log
void log(Level level, const char *format,...) const
Log a message with default facility.
Definition: log.cpp:290
uuid::log::Logger::enabled
bool enabled(Level level) const
Determine if the specified log level is enabled by the effective log level.
Definition: log.h:422
uuid
Common utilities.
Definition: get_uptime_ms.cpp:28
uuid::log::Logger::warning
void warning(const char *format,...) const
Log a message at level Level::WARNING.
Definition: log.cpp:190
uuid::log::Logger::MAX_LOG_LENGTH
static constexpr size_t MAX_LOG_LENGTH
This is the maximum length of any log message.
Definition: log.h:357
uuid::log::Handler::operator<<
virtual void operator<<(std::shared_ptr< Message > message)=0
Add a new log message.
uuid::log::Logger::vlog_internal
void vlog_internal(Level level, Facility facility, const char *format, va_list ap) const
Log a message at the specified level and facility without checking that the specified level is enable...
Definition: log.cpp:370
uuid::log::parse_level_lowercase
bool parse_level_lowercase(const std::string &name, Level &level)
Parse a lowercase string to a log level.
Definition: parse_level_lowercase.cpp:29
uuid::log::format_timestamp_ms
std::string format_timestamp_ms(uint64_t timestamp_ms, unsigned int days_width)
Format a system uptime timestamp as a string.
Definition: format_timestamp_ms.cpp:31
uuid::log::Logger::emerg
void emerg(const char *format,...) const
Log a message at level Level::EMERG.
Definition: log.cpp:111
uuid::log::SYSLOG
@ SYSLOG
Definition: log.h:109
uuid::log::Handler::Logger
friend Logger
Logger needs to be able to access the private reference to the registered log handlers.
Definition: log.h:297
uuid::log::Logger::level
void level(Level level)
Set the log level.
Definition: log.h:450
uuid::log::LOCAL2
@ LOCAL2
Definition: log.h:122
uuid::log::ALERT
@ ALERT
Definition: log.h:87
uuid::log::levels_uppercase
std::vector< std::string > levels_uppercase()
Get all log levels as uppercase strings.
Definition: levels_uppercase.cpp:29
uuid::log::LOCAL6
@ LOCAL6
Definition: log.h:126
uuid::log::CRON
@ CRON
Definition: log.h:113
uuid::log::LOCAL5
@ LOCAL5
Definition: log.h:125
uuid::log::Logger::mutex_
static std::mutex mutex_
Definition: log.h:774
uuid::log::format_level_char
char format_level_char(Level level)
Format a log level as a single character.
Definition: format_level_char.cpp:25
uuid::log::PrintHandler::log_messages_
std::list< std::shared_ptr< Message > > log_messages_
Definition: log.h:848
uuid::log::PrintHandler::mutex_
std::mutex mutex_
Definition: log.h:845
uuid::log::Message::uptime_ms
const uint64_t uptime_ms
System uptime at the time the message was logged.
Definition: log.h:249
uuid::log::Message::text
const std::string text
Formatted log message text.
Definition: log.h:280
uuid::log::LOCAL1
@ LOCAL1
Definition: log.h:121
uuid::log::USER
@ USER
Definition: log.h:105
uuid::log::PrintHandler::operator<<
void operator<<(std::shared_ptr< Message > message) override
Add a new log message.
Definition: print_handler.cpp:91
uuid::log::ALL
@ ALL
Definition: log.h:95
uuid::log::CRON2
@ CRON2
Definition: log.h:119
uuid::log::Logger::alert
void alert(const char *format,...) const
Log a message at level Level::ALERT.
Definition: log.cpp:151
uuid::log::Logger::crit
void crit(const char *format,...) const
Log a message at level Level::CRIT.
Definition: log.cpp:131
uuid::log::Logger::registered_handlers
static std::shared_ptr< std::map< Handler *, Level > > & registered_handlers()
Get registered log handlers.
Definition: log.cpp:65