feat: Add per-subsystem log tags to all firmware modules
Refactored logging system to require a TAG as first argument on all LOG_* macros, enabling per-subsystem log filtering and cleaner output. Each subsystem now defines its own TAG (e.g. "BellEngine", "Player"). Also overhauled Logging.hpp/cpp with improved level control and output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,14 +1,28 @@
|
||||
/*
|
||||
* ═══════════════════════════════════════════════════════════════════════════════════
|
||||
* LOGGING.HPP - Centralized Logging System
|
||||
* LOGGING.HPP - Subsystem-Aware Centralized Logging System
|
||||
* ═══════════════════════════════════════════════════════════════════════════════════
|
||||
*
|
||||
*
|
||||
* 📝 THE INFORMATION CHRONICLER OF VESPER 📝
|
||||
*
|
||||
* This header provides a unified logging interface with multiple levels,
|
||||
* timestamps, and comprehensive debugging support throughout the system.
|
||||
*
|
||||
* 📋 VERSION: 2.0 (Enhanced logging system)
|
||||
*
|
||||
* Three independent output channels, each with their own level:
|
||||
* • Serial — USB debugging, local connection
|
||||
* • MQTT — Remote troubleshooting via web dashboard
|
||||
* • SD — Persistent log storage for post-mortem analysis
|
||||
*
|
||||
* Per-subsystem filtering: each subsystem tag can have its own level
|
||||
* overrides per channel. If no override is set, the global channel
|
||||
* level applies. Set a tag's level to NONE on a specific channel to
|
||||
* silence it entirely on that channel (e.g. MQTT internals on MQTT).
|
||||
*
|
||||
* Usage in each .cpp file:
|
||||
* #define TAG "BellEngine" // one line at the top
|
||||
* LOG_INFO(TAG, "Ring scheduled"); // all calls include the tag
|
||||
*
|
||||
* The JSON payload sent over MQTT includes the subsystem field:
|
||||
* {"level":"WARNING","subsystem":"BellEngine","message":"...","timestamp":12345}
|
||||
*
|
||||
* 📋 VERSION: 3.0 (Subsystem-aware logging)
|
||||
* 📅 DATE: 2025
|
||||
* 👨💻 AUTHOR: Advanced Bell Systems
|
||||
* ═══════════════════════════════════════════════════════════════════════════════════
|
||||
@@ -18,67 +32,114 @@
|
||||
#define LOGGING_HPP
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// Forward declaration
|
||||
class MQTTAsyncClient;
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
class Logging {
|
||||
public:
|
||||
// Log Levels
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// LOG LEVELS
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
enum LogLevel {
|
||||
NONE = 0, // No logs
|
||||
ERROR = 1, // Errors only
|
||||
WARNING = 2, // Warnings and errors
|
||||
INFO = 3, // Info, warnings, and errors
|
||||
DEBUG = 4, // Debug logs. Really high level (full debugging)
|
||||
VERBOSE = 5 // Nearly every command gets printed
|
||||
NONE = 0, // No output
|
||||
ERROR = 1, // Errors only
|
||||
WARNING = 2, // Warnings and errors
|
||||
INFO = 3, // Info, warnings, errors
|
||||
DEBUG = 4, // Debug detail
|
||||
VERBOSE = 5 // Everything
|
||||
};
|
||||
|
||||
// MQTT Log Publishing Callback
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// CALLBACK TYPES
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
using MqttPublishCallback = std::function<void(const String& topic, const String& payload, int qos)>;
|
||||
using SdWriteCallback = std::function<void(const String& line)>;
|
||||
|
||||
private:
|
||||
static LogLevel currentLevel;
|
||||
static LogLevel mqttLogLevel;
|
||||
static MqttPublishCallback mqttPublishCallback;
|
||||
static String mqttLogTopic;
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// GLOBAL CHANNEL LEVELS
|
||||
// Set the baseline level for each output channel.
|
||||
// Per-subsystem overrides take precedence when set.
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
static void setSerialLevel(LogLevel level);
|
||||
static void setMqttLevel(LogLevel level);
|
||||
static void setSdLevel(LogLevel level);
|
||||
|
||||
public:
|
||||
// Set the active log level
|
||||
static void setLevel(LogLevel level);
|
||||
static LogLevel getSerialLevel();
|
||||
static LogLevel getMqttLevel();
|
||||
static LogLevel getSdLevel();
|
||||
|
||||
// Get current log level
|
||||
static LogLevel getLevel();
|
||||
// Legacy compatibility (maps to serial level)
|
||||
static void setLevel(LogLevel level) { setSerialLevel(level); }
|
||||
static LogLevel getLevel() { return getSerialLevel(); }
|
||||
static void setMqttLogLevel(LogLevel level) { setMqttLevel(level); }
|
||||
static LogLevel getMqttLogLevel() { return getMqttLevel(); }
|
||||
|
||||
// Set MQTT log level (independent from serial logging)
|
||||
static void setMqttLogLevel(LogLevel level);
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// PER-SUBSYSTEM LEVEL OVERRIDES
|
||||
// Call these at startup to silence or focus specific subsystems per channel.
|
||||
// Pass NONE to completely silence a subsystem on a channel.
|
||||
// Pass a level to cap that subsystem at that level on that channel.
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
static void setSubsystemSerialLevel(const char* tag, LogLevel level);
|
||||
static void setSubsystemMqttLevel(const char* tag, LogLevel level);
|
||||
static void setSubsystemSdLevel(const char* tag, LogLevel level);
|
||||
|
||||
// Get MQTT log level
|
||||
static LogLevel getMqttLogLevel();
|
||||
|
||||
// Set MQTT callback for publishing logs
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// OUTPUT CHANNEL REGISTRATION
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
static void setMqttPublishCallback(MqttPublishCallback callback, const String& logTopic);
|
||||
static void setSdWriteCallback(SdWriteCallback callback);
|
||||
|
||||
// Logging functions
|
||||
static void error(const char* format, ...);
|
||||
static void warning(const char* format, ...);
|
||||
static void info(const char* format, ...);
|
||||
static void debug(const char* format, ...);
|
||||
static void verbose(const char* format, ...);
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// LOGGING FUNCTIONS (tag = subsystem name, e.g. "BellEngine")
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
static void error(const char* tag, const char* format, ...);
|
||||
static void warning(const char* tag, const char* format, ...);
|
||||
static void info(const char* tag, const char* format, ...);
|
||||
static void debug(const char* tag, const char* format, ...);
|
||||
static void verbose(const char* tag, const char* format, ...);
|
||||
|
||||
// Check if level is enabled (for conditional logging)
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// UTILITIES
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
static bool isLevelEnabled(LogLevel level);
|
||||
static String levelToString(LogLevel level);
|
||||
|
||||
private:
|
||||
static void log(LogLevel level, const char* levelStr, const char* format, va_list args);
|
||||
static void publishToMqtt(LogLevel level, const char* levelStr, const char* message);
|
||||
// Global channel levels
|
||||
static LogLevel _serialLevel;
|
||||
static LogLevel _mqttLevel;
|
||||
static LogLevel _sdLevel;
|
||||
|
||||
// Per-subsystem overrides per channel (tag -> level)
|
||||
// A value of NONE means "suppress this subsystem on this channel entirely"
|
||||
static std::map<String, LogLevel> _serialOverrides;
|
||||
static std::map<String, LogLevel> _mqttOverrides;
|
||||
static std::map<String, LogLevel> _sdOverrides;
|
||||
|
||||
// Output channel callbacks
|
||||
static MqttPublishCallback _mqttCallback;
|
||||
static SdWriteCallback _sdCallback;
|
||||
static String _mqttLogTopic;
|
||||
|
||||
// Core internal methods
|
||||
static void log(LogLevel level, const char* levelStr, const char* tag, const char* format, va_list args);
|
||||
static void publishToMqtt(LogLevel level, const char* levelStr, const char* tag, const char* message);
|
||||
static void writeToSd(LogLevel level, const char* levelStr, const char* tag, const char* message);
|
||||
|
||||
// Resolve effective level for a tag on a channel
|
||||
static LogLevel resolveLevel(const char* tag, LogLevel globalLevel, const std::map<String, LogLevel>& overrides);
|
||||
};
|
||||
|
||||
// Convenience macros for easier use
|
||||
#define LOG_ERROR(...) Logging::error(__VA_ARGS__)
|
||||
#define LOG_WARNING(...) Logging::warning(__VA_ARGS__)
|
||||
#define LOG_INFO(...) Logging::info(__VA_ARGS__)
|
||||
#define LOG_DEBUG(...) Logging::debug(__VA_ARGS__)
|
||||
#define LOG_VERBOSE(...) Logging::verbose(__VA_ARGS__)
|
||||
// ═══════════════════════════════════════════════════════════════════════════════════
|
||||
// MACROS
|
||||
// Each .cpp file defines: #define TAG "SubsystemName"
|
||||
// Then uses: LOG_INFO(TAG, "message %d", value)
|
||||
// ═══════════════════════════════════════════════════════════════════════════════════
|
||||
#define LOG_ERROR(tag, ...) Logging::error(tag, __VA_ARGS__)
|
||||
#define LOG_WARNING(tag, ...) Logging::warning(tag, __VA_ARGS__)
|
||||
#define LOG_INFO(tag, ...) Logging::info(tag, __VA_ARGS__)
|
||||
#define LOG_DEBUG(tag, ...) Logging::debug(tag, __VA_ARGS__)
|
||||
#define LOG_VERBOSE(tag, ...) Logging::verbose(tag, __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user