Add command FileLog 10..14 to enable logging to filesystem using up to 16 log files of 100kB

This commit is contained in:
Theo Arends 2025-01-16 15:07:49 +01:00
parent ec8cf6e2f0
commit 6d7aab4662
5 changed files with 88 additions and 41 deletions

View File

@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
## [14.4.1.3] ## [14.4.1.3]
### Added ### Added
- Command `FileLog 0..4` to enable logging to filesystem using up to 16 rotating log files of 100kB (`#define FILE_LOG_SIZE 100`) - Command `FileLog 0..4` to enable logging to filesystem using up to 16 rotating log files of 100kB (`#define FILE_LOG_SIZE 100`)
- Command `FileLog 10..14` to enable logging to filesystem using up to 16 log files of 100kB (`#define FILE_LOG_SIZE 100`)
- I2S Opus stream and file support for opus/aac (#22795) - I2S Opus stream and file support for opus/aac (#22795)
- I2S command I2sLoop (#22807) - I2S command I2sLoop (#22807)

View File

@ -118,6 +118,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
### Added ### Added
- Command `SetOption163 1` to disable display of Device name in GUI header - Command `SetOption163 1` to disable display of Device name in GUI header
- Command `FileLog 0..4` to enable logging to filesystem using up to 16 rotating log files of 100kB (`#define FILE_LOG_SIZE 100`) - Command `FileLog 0..4` to enable logging to filesystem using up to 16 rotating log files of 100kB (`#define FILE_LOG_SIZE 100`)
- Command `FileLog 10..14` to enable logging to filesystem using up to 16 log files of 100kB (`#define FILE_LOG_SIZE 100`)
- Command I2sLoop [#22807](https://github.com/arendst/Tasmota/issues/22807) - Command I2sLoop [#22807](https://github.com/arendst/Tasmota/issues/22807)
- Support for PCF85063 RTC [#22727](https://github.com/arendst/Tasmota/issues/22727) - Support for PCF85063 RTC [#22727](https://github.com/arendst/Tasmota/issues/22727)
- Support for Senseair S88 CO2 sensor [#22733](https://github.com/arendst/Tasmota/issues/22733) - Support for Senseair S88 CO2 sensor [#22733](https://github.com/arendst/Tasmota/issues/22733)

View File

@ -2650,7 +2650,8 @@ void AddLogData(uint32_t loglevel, const char* log_data, const char* log_data_pa
uint32_t highest_loglevel = Settings->weblog_level; uint32_t highest_loglevel = Settings->weblog_level;
if (Settings->mqttlog_level > highest_loglevel) { highest_loglevel = Settings->mqttlog_level; } if (Settings->mqttlog_level > highest_loglevel) { highest_loglevel = Settings->mqttlog_level; }
#ifdef USE_UFILESYS #ifdef USE_UFILESYS
if (Settings->filelog_level > highest_loglevel) { highest_loglevel = Settings->filelog_level; } uint32_t filelog_level = Settings->filelog_level % 10;
if (filelog_level > highest_loglevel) { highest_loglevel = filelog_level; }
#endif // USE_UFILESYS #endif // USE_UFILESYS
if (TasmotaGlobal.syslog_level > highest_loglevel) { highest_loglevel = TasmotaGlobal.syslog_level; } if (TasmotaGlobal.syslog_level > highest_loglevel) { highest_loglevel = TasmotaGlobal.syslog_level; }
if (TasmotaGlobal.templog_level > highest_loglevel) { highest_loglevel = TasmotaGlobal.templog_level; } if (TasmotaGlobal.templog_level > highest_loglevel) { highest_loglevel = TasmotaGlobal.templog_level; }

View File

@ -2163,8 +2163,22 @@ void CmndLogport(void)
#ifdef USE_UFILESYS #ifdef USE_UFILESYS
void CmndFilelog(void) { void CmndFilelog(void) {
if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) { // Filelog 0 - Disable file logging
Settings->filelog_level = XdrvMailbox.payload; // Filelog 1..4 - Enable rotating file logging
// Filelog 10 - Remove log files and disable file logging
// Filelog 11..14 - Remove log files and enable file logging until filesystem is full or max rotates
if (XdrvMailbox.payload >= LOG_LEVEL_NONE) {
uint32_t filelog_level = XdrvMailbox.payload % 10;
uint32_t filelog_option = XdrvMailbox.payload / 10;
if (1 == filelog_option) { // Enable file logging until filesystem is full
FileLoggingDelete(); // Remove all log files
if (LOG_LEVEL_NONE == filelog_level) { // Remove log files and disable logging
filelog_option = 0;
}
}
if ((filelog_level >= LOG_LEVEL_NONE) && (filelog_level <= LOG_LEVEL_DEBUG_MORE)) {
Settings->filelog_level = (filelog_option * 10) + filelog_level;
}
} }
ResponseCmndNumber(Settings->filelog_level); ResponseCmndNumber(Settings->filelog_level);
} }

View File

@ -497,43 +497,80 @@ bool TfsRenameFile(const char *fname1, const char *fname2) {
/*********************************************************************************************\ /*********************************************************************************************\
* Log file * Log file
* *
* Enable with command `FileLog 1..4` * Enable with command `FileLog 1..4` or `FileLog 11..14`
* Rotate max 16 x FILE_LOG_SIZE kB log files /log01 -> /log02 ... /log16 -> /log01 ... * Rotate max 16 x FILE_LOG_SIZE kB log files /log01 -> /log02 ... /log16 -> /log01 ...
* Filesystem needs to be larger than FILE_LOG_SIZE + LOG_BUFFER_SIZE * Filesystem needs to be larger than 10k (FILE_LOG_FREE)
\*********************************************************************************************/ \*********************************************************************************************/
#ifndef FILE_LOG_SIZE #ifndef FILE_LOG_SIZE
#define FILE_LOG_SIZE 100 // Log file size in kBytes (100kB is based on minimal filesystem of 320kB) #define FILE_LOG_SIZE 100 // Log file size in kBytes (100kB is based on minimal filesystem of 320kB)
#endif #endif
#define FILE_LOG_FREE FILE_LOG_SIZE+(LOG_BUFFER_SIZE/1000) // Minimum free filesystem space in kBytes #define FILE_LOG_FREE 10 // Minimum free filesystem space in kBytes
#define FILE_LOG_COUNT 16 // Number of log files (max 16 as four bits are reserved for index) #define FILE_LOG_COUNT 16 // Number of log files (max 16 as four bits are reserved for index)
#define FILE_LOG_NAME "/log%02d" // Log file name #define FILE_LOG_NAME "/log%02d" // Log file name
void FileLoggingAsync(bool refresh) { void FileLoggingAsync(bool refresh) {
static uint32_t index = 1; // Rotating log buffer entry pointer static uint32_t index = 1; // Rotating log buffer entry pointer
if (!ffs_type || !Settings->filelog_level) { return; } // No filesystem or [FileLog] disabled uint32_t filelog_level = Settings->filelog_level % 10;
if (refresh && !NeedLogRefresh(Settings->filelog_level, index)) { return; } // No log buffer changes if (!ffs_type || !filelog_level) { return; } // No filesystem or [FileLog] disabled
if (UfsSize() < FILE_LOG_FREE) { if (refresh && !NeedLogRefresh(filelog_level, index)) { return; } // No log buffer changes
Settings->filelog_level = 0; // [FileLog] disable uint32_t filelog_option = Settings->filelog_level / 10;
AddLog(LOG_LEVEL_INFO, PSTR("FLG: Logging diabled. Filesystem too small")); // Or FILE_LOG_SIZE too large
return;
}
char fname[14]; char fname[14];
snprintf_P(fname, sizeof(fname), PSTR(FILE_LOG_NAME), Settings->mbflag2.log_file_idx +1); // /log01 File file;
File file = ffsp->open(fname, "a"); // Append to existing log file uint32_t log_file_idx = Settings->mbflag2.log_file_idx; // 0..15
if (!file) { for (uint32_t retry = 0; retry <= 1; retry++) {
if (UfsFree() < FILE_LOG_FREE) { snprintf_P(fname, sizeof(fname), PSTR(FILE_LOG_NAME), log_file_idx +1); // /log01
file = ffsp->open(fname, "a"); // Append to existing log file
if (!file) {
file = ffsp->open(fname, "w"); // Make new log file
if (!file) {
Settings->filelog_level = 0; // [FileLog] disable
AddLog(LOG_LEVEL_INFO, PSTR("FLG: Logging disabled. Save failed"));
return; // Failed to make file
}
}
bool fs_full = (UfsFree() < FILE_LOG_FREE);
if (!fs_full && (file.size() < (FILE_LOG_SIZE * 1000))) { break; }
file.close();
if (1 == retry) {
Settings->filelog_level = 0; // [FileLog] disable Settings->filelog_level = 0; // [FileLog] disable
AddLog(LOG_LEVEL_INFO, PSTR("FLG: Logging disabled. Filesystem full")); AddLog(LOG_LEVEL_INFO, PSTR("FLG: Logging disabled. No free space"));
return; return;
} }
file = ffsp->open(fname, "w"); // Make new log file
if (!file) { // Rotate log file(s) as size is over FILE_LOG_SIZE or free space is less than FILE_LOG_FREE
uint32_t last_log_file_idx = log_file_idx; // 0..15
log_file_idx++;
if ((1 == filelog_option) &&
(fs_full || (log_file_idx == FILE_LOG_COUNT))) { // Rotate until free space is less than FILE_LOG_FREE
Settings->filelog_level = 0; // [FileLog] disable Settings->filelog_level = 0; // [FileLog] disable
AddLog(LOG_LEVEL_INFO, PSTR("FLG: Logging disabled. Save failed")); AddLog(LOG_LEVEL_INFO, PSTR("FLG: Logging disabled. Max rotates"));
return; // Failed to make file return;
}
if (log_file_idx >= FILE_LOG_COUNT) { log_file_idx = 0; } // Rotate max 16 log files
snprintf_P(fname, sizeof(fname), PSTR(FILE_LOG_NAME), log_file_idx +1);
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("FLG: Rotate file %s"), fname +1); // Skip leading slash
Settings->mbflag2.log_file_idx = log_file_idx; // Save for restart or power on
if (0 == filelog_option) { // Remove oldest log file(s)
// Remove log file(s) taking into account non-sequential file names and different file sizes
uint32_t idx = log_file_idx; // Next log file index
do { // Need free space around FILE_LOG_SIZE so find oldest log file(s) and remove it
snprintf_P(fname, sizeof(fname), PSTR(FILE_LOG_NAME), idx +1);
if (ffsp->remove(fname)) { // Remove oldest (non-)sequential log file(s)
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("FLG: Delete file %s"), fname +1); // Skip leading slash
}
idx++;
if (idx >= FILE_LOG_COUNT) { idx = 0; }
} while ((UfsFree() < FILE_LOG_FREE) && (idx != last_log_file_idx));
} }
} }
@ -542,7 +579,7 @@ void FileLoggingAsync(bool refresh) {
#endif #endif
char* line; char* line;
size_t len; size_t len;
while (GetLog(Settings->filelog_level, &index, &line, &len)) { while (GetLog(filelog_level, &index, &line, &len)) {
// This will timeout on ESP32-webcam // This will timeout on ESP32-webcam
// But now solved with WcInterrupt(0) in support_esp.ino // But now solved with WcInterrupt(0) in support_esp.ino
file.write((uint8_t*)line, len -1); // Write up to LOG_BUFFER_SIZE log data file.write((uint8_t*)line, len -1); // Write up to LOG_BUFFER_SIZE log data
@ -553,25 +590,19 @@ void FileLoggingAsync(bool refresh) {
WcInterrupt(1); WcInterrupt(1);
#endif #endif
uint32_t file_size = file.size();
file.close(); file.close();
if (file_size > (FILE_LOG_SIZE * 1000)) { }
// Rotate log file(s) as size is over FILE_LOG_SIZE
// Taking into account non-sequential file names and different file sizes void FileLoggingDelete(void) {
uint32_t log_file_idx = Settings->mbflag2.log_file_idx; // 0..15 if (!ffs_type) { return; } // No filesystem
log_file_idx++;
if (log_file_idx >= FILE_LOG_COUNT) { log_file_idx = 0; } // Rotate max 16 log files char fname[14];
uint32_t idx = log_file_idx; for (uint32_t idx = 0; idx < FILE_LOG_COUNT; idx++) {
do { // Need free space around FILE_LOG_SIZE so find oldest log file(s) and remove it snprintf_P(fname, sizeof(fname), PSTR(FILE_LOG_NAME), idx +1);
snprintf_P(fname, sizeof(fname), PSTR(FILE_LOG_NAME), idx +1); ffsp->remove(fname); // Remove all log file(s)
ffsp->remove(fname); // Remove oldest (non-)sequential log file(s)
idx++;
if (idx >= FILE_LOG_COUNT) { idx = 0; }
} while ((UfsFree() < FILE_LOG_FREE) && (idx != Settings->mbflag2.log_file_idx));
Settings->mbflag2.log_file_idx = log_file_idx; // Save for restart or power on
snprintf_P(fname, sizeof(fname), PSTR(FILE_LOG_NAME), log_file_idx +1);
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("FLG: Rotate file %s"), fname +1); // Skip leading slash
} }
Settings->mbflag2.log_file_idx = 0;
AddLog(LOG_LEVEL_INFO, PSTR("FLG: Log files deleted"));
} }
/*********************************************************************************************\ /*********************************************************************************************\
@ -1819,7 +1850,6 @@ void Switch_FTP(void) {
* Interface * Interface
\*********************************************************************************************/ \*********************************************************************************************/
bool Xdrv50(uint32_t function) { bool Xdrv50(uint32_t function) {
bool result = false; bool result = false;