diff --git a/README.md b/README.md
index 69b7fff..0505917 100644
--- a/README.md
+++ b/README.md
@@ -60,16 +60,15 @@ Saving should be quite straightforward: just copy any message that is sent to th
Last but not least, the use should be as simple as possible: you just need to create `AdvancedLogger advancedLogger;` and simply use `advancedLogger.log("Setting up ADE7953...", "main::setup", INFO);`
## Dependencies
-This project depends on the following libraries:
-- [ArduinoJson](https://github.com/bblanchon/ArduinoJson), version 7.0.0 or later.
+This project has no external dependencies, and uses only the standard libraries.
## What's next?
-- [ ] **Customizable paths**: allow to set a custom path when creating the AdvancedLogger object.
-- [ ] **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.
+- [x] **Customizable paths**: allow to set a custom path when creating the AdvancedLogger object.
+- [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] **Dump to serial**: implement a function that dumps the entire log to the serial, so that it can be accessed in real time.
-- [ ] **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.
+- [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.
- [ ] **Upgrade to LittleFS**: the SPIFFS library is deprecated, and as such it should be replaced with the LittleFS library.
-- [ ] **Test other microcontrollers**: the library is currently tested only on the ESP32S3, but it should be tested on other microcontrollers to ensure compatibility.
+- [ ] **Test other microcontrollers**: the library is currently tested only on the ESP32, but it should be tested on other microcontrollers to ensure compatibility.
- [ ] **MQTT integration**: the ability to send logs to an MQTT server would be a great addition, as it would allow to monitor the device remotely.
-- [ ] ~~**Consistent spacing**: the spacing between the different parts of the log should be consistent, to make it easier to read.~~ Not needed, as the format is already quite clear.
\ No newline at end of file
+- [x] ~~**Consistent spacing**: the spacing between the different parts of the log should be consistent, to make it easier to read.~~ Not needed, as the format is already quite clear.
\ No newline at end of file
diff --git a/examples/basicServer/basicServer.cpp b/examples/basicServer/basicServer.cpp
index bd5fd95..e2cf028 100644
--- a/examples/basicServer/basicServer.cpp
+++ b/examples/basicServer/basicServer.cpp
@@ -4,7 +4,7 @@
* This file provides a simple example to show how to use the AdvancedLogger library.
*
* Author: Jibril Sharafi, @jibrilsharafi
- * Date: 11/05/2024
+ * Date: 07/04/2024
* GitHub repository: https://github.com/jibrilsharafi/AdvancedLogger
*
* This library is licensed under the MIT License. See the LICENSE file for more information.
@@ -34,7 +34,10 @@
#include "advancedLogger.h"
-AdvancedLogger logger;
+String customLogPath = "/customPath/log.txt";
+String customConfigPath = "/customPath/config.txt";
+
+AdvancedLogger logger(customLogPath.c_str(), customConfigPath.c_str()); // Leave empty for default paths
AsyncWebServer server(80);
@@ -47,6 +50,8 @@ const long intervalLogDump = 10000;
long lastMillisLogClear = 0;
const long intervalLogClear = 30000;
+int maxLogLines = 10; // Low value for testing purposes
+
// **** CHANGE THESE TO YOUR SSID AND PASSWORD ****
const char *ssid = "YOUR_SSID";
const char *password = "YOUR_PASSWORD";
@@ -70,6 +75,9 @@ void setup()
// levels are used (DEBUG for print and INFO for save).
logger.setPrintLevel(ADVANCEDLOGGER_DEBUG);
logger.setSaveLevel(ADVANCEDLOGGER_INFO);
+ // Set the maximum number of log lines before the log is cleared
+ // If you don't set this, the default is used
+ logger.setMaxLogLines(maxLogLines);
logger.log("AdvancedLogger setup done!", "basicServer::setup", ADVANCEDLOGGER_INFO);
// Connect to WiFi
@@ -86,8 +94,8 @@ void setup()
// --------------------
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(200, "text/html", "
"); });
- server.serveStatic("/log", SPIFFS, "/AdvancedLogger/log.txt");
- server.serveStatic("/config", SPIFFS, "/AdvancedLogger/config.json");
+ server.serveStatic("/log", SPIFFS, customLogPath.c_str());
+ server.serveStatic("/config", SPIFFS, customConfigPath.c_str());
server.onNotFound([](AsyncWebServerRequest *request)
{ request->send(404, "text/plain", "Not found"); });
server.begin();
@@ -101,12 +109,17 @@ void setup()
void loop()
{
logger.log("This is an debug message!", "basicServer::loop", ADVANCEDLOGGER_DEBUG);
+ delay(500);
logger.log("This is an info message!!", "basicServer::loop", ADVANCEDLOGGER_INFO);
+ delay(500);
logger.log("This is an warning message!!!", "basicServer::loop", ADVANCEDLOGGER_WARNING);
+ delay(500);
logger.log("This is an error message!!!!", "basicServer::loop", ADVANCEDLOGGER_ERROR);
+ delay(500);
logger.log("This is an fatal message!!!!!", "basicServer::loop", ADVANCEDLOGGER_FATAL);
- delay(1000);
+ delay(500);
logger.logOnly("This is an info message (logOnly)!!", "basicServer::loop", ADVANCEDLOGGER_INFO);
+ delay(1000);
printLevel = logger.getPrintLevel();
saveLevel = logger.getSaveLevel();
@@ -120,7 +133,11 @@ void loop()
if (millis() - lastMillisLogClear > intervalLogClear)
{
- logger.dumpToSerial();
+ logger.log(
+ ("Current number of log lines: " + String(logger.getLogLines())).c_str(),
+ "basicServer::loop",
+ ADVANCEDLOGGER_INFO
+ );
logger.clearLog();
logger.setDefaultLogLevels();
logger.log("Log cleared!", "basicServer::loop", ADVANCEDLOGGER_WARNING);
diff --git a/examples/basicUsage/basicUsage.cpp b/examples/basicUsage/basicUsage.cpp
index b8e9ce2..7918b8c 100644
--- a/examples/basicUsage/basicUsage.cpp
+++ b/examples/basicUsage/basicUsage.cpp
@@ -27,7 +27,10 @@
#include "advancedLogger.h"
-AdvancedLogger logger;
+String customLogPath = "/customPath/log.txt";
+String customConfigPath = "/customPath/config.txt";
+
+AdvancedLogger logger(customLogPath.c_str(), customConfigPath.c_str()); // Leave empty for default paths
String printLevel;
String saveLevel;
@@ -38,6 +41,8 @@ const long intervalLogDump = 10000;
long lastMillisLogClear = 0;
const long intervalLogClear = 30000;
+int maxLogLines = 10; // Low value for testing purposes
+
void setup()
{
// Initialize Serial and SPIFFS (mandatory for the AdvancedLogger library)
@@ -57,6 +62,10 @@ void setup()
// levels are used (DEBUG for print and INFO for save).
logger.setPrintLevel(ADVANCEDLOGGER_DEBUG);
logger.setSaveLevel(ADVANCEDLOGGER_INFO);
+ // Set the maximum number of log lines before the log is cleared
+ // If you don't set this, the default is used
+ logger.setMaxLogLines(maxLogLines);
+ logger.log("AdvancedLogger setup done!", "basicUsage::setup", ADVANCEDLOGGER_INFO);
lastMillisLogDump = millis();
lastMillisLogClear = millis();
@@ -65,13 +74,18 @@ void setup()
void loop()
{
- logger.log("This is an debug message!", "basicUsage::loop", ADVANCEDLOGGER_DEBUG);
- logger.log("This is an info message!!", "basicUsage::loop", ADVANCEDLOGGER_INFO);
- logger.log("This is an warning message!!!", "basicUsage::loop", ADVANCEDLOGGER_WARNING);
- logger.log("This is an error message!!!!", "basicUsage::loop", ADVANCEDLOGGER_ERROR);
- logger.log("This is an fatal message!!!!!", "basicUsage::loop", ADVANCEDLOGGER_FATAL);
+ logger.log("This is an debug message!", "basicServer::loop", ADVANCEDLOGGER_DEBUG);
+ delay(500);
+ logger.log("This is an info message!!", "basicServer::loop", ADVANCEDLOGGER_INFO);
+ delay(500);
+ logger.log("This is an warning message!!!", "basicServer::loop", ADVANCEDLOGGER_WARNING);
+ delay(500);
+ logger.log("This is an error message!!!!", "basicServer::loop", ADVANCEDLOGGER_ERROR);
+ delay(500);
+ logger.log("This is an fatal message!!!!!", "basicServer::loop", ADVANCEDLOGGER_FATAL);
+ delay(500);
+ logger.logOnly("This is an info message (logOnly)!!", "basicServer::loop", ADVANCEDLOGGER_INFO);
delay(1000);
- logger.logOnly("This is an info message (logOnly)!!", "basicUsage::loop", ADVANCEDLOGGER_INFO);
printLevel = logger.getPrintLevel();
saveLevel = logger.getSaveLevel();
@@ -85,7 +99,11 @@ void loop()
if (millis() - lastMillisLogClear > intervalLogClear)
{
- logger.dumpToSerial();
+ logger.log(
+ ("Current number of log lines: " + String(logger.getLogLines())).c_str(),
+ "basicServer::loop",
+ ADVANCEDLOGGER_INFO
+ );
logger.clearLog();
logger.setDefaultLogLevels();
logger.log("Log cleared!", "basicServer::loop", ADVANCEDLOGGER_WARNING);
diff --git a/library.json b/library.json
index 5a7e5c5..0e9c5e5 100644
--- a/library.json
+++ b/library.json
@@ -1,29 +1,21 @@
{
- "name": "AdvancedLogger",
- "keywords": "logger, log, logging, memory, format",
- "description": "Library for simple logging to memory with comprehensive format.",
- "repository":
+ "name": "AdvancedLogger",
+ "keywords": "logger, log, logging, memory, format",
+ "description": "Library for simple logging to memory with comprehensive format.",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/jibrilsharafi/AdvancedLogger.git"
+ },
+ "authors": [
{
- "type": "git",
- "url": "https://github.com/jibrilsharafi/AdvancedLogger.git"
- },
- "authors":
- [
- {
- "name": "Jibril Sharafi",
- "email": "jibril.sharafi@gmail.com",
- "url": "https://github.com/jibrilsharafi",
- "maintainer": true
- }
- ],
- "dependencies":
- {
- "name": "ArduinoJson",
- "authors": "bblanchon",
- "frameworks": "arduino"
- },
- "version": "1.1.0",
- "frameworks": "arduino",
- "platforms": "*"
- }
-
\ No newline at end of file
+ "name": "Jibril Sharafi",
+ "email": "jibril.sharafi@gmail.com",
+ "url": "https://github.com/jibrilsharafi",
+ "maintainer": true
+ }
+ ],
+ "dependencies": {},
+ "version": "1.1.0",
+ "frameworks": "arduino",
+ "platforms": "*"
+}
\ No newline at end of file
diff --git a/library.properties b/library.properties
index a7f5f72..a5fb2cc 100644
--- a/library.properties
+++ b/library.properties
@@ -7,4 +7,4 @@ paragraph=Easy to use, logs to memory using SPIFFS and the format contains all t
category=Communication
url=https://github.com/jibrilsharafi/AdvancedLogger
architectures=*
-depends=ArduinoJson
\ No newline at end of file
+depends=
\ No newline at end of file
diff --git a/src/advancedLogger.cpp b/src/advancedLogger.cpp
index b343453..5138774 100644
--- a/src/advancedLogger.cpp
+++ b/src/advancedLogger.cpp
@@ -1,17 +1,22 @@
#include "advancedLogger.h"
-AdvancedLogger::AdvancedLogger()
+AdvancedLogger::AdvancedLogger(const char *logFilePath, const char *configFilePath)
+ : _logFilePath(logFilePath), _configFilePath(configFilePath)
{
_printLevel = ADVANCEDLOGGER_DEFAULT_PRINT_LEVEL;
_saveLevel = ADVANCEDLOGGER_DEFAULT_SAVE_LEVEL;
+ _maxLogLines = ADVANCEDLOGGER_DEFAULT_MAX_LOG_LINES;
}
void AdvancedLogger::begin()
{
- if (!setLogLevelsFromSpiffs())
+ log("Initializing AdvancedLogger...", "advancedLogger::begin", ADVANCEDLOGGER_DEBUG);
+
+ if (!_setConfigFromSpiffs())
{
setDefaultLogLevels();
}
+
log("AdvancedLogger initialized", "advancedLogger::begin", ADVANCEDLOGGER_DEBUG);
}
@@ -44,6 +49,14 @@ void AdvancedLogger::log(const char *message, const char *function, int logLevel
if (logLevel >= _saveLevel)
{
_save(_message_formatted);
+ if (getLogLines() > _maxLogLines)
+ {
+ clearLog();
+ log(
+ ("Log cleared due to max log lines (" + String(_maxLogLines) + ") reached").c_str(),
+ "advancedLogger::log",
+ ADVANCEDLOGGER_WARNING);
+ }
}
}
@@ -81,7 +94,7 @@ void AdvancedLogger::setPrintLevel(int level)
"advancedLogger::setPrintLevel",
ADVANCEDLOGGER_INFO);
_printLevel = _saturateLogLevel(level);
- _saveLogLevelsToSpiffs();
+ _saveConfigToSpiffs();
}
void AdvancedLogger::setSaveLevel(int level)
@@ -91,7 +104,7 @@ void AdvancedLogger::setSaveLevel(int level)
"advancedLogger::setSaveLevel",
ADVANCEDLOGGER_INFO);
_saveLevel = _saturateLogLevel(level);
- _saveLogLevelsToSpiffs();
+ _saveConfigToSpiffs();
}
String AdvancedLogger::getPrintLevel()
@@ -108,69 +121,98 @@ void AdvancedLogger::setDefaultLogLevels()
{
setPrintLevel(ADVANCEDLOGGER_DEFAULT_PRINT_LEVEL);
setSaveLevel(ADVANCEDLOGGER_DEFAULT_SAVE_LEVEL);
- log("Log levels set to default", "advancedLogger::setDefaultLogLevels", ADVANCEDLOGGER_DEBUG);
+ setMaxLogLines(ADVANCEDLOGGER_DEFAULT_MAX_LOG_LINES);
+
+ log("Log levels set to default", "advancedLogger::setDefaultLogLevels", ADVANCEDLOGGER_INFO);
}
-bool AdvancedLogger::setLogLevelsFromSpiffs()
+bool AdvancedLogger::_setConfigFromSpiffs()
{
- log("Deserializing JSON from SPIFFS", "utils::deserializeJsonFromSpiffs", ADVANCEDLOGGER_DEBUG);
-
- File _file = SPIFFS.open(ADVANCEDLOGGER_CONFIG_PATH, "r");
- if (!_file)
+ File file = SPIFFS.open(_configFilePath, "r");
+ if (!file)
{
- log(
- ("Failed to open file " + String(ADVANCEDLOGGER_CONFIG_PATH)).c_str(),
- "utils::deserializeJsonFromSpiffs",
- ADVANCEDLOGGER_ERROR);
+ log("Failed to open config file for reading", "advancedLogger::_setConfigFromSpiffs", ADVANCEDLOGGER_ERROR);
return false;
}
- JsonDocument _jsonDocument;
- DeserializationError _error = deserializeJson(_jsonDocument, _file);
- _file.close();
- if (_error)
+ while (file.available())
{
- log(
- ("Failed to deserialize file " + String(ADVANCEDLOGGER_CONFIG_PATH) + ". Error: " + String(_error.c_str())).c_str(),
- "utils::deserializeJsonFromSpiffs",
- ADVANCEDLOGGER_ERROR);
- return false;
+ String line = file.readStringUntil('\n');
+ int separatorPosition = line.indexOf('=');
+ String key = line.substring(0, separatorPosition);
+ String value = line.substring(separatorPosition + 1);
+
+ if (key == "printLevel")
+ {
+ setPrintLevel(value.toInt());
+ }
+ else if (key == "saveLevel")
+ {
+ setSaveLevel(value.toInt());
+ }
+ else if (key == "maxLogLines")
+ {
+ setMaxLogLines(value.toInt());
+ }
}
- log("JSON deserialized from SPIFFS correctly", "utils::deserializeJsonFromSpiffs", ADVANCEDLOGGER_DEBUG);
+ file.close();
+ log("Log levels set from SPIFFS", "advancedLogger::_setConfigFromSpiffs", ADVANCEDLOGGER_DEBUG);
+ return true;
+}
- if (_jsonDocument.isNull())
+void AdvancedLogger::_saveConfigToSpiffs()
+{
+ File file = SPIFFS.open(_configFilePath, "w");
+ if (!file)
{
- return false;
+ log("Failed to open config file for writing", "advancedLogger::_saveConfigToSpiffs", ADVANCEDLOGGER_ERROR);
+ return;
}
- setPrintLevel(_jsonDocument["level"]["print"].as());
- setSaveLevel(_jsonDocument["level"]["save"].as());
- log("Log levels set from SPIFFS", "advancedLogger::setLogLevelsFromSpiffs", ADVANCEDLOGGER_DEBUG);
- return true;
+ file.println(String("printLevel=") + String(_printLevel));
+ file.println(String("saveLevel=") + String(_saveLevel));
+ file.println(String("maxLogLines=") + String(_maxLogLines));
+ file.close();
+ log("Log levels saved to SPIFFS", "advancedLogger::_saveConfigToSpiffs", ADVANCEDLOGGER_DEBUG);
}
-void AdvancedLogger::_saveLogLevelsToSpiffs()
+void AdvancedLogger::setMaxLogLines(int maxLines)
{
- JsonDocument _jsonDocument;
- _jsonDocument["level"]["print"] = _printLevel;
- _jsonDocument["level"]["save"] = _saveLevel;
- File _file = SPIFFS.open(ADVANCEDLOGGER_CONFIG_PATH, "w");
- if (!_file)
+ log(
+ ("Setting max log lines to " + String(maxLines)).c_str(),
+ "advancedLogger::setMaxLogLines",
+ ADVANCEDLOGGER_INFO);
+ _maxLogLines = maxLines;
+ _saveConfigToSpiffs();
+}
+
+int AdvancedLogger::getLogLines()
+{
+ File file = SPIFFS.open(_logFilePath, "r");
+ if (!file)
{
- log("Failed to open logger.json", "advancedLogger::_saveLogLevelsToSpiffs", ADVANCEDLOGGER_ERROR);
- return;
+ logOnly("Failed to open log file", "advancedLogger::getLogLines", ADVANCEDLOGGER_ERROR);
+ return -1;
}
- serializeJson(_jsonDocument, _file);
- _file.close();
- log("Log levels saved to SPIFFS", "advancedLogger::_saveLogLevelsToSpiffs", ADVANCEDLOGGER_DEBUG);
+
+ int lines = 0;
+ while (file.available())
+ {
+ if (file.read() == '\n')
+ {
+ lines++;
+ }
+ }
+ file.close();
+ return lines;
}
void AdvancedLogger::clearLog()
{
logOnly("Clearing log", "advancedLogger::clearLog", ADVANCEDLOGGER_WARNING);
- SPIFFS.remove(ADVANCEDLOGGER_LOG_PATH);
- File _file = SPIFFS.open(ADVANCEDLOGGER_LOG_PATH, "w");
+ SPIFFS.remove(_logFilePath);
+ File _file = SPIFFS.open(_logFilePath, "w");
if (!_file)
{
logOnly("Failed to open log file", "advancedLogger::clearLog", ADVANCEDLOGGER_ERROR);
@@ -182,7 +224,7 @@ void AdvancedLogger::clearLog()
void AdvancedLogger::_save(const char *messageFormatted)
{
- File file = SPIFFS.open(ADVANCEDLOGGER_LOG_PATH, "a");
+ File file = SPIFFS.open(_logFilePath, "a");
if (file)
{
file.println(messageFormatted);
@@ -197,15 +239,15 @@ void AdvancedLogger::_save(const char *messageFormatted)
void AdvancedLogger::dumpToSerial()
{
logOnly(
- "Dumping log to Serial",
- "advancedLogger::dumpToSerial",
- ADVANCEDLOGGER_INFO
- );
+ "Dumping log to Serial",
+ "advancedLogger::dumpToSerial",
+ ADVANCEDLOGGER_INFO);
- for(int i = 0; i < 2*50; i++) Serial.print("_");
+ for (int i = 0; i < 2 * 50; i++)
+ Serial.print("_");
Serial.println();
- File file = SPIFFS.open(ADVANCEDLOGGER_LOG_PATH, "r");
+ File file = SPIFFS.open(_logFilePath, "r");
if (!file)
{
logOnly("Failed to open log file", "advancedLogger::dumpToSerial", ADVANCEDLOGGER_ERROR);
@@ -218,14 +260,14 @@ void AdvancedLogger::dumpToSerial()
}
file.close();
- for(int i = 0; i < 2*50; i++) Serial.print("_");
+ for (int i = 0; i < 2 * 50; i++)
+ Serial.print("_");
Serial.println();
logOnly(
- "Log dumped to Serial",
- "advancedLogger::dumpToSerial",
- ADVANCEDLOGGER_INFO
- );
+ "Log dumped to Serial",
+ "advancedLogger::dumpToSerial",
+ ADVANCEDLOGGER_INFO);
}
String AdvancedLogger::_logLevelToString(int logLevel)
diff --git a/src/advancedLogger.h b/src/advancedLogger.h
index 3393110..2928864 100644
--- a/src/advancedLogger.h
+++ b/src/advancedLogger.h
@@ -28,22 +28,22 @@
#define ADVANCEDLOGGER_DEFAULT_PRINT_LEVEL 2 // 2 = INFO
#define ADVANCEDLOGGER_DEFAULT_SAVE_LEVEL 3 // 3 = WARNING
+#define ADVANCEDLOGGER_DEFAULT_MAX_LOG_LINES 1000 // 1000 lines before the log is cleared
#define ADVANCEDLOGGER_TIMESTAMP_FORMAT "%Y-%m-%d %H:%M:%S"
#define ADVANCEDLOGGER_FORMAT "[%s] [%lu ms] [%s] [Core %d] [%s] %s" // [TIME] [MICROS us] [LOG_LEVEL] [Core CORE] [FUNCTION] MESSAGE
#define ADVANCEDLOGGER_LOG_PATH "/AdvancedLogger/log.txt"
-#define ADVANCEDLOGGER_CONFIG_PATH "/AdvancedLogger/config.json"
+#define ADVANCEDLOGGER_CONFIG_PATH "/AdvancedLogger/config.txt"
#include
#include
-#include
class AdvancedLogger
{
public:
- AdvancedLogger();
+ AdvancedLogger(const char *logFilePath = ADVANCEDLOGGER_LOG_PATH, const char *configFilePath = ADVANCEDLOGGER_CONFIG_PATH);
void begin();
@@ -56,18 +56,25 @@ class AdvancedLogger
String getSaveLevel();
void setDefaultLogLevels();
- bool setLogLevelsFromSpiffs();
+ void setMaxLogLines(int maxLines);
+ int getLogLines();
void clearLog();
void dumpToSerial();
private:
+ String _logFilePath;
+ String _configFilePath;
+
int _printLevel;
int _saveLevel;
+
+ int _maxLogLines;
void _save(const char *messageFormatted);
- void _saveLogLevelsToSpiffs();
+ bool _setConfigFromSpiffs();
+ void _saveConfigToSpiffs();
String _logLevelToString(int logLevel);
int _saturateLogLevel(int logLevel);