129 lines
3.6 KiB
Python
129 lines
3.6 KiB
Python
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)
|
|
|
|
# If it's an error, try to send it immediately as a message too
|
|
if level.upper() in ["ERROR", "CRITICAL"]:
|
|
threading.Thread(
|
|
target=send_discord_message,
|
|
args=(f"**[{level.upper()}] [{module}]** {message[:1900]}",),
|
|
daemon=True
|
|
).start()
|
|
|
|
|
|
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)
|