From 85176756ec9c148a28e76d94e58477d4b0bac340 Mon Sep 17 00:00:00 2001 From: Christopher Hoover Date: Thu, 15 Aug 2024 17:09:06 -0700 Subject: [PATCH] Adds ASCII log option needed by portudino (#4443) * Adds ASCII logs useful to portudino Activates ASCII log option when stdout is not a terminal. This is generally the right thing to do; if not, the behavior can be overridden in config.yaml using AsciiLogs under Logging. The result is reasonable system logs for portudino when running under systemd or the like. Signed-off-by: Christopher Hoover --- bin/config-dist.yaml | 3 +- src/DebugConfiguration.cpp | 16 +++++- src/RedirectablePrint.cpp | 70 +++++++++++++++++------- src/platform/portduino/PortduinoGlue.cpp | 5 ++ src/platform/portduino/PortduinoGlue.h | 5 +- 5 files changed, 76 insertions(+), 23 deletions(-) diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml index 1cd219c4ce..5590ed3b0a 100644 --- a/bin/config-dist.yaml +++ b/bin/config-dist.yaml @@ -145,6 +145,7 @@ Input: Logging: LogLevel: info # debug, info, warn, error # TraceFile: /var/log/meshtasticd.json +# AsciiLogs: true # default if not specified is !isatty() on stdout Webserver: # Port: 443 # Port for Webserver & Webservices @@ -152,4 +153,4 @@ Webserver: General: MaxNodes: 200 - MaxMessageQueue: 100 \ No newline at end of file + MaxMessageQueue: 100 diff --git a/src/DebugConfiguration.cpp b/src/DebugConfiguration.cpp index d58856c4db..23b140daf7 100644 --- a/src/DebugConfiguration.cpp +++ b/src/DebugConfiguration.cpp @@ -26,6 +26,10 @@ SOFTWARE.*/ #include "DebugConfiguration.h" +#ifdef ARCH_PORTDUINO +#include "platform/portduino/PortduinoGlue.h" +#endif + /// A C wrapper for LOG_DEBUG that can be used from arduino C libs that don't know about C++ or meshtastic extern "C" void logLegacy(const char *level, const char *fmt, ...) { @@ -139,6 +143,11 @@ bool Syslog::vlogf(uint16_t pri, const char *appName, const char *fmt, va_list a inline bool Syslog::_sendLog(uint16_t pri, const char *appName, const char *message) { int result; +#ifdef ARCH_PORTDUINO + bool utf = !settingsMap[ascii_logs]; +#else + bool utf = true; +#endif if (!this->_enabled) return false; @@ -169,7 +178,12 @@ inline bool Syslog::_sendLog(uint16_t pri, const char *appName, const char *mess this->_client->print(this->_deviceHostname); this->_client->print(' '); this->_client->print(appName); - this->_client->print(F(" - - - \xEF\xBB\xBF")); + this->_client->print(F(" - - - ")); + if (utf) { + this->_client->print(F("\xEF\xBB\xBF")); + } else { + this->_client->print(F(" ")); + } this->_client->print(F("[")); this->_client->print(int(millis() / 1000)); this->_client->print(F("]: ")); diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 05d349de92..c2b0c55dbe 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -55,6 +55,12 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l static char printBuf[160]; #endif +#ifdef ARCH_PORTDUINO + bool color = !settingsMap[ascii_logs]; +#else + bool color = true; +#endif + va_copy(copy, arg); size_t len = vsnprintf(printBuf, sizeof(printBuf), format, copy); va_end(copy); @@ -70,7 +76,7 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l if (!std::isprint(static_cast(printBuf[f])) && printBuf[f] != '\n') printBuf[f] = '#'; } - if (logLevel != nullptr) { + if (color && logLevel != nullptr) { if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) Print::write("\u001b[34m", 6); if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) @@ -81,7 +87,9 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l Print::write("\u001b[31m", 6); } len = Print::write(printBuf, len); - Print::write("\u001b[0m", 5); + if (color && logLevel != nullptr) { + Print::write("\u001b[0m", 5); + } return len; } @@ -91,19 +99,27 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, // Cope with 0 len format strings, but look for new line terminator bool hasNewline = *format && format[strlen(format) - 1] == '\n'; +#ifdef ARCH_PORTDUINO + bool color = !settingsMap[ascii_logs]; +#else + bool color = true; +#endif // If we are the first message on a report, include the header if (!isContinuationMessage) { - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) - Print::write("\u001b[34m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) - Print::write("\u001b[32m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) - Print::write("\u001b[33m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) - Print::write("\u001b[31m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) - Print::write("\u001b[35m", 6); + if (color) { + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) + Print::write("\u001b[34m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) + Print::write("\u001b[32m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) + Print::write("\u001b[33m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) + Print::write("\u001b[31m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) + Print::write("\u001b[35m", 6); + } + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile if (rtc_sec > 0) { long hms = rtc_sec % SEC_PER_DAY; @@ -117,17 +133,33 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN #ifdef ARCH_PORTDUINO - ::printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); + ::printf("%s ", logLevel); + if (color) { + ::printf("\u001b[0m"); + } + ::printf("| %02d:%02d:%02d %u ", hour, min, sec, millis() / 1000); #else - printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); + printf("%s ", logLevel); + if (color) { + printf("\u001b[0m"); + } + printf("| %02d:%02d:%02d %u ", hour, min, sec, millis() / 1000); #endif - } else + } else { #ifdef ARCH_PORTDUINO - ::printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); + ::printf("%s ", logLevel); + if (color) { + ::printf("\u001b[0m"); + } + ::printf("| ??:??:?? %u ", millis() / 1000); #else - printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); + printf("%s ", logLevel); + if (color) { + printf("\u001b[0m"); + } + printf("| ??:??:?? %u ", millis() / 1000); #endif - + } auto thread = concurrency::OSThread::currentThread; if (thread) { print("["); @@ -350,4 +382,4 @@ std::string RedirectablePrint::mt_sprintf(const std::string fmt_str, ...) break; } return std::string(formatted.get()); -} \ No newline at end of file +} diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index f8dd79b203..3532d2e79f 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -99,6 +99,7 @@ void portduinoSetup() settingsStrings[spidev] = ""; settingsStrings[displayspidev] = ""; settingsMap[spiSpeed] = 2000000; + settingsMap[ascii_logs] = !isatty(1); YAML::Node yamlConfig; @@ -152,6 +153,10 @@ void portduinoSetup() settingsMap[logoutputlevel] = level_error; } settingsStrings[traceFilename] = yamlConfig["Logging"]["TraceFile"].as(""); + if (yamlConfig["Logging"]["AsciiLogs"]) { + // Default is !isatty(1) but can be set explicitly in config.yaml + settingsMap[ascii_logs] = yamlConfig["Logging"]["AsciiLogs"].as(); + } } if (yamlConfig["Lora"]) { settingsMap[use_sx1262] = false; diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index 0c81b8686d..3fee1db400 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -53,7 +53,8 @@ enum configNames { webserverport, webserverrootpath, maxtophone, - maxnodes + maxnodes, + ascii_logs }; enum { no_screen, x11, st7789, st7735, st7735s, st7796, ili9341, ili9488, hx8357d }; enum { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 }; @@ -62,4 +63,4 @@ enum { level_error, level_warn, level_info, level_debug, level_trace }; extern std::map settingsMap; extern std::map settingsStrings; extern std::ofstream traceFile; -int initGPIOPin(int pinNum, std::string gpioChipname); \ No newline at end of file +int initGPIOPin(int pinNum, std::string gpioChipname);