Skip to content

Commit

Permalink
Merge pull request #15 from jibrilsharafi/development
Browse files Browse the repository at this point in the history
Log clearing improvement
  • Loading branch information
jibrilsharafi authored Aug 24, 2024
2 parents f0db97e + 4e34ad5 commit cce85a7
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 17 deletions.
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ Alternatively, the library can be installed manually by downloading the latest r
**No external dependencies are required**, as the library uses only the standard libraries in the Arduino Framework.

The library so far has been successfully tested on the following microcontrollers:

- ESP32S3

## Usage

### Basic

The simplest way to use the library is the following:

```cpp
#include <AdvancedLogger.h>

Expand All @@ -53,14 +57,18 @@ void loop() {
...
}
```

Output (both in the Serial and in the log file in the SPIFFS memory):

```cpp
[2024-03-23 09:44:10] [1 450 ms] [INFO ] [Core 1] [main::setup] This is an info message!
[2024-03-23 09:44:11] [2 459 ms] [ERROR ] [Core 1] [main::loop] This is an error message!! Random value: 42
```

### Advanced

The library provides the following public methods:

- `begin()`: initializes the logger, creating the log file and loading the configuration.
- Logging methods. All of them have the same structure, where the first argument is the message to be logged, and the second argument is the function name. The message can be formatted using the `printf` syntax.
- `verbose(const char *format, const char *function = "functionName", ...)`
Expand All @@ -69,29 +77,32 @@ The library provides the following public methods:
- `warning(const char *format, const char *function = "functionName", ...)`
- `error(const char *format, const char *function = "functionName", ...)`
- `fatal(const char *format, const char *function = "functionName", ...)`
- `setPrintLevel(LogLevel logLevel)` and `setSaveLevel(LogLevel logLevel)`: set the log level for printing and saving respectively. The log level can be one of the following (The default log level is **INFO**, and the default save level is WARNING):
- `LogLevel::VERBOSE`
- `setPrintLevel(LogLevel logLevel)` and `setSaveLevel(LogLevel logLevel)`: set the log level for printing and saving respectively. The log level can be one of the following (The default log level is **INFO**, and the default save level is WARNING):
- `LogLevel::VERBOSE`
- `LogLevel::DEBUG`
- `LogLevel::INFO`
- `LogLevel::WARNING`
- `LogLevel::ERROR`
- `LogLevel::FATAL`
- `LogLevel::WARNING`
- `LogLevel::ERROR`
- `LogLevel::FATAL`
- `getPrintLevel()` and `getSaveLevel()`: get the log level for printing and saving respectively, as a LogLevel enum. To be used in conjunction with the `logLevelToString` method.
- `logLevelToString(LogLevel logLevel, bool trim = true)`: convert a log level from the LogLevel enum to a String.
- `setMaxLogLines(int maxLogLines)`: set the maximum number of log lines. The default value is 1000.
- `getLogLines()`: get the number of log lines.
- `clearLogKeepLatestXPercent(int percentage)`: clear the log, keeping the latest X percent of the logs. By default, it keeps the latest 10% of the logs.
- `clearLog()`: clear the log.
- `dump(Stream& stream)`: dump the log to a stream, such as the Serial or an opened file.
- `setDefaultConfig()`: set the default configuration.

For a detailed example, see the [basicUsage](examples/basicUsage/basicUsage.ino) and [basicServer](examples/basicServer/basicServer.ino) in the examples folder.

## Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. If you'd like to contribute, please fork the repository and use a feature branch. Pull requests are warmly welcome.

For more information regarding the necessity of this library, see the [WHY.md](WHY.md) file.
For more information regarding the necessity of this library, see the [WHY.md](WHY.md) file.

### What's next?

