M5Utility 0.2.0 git rev:301a6b5
Loading...
Searching...
No Matches
library_log.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UTILITY_LOG_LIBRARY_LOG_HPP
11#define M5_UTILITY_LOG_LIBRARY_LOG_HPP
12
13#include <cstdint>
14#include <cinttypes>
15#include <cstddef>
17
18// Some environments ship a <chrono> that does not compile (see
19// M5UTILITY_HAS_USABLE_CHRONO in platform_detect.hpp); fall back to a 32-bit
20// millisecond timestamp backed by m5::utility::millis() there.
21#if M5UTILITY_HAS_USABLE_CHRONO
22#include <chrono>
23#endif
24// ESP-IDF / Arduino-ESP32 (any platform shipping sdkconfig.h) provides
25// CONFIG_NEWLIB_NANO_FORMAT that flags whether the linked printf supports
26// %lld. __has_include keeps this header usable on platforms without it.
27#if defined(__has_include)
28#if __has_include(<sdkconfig.h>)
29#include <sdkconfig.h>
30#endif
31#endif
32
33namespace m5 {
34namespace utility {
35namespace log {
36
41enum class LogLevel : uint8_t {
42 None,
43 Error,
44 Warn,
45 Info,
46 Debug,
47 Verbose,
48};
49using log_level_t = LogLevel;
50
51#if defined(NDEBUG)
52constexpr log_level_t logOutputLevel = log_level_t::None;
53#elif defined(M5_LOG_LEVEL)
54constexpr log_level_t logOutputLevel = static_cast<log_level_t>(M5_LOG_LEVEL);
55#elif defined(CORE_DEBUG_LEVEL)
56constexpr log_level_t logOutputLevel = static_cast<log_level_t>(CORE_DEBUG_LEVEL);
57#else
66constexpr log_level_t logOutputLevel = log_level_t::None;
67#endif
68
70// Does the string contain slash?
71constexpr bool contains_slash(const char* s)
72{
73 return *s ? (*s == '/' ? true : contains_slash(s + 1)) : false;
74}
75// Returns the next position after the right-most slash
76constexpr const char* after_right_slash(const char* s)
77{
78 return (*s == '/') ? (s + 1) : after_right_slash(s - 1);
79}
80// Gets the tail of string
81constexpr const char* tail(const char* s)
82{
83 return *s ? tail(s + 1) : s;
84}
86
92constexpr const char* pathToFilename(const char* path)
93{
94 return (path && path[0]) ? (contains_slash(path) ? after_right_slash(tail(path)) : path) : "";
95}
96
98void logPrintf(const char* format, ...);
100void dump(const void* addr, const size_t len, const bool align = true);
101
102#if !M5UTILITY_HAS_USABLE_CHRONO
115 constexpr elapsed_time_t() : ms(0)
116 {
117 }
118 constexpr explicit elapsed_time_t(uint32_t value) : ms(value)
119 {
120 }
121
122 uint32_t ms;
123 constexpr uint32_t count() const
124 {
125 return ms;
126 }
127};
128#else
129using elapsed_time_t = std::chrono::milliseconds;
130// using elapsed_time_t = std::chrono::microseconds;
131#endif
132
135
137// ESP-IDF newlib-nano printf does not support %lld; misaligned varargs cause a
138// LoadProhibited crash on the next %s. Detect via CONFIG_NEWLIB_NANO_FORMAT and
139// fall back to a 32-bit timestamp (~49.7 day wrap, acceptable for log use).
140// The no-<chrono> fallback takes the same 32-bit branch: those bare-metal
141// cores commonly link newlib-nano too (e.g. the Arduino/Adafruit SAMD core
142// passes --specs=nano.specs) without defining CONFIG_NEWLIB_NANO_FORMAT, and
143// its elapsed_time_t::count() is 32-bit to begin with.
144#if defined(CONFIG_NEWLIB_NANO_FORMAT) || !M5UTILITY_HAS_USABLE_CHRONO
145#define M5_UTILITY_LOG_TS_FMT "%6" PRIu32
146#define M5_UTILITY_LOG_TS_VAL (uint32_t) m5::utility::log::elapsedTime().count()
147#else
148#define M5_UTILITY_LOG_TS_FMT "%6" PRId64
149#define M5_UTILITY_LOG_TS_VAL (int64_t) m5::utility::log::elapsedTime().count()
150#endif
151
152#ifndef M5_UTILITY_LOG_FORMAT
153#define M5_UTILITY_LOG_FORMAT(letter, format) \
154 "[" M5_UTILITY_LOG_TS_FMT "][" #letter "][%s:%u] %s(): " format "\n", M5_UTILITY_LOG_TS_VAL, \
155 m5::utility::log::pathToFilename(__FILE__), __LINE__, __func__
156#endif
158
163#define M5_LIB_LOGE(format, ...) \
164 do { \
165 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Error) { \
166 m5::utility::log::logPrintf(M5_UTILITY_LOG_FORMAT(E, format), ##__VA_ARGS__); \
167 } \
168 } while (0)
173#define M5_LIB_LOGW(format, ...) \
174 do { \
175 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Warn) { \
176 m5::utility::log::logPrintf(M5_UTILITY_LOG_FORMAT(W, format), ##__VA_ARGS__); \
177 } \
178 } while (0)
183#define M5_LIB_LOGI(format, ...) \
184 do { \
185 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Info) { \
186 m5::utility::log::logPrintf(M5_UTILITY_LOG_FORMAT(I, format), ##__VA_ARGS__); \
187 } \
188 } while (0)
193#define M5_LIB_LOGD(format, ...) \
194 do { \
195 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Debug) { \
196 m5::utility::log::logPrintf(M5_UTILITY_LOG_FORMAT(D, format), ##__VA_ARGS__); \
197 } \
198 } while (0)
203#define M5_LIB_LOGV(format, ...) \
204 do { \
205 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Verbose) { \
206 m5::utility::log::logPrintf(M5_UTILITY_LOG_FORMAT(V, format), ##__VA_ARGS__); \
207 } \
208 } while (0)
209
214#define M5_DUMPE(addr, len) \
215 do { \
216 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Error) { \
217 m5::utility::log::dump((addr), (len)); \
218 } \
219 } while (0)
224#define M5_DUMPW(addr, len) \
225 do { \
226 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Warn) { \
227 m5::utility::log::dump((addr), (len)); \
228 } \
229 } while (0)
234#define M5_DUMPI(addr, len) \
235 do { \
236 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Info) { \
237 m5::utility::log::dump((addr), (len)); \
238 } \
239 } while (0)
244#define M5_DUMPD(addr, len) \
245 do { \
246 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Debug) { \
247 m5::utility::log::dump((addr), (len)); \
248 } \
249 } while (0)
254#define M5_DUMPV(addr, len) \
255 do { \
256 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Verbose) { \
257 m5::utility::log::dump((addr), (len)); \
258 } \
259 } while (0)
260
261} // namespace log
262} // namespace utility
263} // namespace m5
264
265#endif
elapsed_time_t elapsedTime()
Gets the elapsed time for log.
Definition library_log.cpp:123
LogLevel
Log output control level.
Definition library_log.hpp:41
constexpr log_level_t logOutputLevel
Base value of log level to be output.
Definition library_log.hpp:66
constexpr const char * pathToFilename(const char *path)
Gets the filename from full pathname.
Definition library_log.hpp:92
Top level namespace of M5.
Definition base64.cpp:39
For utilities.
Build-environment detection shared by the sources that need a time source or <chrono>
Millisecond duration count; only .count() is provided, unlike the std::chrono::milliseconds used ever...
Definition library_log.hpp:114