Loom 4 v4.5
Arduino library for Internet of Things Rapid Prototyping in environmental sensing
Loading...
Searching...
No Matches
Logger.h
1#pragma once
2
3#include <queue>
4#include <MemoryFree.h>
5#include "Hardware/Loom_Hypnos/Loom_Hypnos.h"
6
7#define FUNCTION_START Logger::getInstance()->startFunction(__FILE__, __func__, __LINE__, freeMemory()) // Marks the start of a function
8#define FUNCTION_END Logger::getInstance()->endFunction(freeMemory()) // Marks the end of a function
9
10#define SLOG(msg) Logger::getInstance()->debugLog(msg, true, __FILE__, __func__, __LINE__) // Log a message without printing to the serial
11#define LOG(msg) Logger::getInstance()->debugLog(msg, false, __FILE__, __func__, __LINE__) // Log a generic message
12#define LOG_LONG(msg) Logger::getInstance()->logLong(msg, false) // Log a long message
13#define ERROR(msg) Logger::getInstance()->errorLog(msg, false, __FILE__, __func__, __LINE__) // Log an error message
14#define WARNING(msg) Logger::getInstance()->warningLog(msg, false, __FILE__, __func__, __LINE__) // Log a warning message
15
16#define ENABLE_SD_LOGGING Logger::getInstance()->enableSD() // Enable SD logging of debug information
17#define ENABLE_FUNC_SUMMARIES Logger::getInstance()->enableSummaries() // Enable logging of function mem usage summaries
18
24class Logger{
25 private:
26
36 struct functionInfo{
37 char fileName[260];
38 char funcName[260];
39 unsigned long lineNumber;
40 int netMemoryUsage;
41 unsigned long time;
42 int indentCount;
43 };
44
45 // Function call list
46 std::queue<struct functionInfo*> callStack;
47 int indentNum = 0;
48
49 // Whether or not to use the SD card or log function summaries
50 bool enableFunctionSummaries = false;
51 bool enableSDLogging = false;
52
53 static Logger* instance;
54 SDManager* sdInst = nullptr;
55 Loom_Hypnos* hypnosInst = nullptr;
56
63 void log(char* message, bool silent){
64 char filePath[100];
65
66 // If we want to actually print to serial
67 if(!silent)
68 Serial.println(message);
69
70 snprintf_P(filePath, 100, PSTR("/debug/output_%i.log"), sdInst->getCurrentFileNumber());
71 // Log as long as we have given it a SD card instance
72 if(sdInst != nullptr && enableSDLogging)
73 sdInst->writeLineToFile(filePath, message);
74 }
75
82 void truncateFileName(const char* fileName, char array[260]){
83
84 int i;
85 // Find the last \\ in the file path to know where the name is
86 char *lastOccurance = strrchr(fileName, '\\');
87
88 int lastSlash = lastOccurance-fileName+1;
89
90 // Loop from the last slash to the end of the string
91 for(i = lastSlash; i < strlen(fileName); i++){
92 array[i-lastSlash] = fileName[i];
93 }
94 array[i-lastSlash] = '\0';
95 };
96
97 Logger() {};
98
99 public:
100 // Deleting copy constructor.
101 Logger(const Logger &obj) = delete;
102
103 /* Get an instance of the logger object */
104 static Logger *getInstance(){
105 if(instance == nullptr){
106 instance = new Logger();
107 return instance;
108 }
109 else{
110 return instance;
111 }
112 };
113
118 void setSDManager(SDManager* manager) { sdInst = manager; };
119
124 void setHypnos(Loom_Hypnos* hypnos) {
125 hypnosInst = hypnos;
126 sdInst = hypnos->getSDManager();
127 };
128
135 void debugLog(const char* message, bool silent, const char* file, const char* func, unsigned long lineNumber){
136 genericLog("DEBUG", message, silent, file, func, lineNumber);
137 };
138
145 void errorLog(const char* message, bool silent, const char* file, const char* func, unsigned long lineNumber){
146 genericLog("ERROR", message, silent, file, func, lineNumber);
147 };
148
155 void warningLog(const char* message, bool silent, const char* file, const char* func, unsigned long lineNumber){
156 genericLog("WARNING", message, silent, file, func, lineNumber);
157 };
158
165 void debugLog(const __FlashStringHelper* message, bool silent, const char* file, const char* func, unsigned long lineNumber){
166 char buff[150];
167 memcpy_P(buff, message, 150);
168 genericLog("DEBUG", buff, silent, file, func, lineNumber);
169 };
170
177 void warningLog(const __FlashStringHelper* message, bool silent, const char* file, const char* func, unsigned long lineNumber){
178 char buff[150];
179 memcpy_P(buff, message, 150);
180 genericLog("WARNING", buff, silent, file, func, lineNumber);
181 };
182
189 void errorLog(const __FlashStringHelper* message, bool silent, const char* file, const char* func, unsigned long lineNumber){
190 char buff[150];
191 memcpy_P(buff, message, 150);
192 genericLog("ERROR", buff, silent, file, func, lineNumber);
193 };
194
204 void genericLog(const char* level, const char* message, bool silent, const char* file, const char* func, unsigned long lineNumber){
205 char logMessage[OUTPUT_SIZE];
206 char fileName[260];
207 truncateFileName(file, fileName);
208
209 /* If the hypnos is not included or the hypnos is included but the RTC hasn't been initialized yet we want to print without the time */
210 if(hypnosInst == nullptr || (hypnosInst != nullptr && !hypnosInst->isRTCInitialized()))
211 snprintf_P( logMessage,
212 OUTPUT_SIZE,
213 PSTR("[%s] [%s:%s:%u] %s"),
214 level,
215 fileName,
216 func,
217 lineNumber,
218 message
219 );
220 else
221 snprintf_P( logMessage,
222 OUTPUT_SIZE,
223 PSTR("[%s] [%s] [%s:%s:%u] %s"),
224 hypnosInst->getCurrentTime().text(),
225 level,
226 fileName,
227 func,
228 lineNumber,
229 message
230 );
231 /* Log the message*/
232 log(logMessage, silent);
233 }
234
235 /*
236 Log an entire char* instead of fixing it to an array you must construct your message before passing it into this function
237 */
238 void logLong(char* message, bool silent){
239 log(message, silent);
240 };
241
242
249 void startFunction(const char* file, const char* func, unsigned long num, int freeMemory){
250 if(enableFunctionSummaries){
251 // Log the start time of the function
252 char fileName[260];
253 memset(fileName, '\0', 260);
254 truncateFileName(file, fileName);
255 struct functionInfo* newFunction = (struct functionInfo*) malloc(sizeof(struct functionInfo));
256 strncpy(newFunction->fileName, fileName, 260);
257 strncpy(newFunction->funcName, func, 260);
258 newFunction->lineNumber = num;
259 newFunction->netMemoryUsage = freeMemory;
260 newFunction->time = millis();
261 newFunction->indentCount = callStack.size();
262 callStack.push(newFunction);
263 }
264 };
265
270 void endFunction(int freeMemory){
271 if(enableFunctionSummaries){
272 char fileName[100];
273 char file[260];
274 char func[260];
275 char output[300];
276 char indents[10];
277
278 // 0 fill the indents array
279 memset(indents, '\0', 10);
280
281 struct functionInfo* info = callStack.front();
282 int memUsage = info->netMemoryUsage;
283 unsigned long time = millis() - info->time;
284 int percentage = ((float)memUsage / 32000.0) * 100;
285
286 // Copy to internal variables
287 strncpy(file, info->fileName, 260);
288 strncpy(func, info->funcName, 260);
289
290 // Cap the number of inents at the size of the array
291 if(info->indentCount > 10){
292 info->indentCount = 10;
293 }
294
295 // Set the number of tab characters we need to add
296 memset(indents, '\t', info->indentCount);
297
298 // Pop the last function off the call stack
299 free(info);
300 callStack.pop();
301
302 // Format the fileName and log output, this function uses 976 bytes
303 snprintf_P(fileName, 100,PSTR("/debug/funcSummaries_%i.log"), sdInst->getCurrentFileNumber());
304 snprintf_P(output, 300, PSTR("%s[%s:%s] Summary\n%s\tInitial Free Memory: %i B (%i %% Free)\n%s\tEnding Free Memory: %i B\n%s\tNet Usage: %i B\n%s\tElapsed Time: %u MS"), indents, file, func, indents, memUsage, percentage, indents, freeMemory, indents, memUsage-freeMemory, indents, time);
305
306 // Log as long as we have given it a SD card instance
307 if(sdInst != nullptr && enableSDLogging)
308 sdInst->writeLineToFile(fileName, output);
309 }
310 };
311
312 /* Enable function summaries to view memory usage */
313 void enableSummaries(){ enableFunctionSummaries = true; };
314
315 /* Save flash write by not logging everything to SD */
316 void enableSD(){ enableSDLogging = true; };
317};
318
Definition: Logger.h:24
void debugLog(const char *message, bool silent, const char *file, const char *func, unsigned long lineNumber)
Definition: Logger.h:135
void debugLog(const __FlashStringHelper *message, bool silent, const char *file, const char *func, unsigned long lineNumber)
Definition: Logger.h:165
void warningLog(const char *message, bool silent, const char *file, const char *func, unsigned long lineNumber)
Definition: Logger.h:155
void errorLog(const __FlashStringHelper *message, bool silent, const char *file, const char *func, unsigned long lineNumber)
Definition: Logger.h:189
void startFunction(const char *file, const char *func, unsigned long num, int freeMemory)
Definition: Logger.h:249
void setSDManager(SDManager *manager)
Definition: Logger.h:118
void warningLog(const __FlashStringHelper *message, bool silent, const char *file, const char *func, unsigned long lineNumber)
Definition: Logger.h:177
void endFunction(int freeMemory)
Definition: Logger.h:270
void setHypnos(Loom_Hypnos *hypnos)
Definition: Logger.h:124
void errorLog(const char *message, bool silent, const char *file, const char *func, unsigned long lineNumber)
Definition: Logger.h:145
void genericLog(const char *level, const char *message, bool silent, const char *file, const char *func, unsigned long lineNumber)
Definition: Logger.h:204
Definition: Loom_Hypnos.h:70
SDManager * getSDManager()
Definition: Loom_Hypnos.h:199
DateTime getCurrentTime()
Definition: Loom_Hypnos.cpp:246
Definition: SDManager.h:15
bool writeLineToFile(const char *filename, const char *content)
Definition: SDManager.cpp:12