- [x] **Automatic log clearing**: if the free memory is less than a certain threshold, the oldest logs should be deleted, keeping the memory usage under control.
- [ ] **Log to SD card**: the ability to log to an external SD card would be a great addition, as it would allow to store a much larger amount of logs.
- [x] **Remove ArduinoJson dependency**: the library is used only for the configuration file, and as such it could be removed by implementing a simpler configuration in .txt format.
Expand All @@ -107,4 +118,4 @@ For more information regarding the necessity of this library, see the [WHY.md](W

## Licensing

The code in this project is licensed under MIT license. See the [LICENSE](LICENSE) file for more information.
The code in this project is licensed under MIT license. See the [LICENSE](LICENSE) file for more information.
6 changes: 4 additions & 2 deletions examples/basicUsage/basicUsage.ino
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* Author: Jibril Sharafi, @jibrilsharafi
* Created: 21/03/2024
* Last modified: 22/05/2024
* Last modified: 24/08/2024
* GitHub repository: https://github.com/jibrilsharafi/AdvancedLogger
*
* This library is licensed under the MIT License. See the LICENSE file for more information.
Expand Down Expand Up @@ -139,7 +139,9 @@ void loop()
if (millis() - lastMillisLogClear > intervalLogClear)
{
// Clear the log and set the default configuration
logger.clearLog();
logger.clearLogKeepLatestXPercent(50);
// If you want to clear the log without keeping the latest X percent of the log, use:
// logger.clearLog();
logger.setDefaultConfig();

logger.info("Log cleared and default configuration set!", "basicUsage::loop");
Expand Down
56 changes: 52 additions & 4 deletions src/AdvancedLogger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ void AdvancedLogger::_log(const char *message, const char *function, LogLevel lo
_save(_messageFormatted);
if (_logLines >= _maxLogLines)
{
clearLog();
clearLogKeepLatestXPercent();
}
}
}
Expand Down Expand Up @@ -262,7 +262,7 @@ void AdvancedLogger::_logPrint(const char *format, const char *function, LogLeve
*/
void AdvancedLogger::setPrintLevel(LogLevel logLevel)
{
debug("Setting print level to %s", logLevelToString(logLevel).c_str(), "AdvancedLogger::setPrintLevel");
debug("Setting print level to %s", "AdvancedLogger::setPrintLevel", logLevelToString(logLevel).c_str());
_printLevel = logLevel;
_saveConfigToSpiffs();
}
Expand All @@ -276,7 +276,7 @@ void AdvancedLogger::setPrintLevel(LogLevel logLevel)
*/
void AdvancedLogger::setSaveLevel(LogLevel logLevel)
{
debug("Setting save level to %s", logLevelToString(logLevel).c_str(), "AdvancedLogger::setSaveLevel");
debug("Setting save level to %s", "AdvancedLogger::setSaveLevel", logLevelToString(logLevel).c_str());
_saveLevel = logLevel;
_saveConfigToSpiffs();
}
Expand Down Expand Up @@ -457,6 +457,54 @@ void AdvancedLogger::clearLog()
_logPrint("Log cleared", "AdvancedLogger::clearLog", LogLevel::INFO);
}

/**
* @brief Clears the log but keeps the latest X percent of log entries.
*
* This method clears the log file but retains the latest X percent of log entries.
* The default value is 10%.
*/
void AdvancedLogger::clearLogKeepLatestXPercent(int percent = 10)
{
File _file = SPIFFS.open(_logFilePath, "r");
if (!_file)
{
LOG_E("Failed to open log file for reading");
_logPrint("Failed to open log file", "AdvancedLogger::clearLogKeepLatestXPercent", LogLevel::ERROR);
return;
}

std::vector<std::string> lines;
while (_file.available())
{
String line = _file.readStringUntil('\n');
lines.push_back(line.c_str());
}
_file.close();

size_t totalLines = lines.size();
percent = min(max(percent, 0), 100);
size_t linesToKeep = totalLines / 100 * percent;

_file = SPIFFS.open(_logFilePath, "w");
if (!_file)
{
LOG_E("Failed to open log file for writing");
_logPrint("Failed to open log file", "AdvancedLogger::clearLogKeepLatestXPercent", LogLevel::ERROR);
return;
}

for (size_t i = totalLines - linesToKeep; i < totalLines; ++i)
{
_file.print(lines[i].c_str());
}
_file.close();

_logLines = linesToKeep;
_logPrint("Log cleared but kept the latest 10%", "AdvancedLogger::clearLogKeepLatestXPercent", LogLevel::INFO);
}

// ...

/**
* @brief Saves a message to the log file.
*
Expand Down Expand Up @@ -683,4 +731,4 @@ std::string AdvancedLogger::_formatMillis(unsigned long millis) {
insertPosition -= 3;
}
return str;
}
}
10 changes: 6 additions & 4 deletions src/AdvancedLogger.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
* advanced logging for the ESP32.
*
* Author: Jibril Sharafi, @jibrilsharafi
* Date: 22/05/2024
* GitHub repository: https://github.com/jibrilsharafi/AdvancedLogger
* Version: 1.2.0
*
* This library is licensed under the MIT License. See the LICENSE file for more information.
*
Expand All @@ -21,6 +19,9 @@
#include <Arduino.h>
#include <SPIFFS.h>

#include <vector>
#include <string>

#define CORE_ID xPortGetCoreID()
#define LOG_D(format, ...) log_d(format, ##__VA_ARGS__)
#define LOG_I(format, ...) log_i(format, ##__VA_ARGS__)
Expand All @@ -36,8 +37,8 @@ enum class LogLevel : int {
FATAL = 5
};

constexpr const LogLevel DEFAULT_PRINT_LEVEL = LogLevel::INFO;
constexpr const LogLevel DEFAULT_SAVE_LEVEL = LogLevel::WARNING;
constexpr const LogLevel DEFAULT_PRINT_LEVEL = LogLevel::DEBUG;
constexpr const LogLevel DEFAULT_SAVE_LEVEL = LogLevel::INFO;

constexpr int MAX_LOG_LENGTH = 1024;

Expand Down Expand Up @@ -78,6 +79,7 @@ class AdvancedLogger
void setMaxLogLines(int maxLogLines);
int getLogLines();
void clearLog();
void clearLogKeepLatestXPercent(int percent);

void dump(Stream& stream);

Expand Down

0 comments on commit cce85a7

Please sign in to comment.