Improve logging with timestamps, icons, and detailed output
This commit is contained in:
@@ -32,6 +32,11 @@ CONFIG_DEFAULTS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class System2MQTT:
|
class System2MQTT:
|
||||||
|
@staticmethod
|
||||||
|
def _timestamp() -> str:
|
||||||
|
"""Get formatted timestamp for logging."""
|
||||||
|
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
def __init__(self, config_path: str = None):
|
def __init__(self, config_path: str = None):
|
||||||
self.config = self._load_config(config_path)
|
self.config = self._load_config(config_path)
|
||||||
self.hostname = socket.gethostname()
|
self.hostname = socket.gethostname()
|
||||||
@@ -88,10 +93,11 @@ class System2MQTT:
|
|||||||
else:
|
else:
|
||||||
config[k] = v
|
config[k] = v
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Warning: failed to load config file {config_path}: {e}")
|
print(f"⚠️ [{self._timestamp()}] WARNING: Failed to load config file '{config_path}': {e}")
|
||||||
print("Proceeding with defaults and environment overrides.")
|
print(f"ℹ️ [{self._timestamp()}] INFO: Proceeding with defaults and environment overrides")
|
||||||
else:
|
else:
|
||||||
print(f"Config file '{config_path}' not found; using defaults and environment variables if set.")
|
print(f"ℹ️ [{self._timestamp()}] INFO: Config file '{config_path}' not found")
|
||||||
|
print(f"ℹ️ [{self._timestamp()}] INFO: Using defaults and environment variables")
|
||||||
|
|
||||||
# Ensure necessary sub-keys exist
|
# Ensure necessary sub-keys exist
|
||||||
config.setdefault('mqtt', CONFIG_DEFAULTS['mqtt'].copy())
|
config.setdefault('mqtt', CONFIG_DEFAULTS['mqtt'].copy())
|
||||||
@@ -100,6 +106,9 @@ class System2MQTT:
|
|||||||
|
|
||||||
# Apply environment variable overrides
|
# Apply environment variable overrides
|
||||||
self._merge_env_overrides(config)
|
self._merge_env_overrides(config)
|
||||||
|
|
||||||
|
# Log loaded config path
|
||||||
|
print(f"ℹ️ [{self._timestamp()}] INFO: Loaded configuration from '{config_path}'")
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
@@ -116,7 +125,7 @@ class System2MQTT:
|
|||||||
try:
|
try:
|
||||||
config['mqtt']['port'] = int(os.environ['MQTT_PORT'])
|
config['mqtt']['port'] = int(os.environ['MQTT_PORT'])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print("Warning: MQTT_PORT is not an integer; ignoring env override")
|
print(f"⚠️ [{self._timestamp()}] WARNING: MQTT_PORT environment variable is not an integer; ignoring override")
|
||||||
if 'MQTT_USERNAME' in os.environ:
|
if 'MQTT_USERNAME' in os.environ:
|
||||||
config['mqtt']['username'] = os.environ['MQTT_USERNAME']
|
config['mqtt']['username'] = os.environ['MQTT_USERNAME']
|
||||||
if 'MQTT_PASSWORD' in os.environ:
|
if 'MQTT_PASSWORD' in os.environ:
|
||||||
@@ -131,7 +140,7 @@ class System2MQTT:
|
|||||||
try:
|
try:
|
||||||
config['collectors']['default_interval'] = int(os.environ['COLLECTORS_DEFAULT_INTERVAL'])
|
config['collectors']['default_interval'] = int(os.environ['COLLECTORS_DEFAULT_INTERVAL'])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print("Warning: COLLECTORS_DEFAULT_INTERVAL is not an integer; ignoring env override")
|
print(f"⚠️ [{self._timestamp()}] WARNING: COLLECTORS_DEFAULT_INTERVAL is not an integer; ignoring override")
|
||||||
|
|
||||||
# Per-collector overrides
|
# Per-collector overrides
|
||||||
for key, val in os.environ.items():
|
for key, val in os.environ.items():
|
||||||
@@ -143,7 +152,7 @@ class System2MQTT:
|
|||||||
try:
|
try:
|
||||||
config['collectors']['intervals'][name] = int(val)
|
config['collectors']['intervals'][name] = int(val)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print(f"Warning: {key} must be an integer; ignoring")
|
print(f"⚠️ [{self._timestamp()}] WARNING: Collector interval '{key}' must be an integer; ignoring")
|
||||||
|
|
||||||
def _setup_mqtt_client(self) -> mqtt.Client:
|
def _setup_mqtt_client(self) -> mqtt.Client:
|
||||||
"""Setup paho-mqtt client with configuration (callback API v2 when available)."""
|
"""Setup paho-mqtt client with configuration (callback API v2 when available)."""
|
||||||
@@ -168,15 +177,21 @@ class System2MQTT:
|
|||||||
except Exception:
|
except Exception:
|
||||||
rc_val = 0
|
rc_val = 0
|
||||||
if rc_val == 0:
|
if rc_val == 0:
|
||||||
print("Connected to MQTT broker")
|
mqtt_host = self.config['mqtt']['host']
|
||||||
|
mqtt_port = self.config['mqtt']['port']
|
||||||
|
print(f"✓ [{self._timestamp()}] SUCCESS: Connected to MQTT broker at {mqtt_host}:{mqtt_port}")
|
||||||
self.connected = True
|
self.connected = True
|
||||||
else:
|
else:
|
||||||
print(f"Failed to connect to MQTT broker with code: {rc_val}")
|
mqtt_host = self.config['mqtt']['host']
|
||||||
|
mqtt_port = self.config['mqtt']['port']
|
||||||
|
print(f"✗ [{self._timestamp()}] ERROR: Failed to connect to MQTT broker at {mqtt_host}:{mqtt_port} (code: {rc_val})")
|
||||||
self.connected = False
|
self.connected = False
|
||||||
|
|
||||||
def _on_disconnect(self, client, userdata, rc, reason_code=None, properties=None):
|
def _on_disconnect(self, client, userdata, rc, reason_code=None, properties=None):
|
||||||
"""Callback when disconnected (paho v2)."""
|
"""Callback when disconnected (paho v2)."""
|
||||||
print("Disconnected from MQTT broker")
|
mqtt_host = self.config['mqtt']['host']
|
||||||
|
mqtt_port = self.config['mqtt']['port']
|
||||||
|
print(f"⚠️ [{self._timestamp()}] INFO: Disconnected from MQTT broker at {mqtt_host}:{mqtt_port}")
|
||||||
self.connected = False
|
self.connected = False
|
||||||
|
|
||||||
def _get_device_info(self) -> Dict[str, Any]:
|
def _get_device_info(self) -> Dict[str, Any]:
|
||||||
@@ -226,14 +241,14 @@ class System2MQTT:
|
|||||||
'name': module_name,
|
'name': module_name,
|
||||||
'interval': interval
|
'interval': interval
|
||||||
})
|
})
|
||||||
print(f"Loaded collector: {module_name} (interval: {interval}s)")
|
print(f"✓ [{self._timestamp()}] SUCCESS: Loaded collector '{module_name}' (update interval: {interval}s)")
|
||||||
|
|
||||||
return collectors
|
return collectors
|
||||||
|
|
||||||
async def process_collector_data(self, data: Dict[str, Any]):
|
async def process_collector_data(self, data: Dict[str, Any]):
|
||||||
"""Process data from collectors and publish to MQTT."""
|
"""Process data from collectors and publish to MQTT."""
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
print("Not connected to MQTT broker")
|
print(f"⚠️ [{self._timestamp()}] WARNING: Cannot process collector data - not connected to MQTT broker")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Publish discovery messages for each entity
|
# Publish discovery messages for each entity
|
||||||
@@ -295,11 +310,12 @@ class System2MQTT:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
data = collector['module'].collect_metrics()
|
data = collector['module'].collect_metrics()
|
||||||
|
entity_count = len(data.get('entities', []))
|
||||||
await self.process_collector_data(data)
|
await self.process_collector_data(data)
|
||||||
self.last_run[collector['name']] = datetime.now()
|
self.last_run[collector['name']] = datetime.now()
|
||||||
print(f"Updated {collector['name']} metrics")
|
print(f"✓ [{self._timestamp()}] SUCCESS: Updated {entity_count} metrics from '{collector['name']}'")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error collecting metrics from {collector['name']}: {e}")
|
print(f"✗ [{self._timestamp()}] ERROR: Failed to collect metrics from '{collector['name']}': {e}")
|
||||||
|
|
||||||
async def connect(self):
|
async def connect(self):
|
||||||
"""Connect to MQTT broker using paho-mqtt and wait briefly for on_connect."""
|
"""Connect to MQTT broker using paho-mqtt and wait briefly for on_connect."""
|
||||||
@@ -313,7 +329,9 @@ class System2MQTT:
|
|||||||
break
|
break
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error connecting to MQTT broker: {e}")
|
mqtt_host = self.config['mqtt']['host']
|
||||||
|
mqtt_port = self.config['mqtt']['port']
|
||||||
|
print(f"✗ [{self._timestamp()}] FATAL: Cannot connect to MQTT broker at {mqtt_host}:{mqtt_port}: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
async def disconnect(self):
|
async def disconnect(self):
|
||||||
@@ -327,6 +345,7 @@ class System2MQTT:
|
|||||||
|
|
||||||
async def async_main():
|
async def async_main():
|
||||||
"""Async main function."""
|
"""Async main function."""
|
||||||
|
print(f"🚀 [{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] INFO: Starting system2mqtt...")
|
||||||
system2mqtt = System2MQTT()
|
system2mqtt = System2MQTT()
|
||||||
await system2mqtt.connect()
|
await system2mqtt.connect()
|
||||||
|
|
||||||
@@ -340,9 +359,10 @@ async def async_main():
|
|||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\nShutting down...")
|
print(f"\n⚠️ [{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] INFO: Received shutdown signal, stopping...")
|
||||||
finally:
|
finally:
|
||||||
await system2mqtt.disconnect()
|
await system2mqtt.disconnect()
|
||||||
|
print(f"✓ [{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] INFO: Shutdown complete")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(async_main())
|
asyncio.run(async_main())
|
||||||
Reference in New Issue
Block a user