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]
### 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 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 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
- 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 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)
- 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)

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;
if (Settings->mqttlog_level > highest_loglevel) { highest_loglevel = Settings->mqttlog_level; }
#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
if (TasmotaGlobal.syslog_level > highest_loglevel) { highest_loglevel = TasmotaGlobal.syslog_level; }
if (TasmotaGlobal.templog_level > highest_loglevel) { highest_loglevel = TasmotaGlobal.templog_level; }

View File

@ -2163,8 +2163,22 @@ void CmndLogport(void)
#ifdef USE_UFILESYS
void CmndFilelog(void) {
if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) {
Settings->filelog_level = XdrvMailbox.payload;
// Filelog 0 - Disable file logging
// 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);
}

View File

@ -497,38 +497,34 @@ bool TfsRenameFile(const char *fname1, const char *fname2) {
/*********************************************************************************************\
* 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 ...
* 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
#define FILE_LOG_SIZE 100 // Log file size in kBytes (100kB is based on minimal filesystem of 320kB)
#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_NAME "/log%02d" // Log file name
void FileLoggingAsync(bool refresh) {
static uint32_t index = 1; // Rotating log buffer entry pointer
if (!ffs_type || !Settings->filelog_level) { return; } // No filesystem or [FileLog] disabled
if (refresh && !NeedLogRefresh(Settings->filelog_level, index)) { return; } // No log buffer changes
if (UfsSize() < FILE_LOG_FREE) {
Settings->filelog_level = 0; // [FileLog] disable
AddLog(LOG_LEVEL_INFO, PSTR("FLG: Logging diabled. Filesystem too small")); // Or FILE_LOG_SIZE too large
return;
}
uint32_t filelog_level = Settings->filelog_level % 10;
if (!ffs_type || !filelog_level) { return; } // No filesystem or [FileLog] disabled
if (refresh && !NeedLogRefresh(filelog_level, index)) { return; } // No log buffer changes
uint32_t filelog_option = Settings->filelog_level / 10;
char fname[14];
snprintf_P(fname, sizeof(fname), PSTR(FILE_LOG_NAME), Settings->mbflag2.log_file_idx +1); // /log01
File file = ffsp->open(fname, "a"); // Append to existing log file
File file;
uint32_t log_file_idx = Settings->mbflag2.log_file_idx; // 0..15
for (uint32_t retry = 0; retry <= 1; retry++) {
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) {
if (UfsFree() < FILE_LOG_FREE) {
Settings->filelog_level = 0; // [FileLog] disable
AddLog(LOG_LEVEL_INFO, PSTR("FLG: Logging disabled. Filesystem full"));
return;
}
file = ffsp->open(fname, "w"); // Make new log file
if (!file) {
Settings->filelog_level = 0; // [FileLog] disable
@ -537,12 +533,53 @@ void FileLoggingAsync(bool refresh) {
}
}
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
AddLog(LOG_LEVEL_INFO, PSTR("FLG: Logging disabled. No free space"));
return;
}
// 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
AddLog(LOG_LEVEL_INFO, PSTR("FLG: Logging disabled. Max rotates"));
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));
}
}
#ifdef USE_WEBCAM
WcInterrupt(0); // Stop stream if active to fix TG1WDT_SYS_RESET
#endif
char* line;
size_t len;
while (GetLog(Settings->filelog_level, &index, &line, &len)) {
while (GetLog(filelog_level, &index, &line, &len)) {
// This will timeout on ESP32-webcam
// 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
@ -553,25 +590,19 @@ void FileLoggingAsync(bool refresh) {
WcInterrupt(1);
#endif
uint32_t file_size = file.size();
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
uint32_t log_file_idx = Settings->mbflag2.log_file_idx; // 0..15
log_file_idx++;
if (log_file_idx >= FILE_LOG_COUNT) { log_file_idx = 0; } // Rotate max 16 log files
uint32_t idx = log_file_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);
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
}
void FileLoggingDelete(void) {
if (!ffs_type) { return; } // No filesystem
char fname[14];
for (uint32_t idx = 0; idx < FILE_LOG_COUNT; idx++) {
snprintf_P(fname, sizeof(fname), PSTR(FILE_LOG_NAME), idx +1);
ffsp->remove(fname); // Remove all log file(s)
}
Settings->mbflag2.log_file_idx = 0;
AddLog(LOG_LEVEL_INFO, PSTR("FLG: Log files deleted"));
}
/*********************************************************************************************\
@ -1819,7 +1850,6 @@ void Switch_FTP(void) {
* Interface
\*********************************************************************************************/
bool Xdrv50(uint32_t function) {
bool result = false;