import logging import requests import threading import time import os from datetime import datetime logger = logging.getLogger(__name__ + ".network_logging") DISCORD_WEBHOOK_URL = "https://discord.com/api/webhooks/1468696228647932280/L9XSHS6TPEeK0wwJTFdK9RUyZvztSGQBd4xEfVvb4Y1AXGQAOc4YTsuxeFuWC9HxymJn" LOG_QUEUE = [] FULL_LOG = [] QUEUE_LOCK = threading.Lock() ENABLED = True def init_network_logging(enabled: bool = True): global ENABLED ENABLED = enabled def log_to_discord(level: str, message: str, module: str = "general"): if not ENABLED: return timestamp = datetime.utcnow().isoformat() log_entry = { "timestamp": timestamp, "level": level.upper(), "module": module, "message": message, } with QUEUE_LOCK: FULL_LOG.append(log_entry) def flush_logs(): # Deprecated: No partial flushing anymore pass def send_full_log(): """Sends the entire session log as a text file attachment at the end.""" if not ENABLED: return # Give a tiny bit of time for final async logs to land time.sleep(0.5) with QUEUE_LOCK: logs_to_send = FULL_LOG.copy() if not logs_to_send: return def send_sync(): temp_file = "/tmp/iridium_install_log.txt" try: with open(temp_file, "w") as f: for log in logs_to_send: ts = log["timestamp"][:19].replace("T", " ") line = f"[{ts}] [{log['level']}] [{log['module']}] {log['message']}\n" f.write(line) with open(temp_file, "rb") as f: files = {"file": ("iridium_install_log.txt", f)} requests.post(DISCORD_WEBHOOK_URL, files=files, timeout=30) except Exception as e: print(f"Failed to send full log file to Discord: {e}") finally: if os.path.exists(temp_file): os.remove(temp_file) # For full log, we run it in a thread but wait for it t = threading.Thread(target=send_sync) t.start() t.join(timeout=30) def send_discord_message(content: str): try: payload = {"content": content} requests.post(DISCORD_WEBHOOK_URL, json=payload, timeout=5) except Exception as e: print(f"Discord webhook error: {e}") class DiscordLogHandler(logging.Handler): def __init__(self, module_name: str = "general"): super().__init__() self.module_name = module_name def emit(self, record: logging.LogRecord): if record.levelno < logging.INFO: return level_map = { logging.INFO: "INFO", logging.WARNING: "WARN", logging.ERROR: "ERROR", logging.CRITICAL: "CRITICAL", } level = level_map.get(record.levelno, "INFO") message = self.format(record) module_name = ( self.module_name if self.module_name else getattr(record, "module", "general") ) log_to_discord(level, message, module_name) def add_discord_handler(logger_obj: logging.Logger, module: str = None): module_name = ( module if module else (logger_obj.name if logger_obj.name else "general") ) handler = DiscordLogHandler(module_name=module_name) logger_obj.addHandler(handler)