M5Utility 0.1.0 git rev:5b5ed96
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 <chrono>
16// ESP-IDF / Arduino-ESP32 (any platform shipping sdkconfig.h) provides
17// CONFIG_NEWLIB_NANO_FORMAT that flags whether the linked printf supports
18// %lld. __has_include keeps this header usable on platforms without it.
19#if defined(__has_include)
20#if __has_include(<sdkconfig.h>)
21#include <sdkconfig.h>
22#endif
23#endif
24
25namespace m5 {
26namespace utility {
27namespace log {
28
33enum class LogLevel : uint8_t {
34 None,
35 Error,
36 Warn,
37 Info,
38 Debug,
39 Verbose,
40};
41using log_level_t = LogLevel;
42
43#if defined(NDEBUG)
44constexpr log_level_t logOutputLevel = log_level_t::None;
45#elif defined(M5_LOG_LEVEL)
46constexpr log_level_t logOutputLevel = static_cast<log_level_t>(M5_LOG_LEVEL);
47#elif defined(CORE_DEBUG_LEVEL)
48constexpr log_level_t logOutputLevel = static_cast<log_level_t>(CORE_DEBUG_LEVEL);
49#else
58constexpr log_level_t logOutputLevel = log_level_t::None;
59#endif
60
62// Does the string contain slash?
63constexpr bool contains_slash(const char* s)
64{
65 return *s ? (*s == '/' ? true : contains_slash(s + 1)) : false;
66}
67// Returns the next position after the right-most slash
68constexpr const char* after_right_slash(const char* s)
69{
70 return (*s == '/') ? (s + 1) : after_right_slash(s - 1);
71}
72// Gets the tail of string
73constexpr const char* tail(const char* s)
74{
75 return *s ? tail(s + 1) : s;
76}
78
84constexpr const char* pathToFilename(const char* path)
85{
86 return (path && path[0]) ? (contains_slash(path) ? after_right_slash(tail(path)) : path) : "";
87}
88
90void logPrintf(const char* format, ...);
92void dump(const void* addr, const size_t len, const bool align = true);
93
94using elapsed_time_t = std::chrono::milliseconds;
95// using elapsed_time_t = std::chrono::microseconds;
96
98elapsed_time_t elapsedTime();
99
101// ESP-IDF newlib-nano printf does not support %lld; misaligned varargs cause a
102// LoadProhibited crash on the next %s. Detect via CONFIG_NEWLIB_NANO_FORMAT and
103// fall back to a 32-bit timestamp (~49.7 day wrap, acceptable for log use).
104#if defined(CONFIG_NEWLIB_NANO_FORMAT)
105#define M5_UTILITY_LOG_TS_FMT "%6" PRIu32
106#define M5_UTILITY_LOG_TS_VAL (uint32_t) m5::utility::log::elapsedTime().count()
107#else
108#define M5_UTILITY_LOG_TS_FMT "%6" PRId64
109#define M5_UTILITY_LOG_TS_VAL (int64_t) m5::utility::log::elapsedTime().count()
110#endif
111
112#ifndef M5_UTILITY_LOG_FORMAT
113#define M5_UTILITY_LOG_FORMAT(letter, format) \
114 "[" M5_UTILITY_LOG_TS_FMT "][" #letter "][%s:%u] %s(): " format "\n", M5_UTILITY_LOG_TS_VAL, \
115 m5::utility::log::pathToFilename(__FILE__), __LINE__, __func__
116#endif
118
123#define M5_LIB_LOGE(format, ...) \
124 do { \
125 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Error) { \
126 m5::utility::log::logPrintf(M5_UTILITY_LOG_FORMAT(E, format), ##__VA_ARGS__); \
127 } \
128 } while (0)
133#define M5_LIB_LOGW(format, ...) \
134 do { \
135 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Warn) { \
136 m5::utility::log::logPrintf(M5_UTILITY_LOG_FORMAT(W, format), ##__VA_ARGS__); \
137 } \
138 } while (0)
143#define M5_LIB_LOGI(format, ...) \
144 do { \
145 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Info) { \
146 m5::utility::log::logPrintf(M5_UTILITY_LOG_FORMAT(I, format), ##__VA_ARGS__); \
147 } \
148 } while (0)
153#define M5_LIB_LOGD(format, ...) \
154 do { \
155 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Debug) { \
156 m5::utility::log::logPrintf(M5_UTILITY_LOG_FORMAT(D, format), ##__VA_ARGS__); \
157 } \
158 } while (0)
163#define M5_LIB_LOGV(format, ...) \
164 do { \
165 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Verbose) { \
166 m5::utility::log::logPrintf(M5_UTILITY_LOG_FORMAT(V, format), ##__VA_ARGS__); \
167 } \
168 } while (0)
169
174#define M5_DUMPE(addr, len) \
175 do { \
176 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Error) { \
177 m5::utility::log::dump((addr), (len)); \
178 } \
179 } while (0)
184#define M5_DUMPW(addr, len) \
185 do { \
186 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Warn) { \
187 m5::utility::log::dump((addr), (len)); \
188 } \
189 } while (0)
194#define M5_DUMPI(addr, len) \
195 do { \
196 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Info) { \
197 m5::utility::log::dump((addr), (len)); \
198 } \
199 } while (0)
204#define M5_DUMPD(addr, len) \
205 do { \
206 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Debug) { \
207 m5::utility::log::dump((addr), (len)); \
208 } \
209 } while (0)
214#define M5_DUMPV(addr, len) \
215 do { \
216 if (m5::utility::log::logOutputLevel >= m5::utility::log::log_level_t::Verbose) { \
217 m5::utility::log::dump((addr), (len)); \
218 } \
219 } while (0)
220
221} // namespace log
222} // namespace utility
223} // namespace m5
224
225#endif
LogLevel
Log output control level.
Definition library_log.hpp:33
constexpr log_level_t logOutputLevel
Base value of log level to be output.
Definition library_log.hpp:58
constexpr const char * pathToFilename(const char *path)
Gets the filename from full pathname.
Definition library_log.hpp:84
Top level namespace of M5.
Definition base64.cpp:39
For utilities.