arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
AudioLoggerSTD.h
1#pragma once
2
3#include "AudioToolsConfig.h"
4#if defined(ARDUINO) && !defined(IS_MIN_DESKTOP)
5#include "Print.h"
6#endif
7
8#include "AudioTools/Concurrency/LockGuard.h"
9#if defined(RP2040)
10#include "AudioTools/Concurrency/RP2040/MutexRP2040.h"
11#elif defined(ESP32)
12#include "AudioTools/Concurrency/RTOS/MutexRTOS.h"
13#include "esp_log.h"
14#endif
15
16#if USE_AUDIO_LOGGING
17
18namespace audio_tools {
19
20#if defined(ESP32)
21static MutexRTOS audio_logger_mutex;
22#elif defined(RP2040)
23static MutexRP2040 audio_logger_mutex;
24#else
25static MutexBase audio_logger_mutex; // no locking
26#endif
27
35class AudioLogger {
36 public:
42 enum LogLevel { Debug, Info, Warning, Error };
43
45 void begin(Print& out, LogLevel level = LOG_LEVEL) {
46 this->log_print_ptr = &out;
47 this->log_level = level;
48 }
49
50 // defines the log level
51 void setLogLevel(LogLevel level) { this->log_level = level; }
52
54 bool isLogging(LogLevel level = Info) {
55 return log_print_ptr != nullptr && level >= log_level;
56 }
57
58 AudioLogger& prefix(const char* file, int line, LogLevel current_level) {
59 printPrefix(file, line, current_level);
60 return *this;
61 }
62
63 void println() {
64#if defined(IS_DESKTOP) || defined(IS_DESKTOP_WITH_TIME_ONLY)
65 fprintf(stderr, "%s\n", print_buffer);
66#else
67 log_print_ptr->println(print_buffer);
68 log_print_ptr->flush();
69#endif
70 print_buffer[0] = 0;
71 }
72
73 char* str() { return print_buffer; }
74
76 static AudioLogger& instance() {
77 static AudioLogger* ptr;
78 if (ptr == nullptr) {
79 ptr = new AudioLogger;
80 }
81 return *ptr;
82 }
83
84 LogLevel level() { return log_level; }
85
86 void print(const char* c) { log_print_ptr->print(c); }
87
88 void printChar(char c) { log_print_ptr->print(c); }
89
90 void printCharHex(char c) {
91 char tmp[5];
92 unsigned char val = c;
93 snprintf(tmp, 5, "%02X ", val);
94 log_print_ptr->print(tmp);
95 }
96
97 protected:
98 Print* log_print_ptr = &LOG_STREAM;
99 LogLevel log_level = LOG_LEVEL;
100 char print_buffer[LOG_PRINTF_BUFFER_SIZE];
101
102 AudioLogger() {}
103
104 const char* levelName(LogLevel level) const {
105 switch (level) {
106 case Debug:
107 return "D";
108 case Info:
109 return "I";
110 case Warning:
111 return "W";
112 case Error:
113 return "E";
114 }
115 return "";
116 }
117
118 int printPrefix(const char* file, int line, LogLevel current_level) const {
119 const char* file_name = strrchr(file, '/') ? strrchr(file, '/') + 1 : file;
120 const char* level_code = levelName(current_level);
121 int len = log_print_ptr->print("[");
122 len += log_print_ptr->print(level_code);
123 len += log_print_ptr->print("] ");
124 len += log_print_ptr->print(file_name);
125 len += log_print_ptr->print(" : ");
126 len += log_print_ptr->print(line);
127 len += log_print_ptr->print(" - ");
128 return len;
129 }
130};
131
132static AudioLogger& AudioToolsLogger = AudioLogger::instance();
133using AudioToolsLogLevel = AudioLogger::LogLevel;
134
136class CustomLogLevel {
137 public:
138 AudioLogger::LogLevel getActual() { return actual; }
139
141 void set(AudioLogger::LogLevel level) {
142 active = true;
143 original = AudioLogger::instance().level();
144 actual = level;
145 }
146
148 void set() {
149 if (active) {
150 AudioLogger::instance().begin(Serial, actual);
151 }
152 }
154 void reset() {
155 if (active) {
156 AudioLogger::instance().begin(Serial, original);
157 }
158 }
159
160 protected:
161 bool active = false;
162 AudioLogger::LogLevel original;
163 AudioLogger::LogLevel actual;
164};
165
166} // namespace audio_tools
167
168// #define LOG_OUT(level, fmt, ...)
169// {AudioLogger::instance().prefix(__FILE__,__LINE__, level);cont char PROGMEM
170// *fmt_P=F(fmt); snprintf_P(AudioLogger::instance().str(),
171// LOG_PRINTF_BUFFER_SIZE, fmt, ##__VA_ARGS__);
172// AudioLogger::instance().println();}
173#define LOG_OUT_PGMEM(level, fmt, ...) \
174 { \
175 LockGuard guard{audio_logger_mutex}; \
176 AudioLogger::instance().prefix(__FILE__, __LINE__, level); \
177 snprintf(AudioLogger::instance().str(), LOG_PRINTF_BUFFER_SIZE, PSTR(fmt), \
178 ##__VA_ARGS__); \
179 AudioLogger::instance().println(); \
180 }
181
182#define LOG_OUT(level, fmt, ...) \
183 { \
184 LockGuard guard{audio_logger_mutex}; \
185 AudioLogger::instance().prefix(__FILE__, __LINE__, level); \
186 snprintf(AudioLogger::instance().str(), LOG_PRINTF_BUFFER_SIZE, fmt, \
187 ##__VA_ARGS__); \
188 AudioLogger::instance().println(); \
189 }
190#define LOG_MIN(level) \
191 { \
192 LockGuard guard{audio_logger_mutex}; \
193 AudioLogger::instance().prefix(__FILE__, __LINE__, level); \
194 AudioLogger::instance().println(); \
195 }
196
197#ifdef LOG_NO_MSG
198#define LOGD(fmt, ...) \
199 if (AudioLogger::instance().level() <= AudioLogger::Debug) { \
200 LOG_MIN(AudioLogger::Debug); \
201 }
202#define LOGI(fmt, ...) \
203 if (AudioLogger::instance().level() <= AudioLogger::Info) { \
204 LOG_MIN(AudioLogger::Info); \
205 }
206#define LOGW(fmt, ...) \
207 if (AudioLogger::instance().level() <= AudioLogger::Warning) { \
208 LOG_MIN(AudioLogger::Warning); \
209 }
210#define LOGE(fmt, ...) \
211 if (AudioLogger::instance().level() <= AudioLogger::Error) { \
212 LOG_MIN(AudioLogger::Error); \
213 }
214#else
215// Log statments which store the fmt string in Progmem
216#define LOGD(fmt, ...) \
217 if (AudioLogger::instance().level() <= AudioLogger::Debug) { \
218 LOG_OUT_PGMEM(AudioLogger::Debug, fmt, ##__VA_ARGS__); \
219 }
220#define LOGI(fmt, ...) \
221 if (AudioLogger::instance().level() <= AudioLogger::Info) { \
222 LOG_OUT_PGMEM(AudioLogger::Info, fmt, ##__VA_ARGS__); \
223 }
224#define LOGW(fmt, ...) \
225 if (AudioLogger::instance().level() <= AudioLogger::Warning) { \
226 LOG_OUT_PGMEM(AudioLogger::Warning, fmt, ##__VA_ARGS__); \
227 }
228#define LOGE(fmt, ...) \
229 if (AudioLogger::instance().level() <= AudioLogger::Error) { \
230 LOG_OUT_PGMEM(AudioLogger::Error, fmt, ##__VA_ARGS__); \
231 }
232#endif
233
234// Just log file and line
235#if defined(NO_TRACED) || defined(NO_TRACE)
236#define TRACED()
237#else
238#define TRACED() \
239 if (AudioLogger::instance().level() <= AudioLogger::Debug) { \
240 LOG_OUT(AudioLogger::Debug, LOG_METHOD); \
241 }
242#endif
243
244#if defined(NO_TRACEI) || defined(NO_TRACE)
245#define TRACEI()
246#else
247#define TRACEI() \
248 if (AudioLogger::instance().level() <= AudioLogger::Info) { \
249 LOG_OUT(AudioLogger::Info, LOG_METHOD); \
250 }
251#endif
252
253#if defined(NO_TRACEW) || defined(NO_TRACE)
254#define TRACEW()
255#else
256#define TRACEW() \
257 if (AudioLogger::instance().level() <= AudioLogger::Warning) { \
258 LOG_OUT(AudioLogger::Warning, LOG_METHOD); \
259 }
260#endif
261
262#if defined(NO_TRACEE) || defined(NO_TRACE)
263#define TRACEE()
264#else
265#define TRACEE() \
266 if (AudioLogger::instance().level() <= AudioLogger::Error) { \
267 LOG_OUT(AudioLogger::Error, LOG_METHOD); \
268 }
269#endif
270
271#else
272
273// Switch off logging
274#define LOGD(...)
275#define LOGI(...)
276#define LOGW(...)
277#define LOGE(...)
278#define TRACED()
279#define TRACEI()
280#define TRACEW()
281#define TRACEE()
282
283#endif
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10