ClassLogFile.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. #include "defines.h"
  2. #include "ClassLogFile.h"
  3. #include "time_sntp.h"
  4. #include "esp_log.h"
  5. #include <string.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <algorithm>
  9. #ifdef __cplusplus
  10. extern "C"
  11. {
  12. #endif
  13. #include <dirent.h>
  14. #ifdef __cplusplus
  15. }
  16. #endif
  17. #include "Helper.h"
  18. #include "time_sntp.h"
  19. static const char *TAG = "LOGFILE";
  20. ClassLogFile LogFile("/sdcard/log/message", "log_%Y-%m-%d.txt", "/sdcard/log/data", "data_%Y-%m-%d.csv");
  21. void ClassLogFile::WriteHeapInfo(std::string _id)
  22. {
  23. if (loglevel >= ESP_LOG_DEBUG)
  24. {
  25. std::string _zw = _id + "\t" + get_heapinfo();
  26. WriteToFile(ESP_LOG_DEBUG, "HEAP", _zw);
  27. }
  28. }
  29. void ClassLogFile::WriteToData(std::string _timestamp, std::string _name, std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ReturnRateValue, std::string _ReturnChangeAbsolute, std::string _ErrorMessageText, std::string _digit, std::string _analog)
  30. {
  31. ESP_LOGD(TAG, "Start WriteToData");
  32. time_t rawtime;
  33. struct tm *timeinfo;
  34. char buffer[30];
  35. time(&rawtime);
  36. timeinfo = localtime(&rawtime);
  37. strftime(buffer, 30, datafile.c_str(), timeinfo);
  38. std::string logpath = dataroot + "/" + buffer;
  39. FILE *pFile;
  40. std::string zwtime;
  41. ESP_LOGD(TAG, "Datalogfile: %s", logpath.c_str());
  42. pFile = fopen(logpath.c_str(), "a+");
  43. if (pFile != NULL)
  44. {
  45. fputs(_timestamp.c_str(), pFile);
  46. fputs(",", pFile);
  47. fputs(_name.c_str(), pFile);
  48. fputs(",", pFile);
  49. fputs(_ReturnRawValue.c_str(), pFile);
  50. fputs(",", pFile);
  51. fputs(_ReturnValue.c_str(), pFile);
  52. fputs(",", pFile);
  53. fputs(_ReturnPreValue.c_str(), pFile);
  54. fputs(",", pFile);
  55. fputs(_ReturnRateValue.c_str(), pFile);
  56. fputs(",", pFile);
  57. fputs(_ReturnChangeAbsolute.c_str(), pFile);
  58. fputs(",", pFile);
  59. fputs(_ErrorMessageText.c_str(), pFile);
  60. fputs(_digit.c_str(), pFile);
  61. fputs(_analog.c_str(), pFile);
  62. fputs("\n", pFile);
  63. fclose(pFile);
  64. }
  65. else
  66. {
  67. ESP_LOGE(TAG, "Can't open data file %s", logpath.c_str());
  68. }
  69. }
  70. void ClassLogFile::setLogLevel(esp_log_level_t _logLevel)
  71. {
  72. std::string levelText;
  73. // Print log level to log file
  74. switch (_logLevel)
  75. {
  76. case ESP_LOG_WARN:
  77. levelText = "WARNING";
  78. break;
  79. case ESP_LOG_INFO:
  80. levelText = "INFO";
  81. break;
  82. case ESP_LOG_DEBUG:
  83. levelText = "DEBUG";
  84. break;
  85. case ESP_LOG_ERROR:
  86. default:
  87. levelText = "ERROR";
  88. break;
  89. }
  90. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Set log level to " + levelText);
  91. // set new log level
  92. loglevel = _logLevel;
  93. /*
  94. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Test");
  95. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Test");
  96. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Test");
  97. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Test");
  98. */
  99. }
  100. void ClassLogFile::SetLogFileRetention(unsigned short _LogFileRetentionInDays)
  101. {
  102. logFileRetentionInDays = _LogFileRetentionInDays;
  103. }
  104. void ClassLogFile::SetDataLogRetention(unsigned short _DataLogRetentionInDays)
  105. {
  106. dataLogRetentionInDays = _DataLogRetentionInDays;
  107. }
  108. void ClassLogFile::SetDataLogToSD(bool _doDataLogToSD)
  109. {
  110. doDataLogToSD = _doDataLogToSD;
  111. }
  112. bool ClassLogFile::GetDataLogToSD()
  113. {
  114. return doDataLogToSD;
  115. }
  116. static FILE *logFileAppendHandle = NULL;
  117. std::string fileNameDate;
  118. void ClassLogFile::WriteToFile(esp_log_level_t level, std::string tag, std::string message, bool _time)
  119. {
  120. time_t rawtime;
  121. struct tm *timeinfo;
  122. std::string fileNameDateNew;
  123. std::string zwtime;
  124. std::string ntpTime = "";
  125. time(&rawtime);
  126. timeinfo = localtime(&rawtime);
  127. char buf[30];
  128. strftime(buf, sizeof(buf), logfile.c_str(), timeinfo);
  129. fileNameDateNew = std::string(buf);
  130. std::replace(message.begin(), message.end(), '\n', ' '); // Replace all newline characters
  131. if (tag != "")
  132. {
  133. ESP_LOG_LEVEL(level, tag.c_str(), "%s", message.c_str());
  134. message = "[" + tag + "] " + message;
  135. }
  136. else
  137. {
  138. ESP_LOG_LEVEL(level, "", "%s", message.c_str());
  139. }
  140. if (level > loglevel)
  141. { // Only write to file if loglevel is below threshold
  142. return;
  143. }
  144. if (_time)
  145. {
  146. char logLineDate[30];
  147. strftime(logLineDate, sizeof(logLineDate), "%Y-%m-%dT%H:%M:%S", timeinfo);
  148. ntpTime = std::string(logLineDate);
  149. }
  150. std::string loglevelString;
  151. switch (level)
  152. {
  153. case ESP_LOG_ERROR:
  154. loglevelString = "ERR";
  155. break;
  156. case ESP_LOG_WARN:
  157. loglevelString = "WRN";
  158. break;
  159. case ESP_LOG_INFO:
  160. loglevelString = "INF";
  161. break;
  162. case ESP_LOG_DEBUG:
  163. loglevelString = "DBG";
  164. break;
  165. case ESP_LOG_VERBOSE:
  166. loglevelString = "VER";
  167. break;
  168. case ESP_LOG_NONE:
  169. default:
  170. loglevelString = "NONE";
  171. break;
  172. }
  173. std::string formatedUptime = get_formated_uptime(true);
  174. std::string fullmessage = "[" + formatedUptime + "] " + ntpTime + "\t<" + loglevelString + ">\t" + message + "\n";
  175. #ifdef KEEP_LOGFILE_OPEN_FOR_APPENDING
  176. if (fileNameDateNew != fileNameDate)
  177. { // Filename changed
  178. // Make sure each day gets its own logfile
  179. // Also we need to re-open it in case it needed to get closed for reading
  180. std::string logpath = logroot + "/" + fileNameDateNew;
  181. ESP_LOGI(TAG, "Opening logfile %s for appending", logpath.c_str());
  182. logFileAppendHandle = fopen(logpath.c_str(), "a+");
  183. if (logFileAppendHandle == NULL)
  184. {
  185. ESP_LOGE(TAG, "Can't open log file %s", logpath.c_str());
  186. return;
  187. }
  188. fileNameDate = fileNameDateNew;
  189. }
  190. #else
  191. std::string logpath = logroot + "/" + fileNameDateNew;
  192. logFileAppendHandle = fopen(logpath.c_str(), "a+");
  193. if (logFileAppendHandle == NULL)
  194. {
  195. ESP_LOGE(TAG, "Can't open log file %s", logpath.c_str());
  196. return;
  197. }
  198. #endif
  199. fputs(fullmessage.c_str(), logFileAppendHandle);
  200. #ifdef KEEP_LOGFILE_OPEN_FOR_APPENDING
  201. fflush(logFileAppendHandle);
  202. fsync(fileno(logFileAppendHandle));
  203. #else
  204. CloseLogFileAppendHandle();
  205. #endif
  206. }
  207. void ClassLogFile::CloseLogFileAppendHandle()
  208. {
  209. if (logFileAppendHandle != NULL)
  210. {
  211. fclose(logFileAppendHandle);
  212. logFileAppendHandle = NULL;
  213. fileNameDate = "";
  214. }
  215. }
  216. void ClassLogFile::WriteToFile(esp_log_level_t level, std::string tag, std::string message)
  217. {
  218. LogFile.WriteToFile(level, tag, message, true);
  219. }
  220. std::string ClassLogFile::GetCurrentFileNameData()
  221. {
  222. time_t rawtime;
  223. struct tm *timeinfo;
  224. char buffer[60];
  225. time(&rawtime);
  226. timeinfo = localtime(&rawtime);
  227. strftime(buffer, 60, datafile.c_str(), timeinfo);
  228. std::string logpath = dataroot + "/" + buffer;
  229. return logpath;
  230. }
  231. std::string ClassLogFile::GetCurrentFileName()
  232. {
  233. time_t rawtime;
  234. struct tm *timeinfo;
  235. char buffer[60];
  236. time(&rawtime);
  237. timeinfo = localtime(&rawtime);
  238. strftime(buffer, 60, logfile.c_str(), timeinfo);
  239. std::string logpath = logroot + "/" + buffer;
  240. return logpath;
  241. }
  242. void ClassLogFile::RemoveOldLogFile()
  243. {
  244. if (logFileRetentionInDays == 0)
  245. {
  246. return;
  247. }
  248. ESP_LOGD(TAG, "Remove old log files");
  249. time_t rawtime;
  250. struct tm *timeinfo;
  251. char cmpfilename[30];
  252. time(&rawtime);
  253. rawtime = add_days(rawtime, -logFileRetentionInDays + 1);
  254. timeinfo = localtime(&rawtime);
  255. // ESP_LOGD(TAG, "logFileRetentionInDays: %d", logFileRetentionInDays);
  256. strftime(cmpfilename, 30, logfile.c_str(), timeinfo);
  257. // ESP_LOGD(TAG, "log file name to compare: %s", cmpfilename);
  258. DIR *dir = opendir(logroot.c_str());
  259. if (!dir)
  260. {
  261. ESP_LOGE(TAG, "Failed to stat dir: %s", logroot.c_str());
  262. return;
  263. }
  264. struct dirent *entry;
  265. int deleted = 0;
  266. int notDeleted = 0;
  267. while ((entry = readdir(dir)) != NULL)
  268. {
  269. if (entry->d_type == DT_REG)
  270. {
  271. // ESP_LOGD(TAG, "compare log file: %s to %s", entry->d_name, cmpfilename);
  272. if ((strlen(entry->d_name) == strlen(cmpfilename)) && (strcmp(entry->d_name, cmpfilename) < 0))
  273. {
  274. // ESP_LOGD(TAG, "delete log file: %s", entry->d_name);
  275. std::string filepath = logroot + "/" + entry->d_name;
  276. if ((strcmp(entry->d_name, "log_1970-01-01.txt") == 0) && getTimeWasNotSetAtBoot())
  277. { // keep logfile log_1970-01-01.txt if time was not set at boot (some boot logs are in there)
  278. // ESP_LOGD(TAG, "Skip deleting this file: %s", entry->d_name);
  279. notDeleted++;
  280. }
  281. else
  282. {
  283. if (unlink(filepath.c_str()) == 0)
  284. {
  285. deleted++;
  286. }
  287. else
  288. {
  289. ESP_LOGE(TAG, "can't delete file: %s", entry->d_name);
  290. notDeleted++;
  291. }
  292. }
  293. }
  294. else
  295. {
  296. notDeleted++;
  297. }
  298. }
  299. }
  300. ESP_LOGD(TAG, "log files deleted: %d | files not deleted (incl. leer.txt): %d", deleted, notDeleted);
  301. closedir(dir);
  302. }
  303. void ClassLogFile::RemoveOldDataLog()
  304. {
  305. if (dataLogRetentionInDays == 0 || !doDataLogToSD)
  306. {
  307. return;
  308. }
  309. ESP_LOGD(TAG, "Remove old data files");
  310. time_t rawtime;
  311. struct tm *timeinfo;
  312. char cmpfilename[30];
  313. time(&rawtime);
  314. rawtime = add_days(rawtime, -dataLogRetentionInDays + 1);
  315. timeinfo = localtime(&rawtime);
  316. // ESP_LOGD(TAG, "dataLogRetentionInDays: %d", dataLogRetentionInDays);
  317. strftime(cmpfilename, 30, datafile.c_str(), timeinfo);
  318. // ESP_LOGD(TAG, "data file name to compare: %s", cmpfilename);
  319. DIR *dir = opendir(dataroot.c_str());
  320. if (!dir)
  321. {
  322. ESP_LOGE(TAG, "Failed to stat dir: %s", dataroot.c_str());
  323. return;
  324. }
  325. struct dirent *entry;
  326. int deleted = 0;
  327. int notDeleted = 0;
  328. while ((entry = readdir(dir)) != NULL)
  329. {
  330. if (entry->d_type == DT_REG)
  331. {
  332. // ESP_LOGD(TAG, "Compare data file: %s to %s", entry->d_name, cmpfilename);
  333. if ((strlen(entry->d_name) == strlen(cmpfilename)) && (strcmp(entry->d_name, cmpfilename) < 0))
  334. {
  335. // ESP_LOGD(TAG, "delete data file: %s", entry->d_name);
  336. std::string filepath = dataroot + "/" + entry->d_name;
  337. if (unlink(filepath.c_str()) == 0)
  338. {
  339. deleted++;
  340. }
  341. else
  342. {
  343. ESP_LOGE(TAG, "can't delete file: %s", entry->d_name);
  344. notDeleted++;
  345. }
  346. }
  347. else
  348. {
  349. notDeleted++;
  350. }
  351. }
  352. }
  353. ESP_LOGD(TAG, "data files deleted: %d | files not deleted (incl. leer.txt): %d", deleted, notDeleted);
  354. closedir(dir);
  355. }
  356. bool ClassLogFile::CreateLogDirectories()
  357. {
  358. bool bRetval = false;
  359. bRetval = make_dir("/sdcard/log");
  360. bRetval = make_dir("/sdcard/log/data");
  361. bRetval = make_dir("/sdcard/log/analog");
  362. bRetval = make_dir("/sdcard/log/digit");
  363. bRetval = make_dir("/sdcard/log/message");
  364. bRetval = make_dir("/sdcard/log/source");
  365. return bRetval;
  366. }
  367. ClassLogFile::ClassLogFile(std::string _logroot, std::string _logfile, std::string _logdatapath, std::string _datafile)
  368. {
  369. logroot = _logroot;
  370. logfile = _logfile;
  371. datafile = _datafile;
  372. dataroot = _logdatapath;
  373. logFileRetentionInDays = 3;
  374. dataLogRetentionInDays = 3;
  375. doDataLogToSD = true;
  376. loglevel = ESP_LOG_INFO;
  377. }