Download monitoring/logger.py from raghava4u/Trading-Bot-M20: direct link, hf CLI and curl.
- Browser
- Download file 3.21 kB
-
https://huggingface.co/raghava4u/Trading-Bot-M20/resolve/main/monitoring/logger.py
- Command line
-
hf download hf://raghava4u/Trading-Bot-M20/monitoring/logger.py
-
curl -L -o logger.py https://huggingface.co/raghava4u/Trading-Bot-M20/resolve/main/monitoring/logger.py
3.21 kB
| """ | |
| monitoring/logger.py — Structured JSON logging with file and console handlers. | |
| All log entries are structured JSON for machine parsing. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import logging | |
| import os | |
| import sys | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| import config | |
| LOG_DIR = Path(config.BASE_DIR) / "logs" | |
| LOG_DIR.mkdir(parents=True, exist_ok=True) | |
| class JSONFormatter(logging.Formatter): | |
| """Structured JSON log formatter.""" | |
| def format(self, record: logging.LogRecord) -> str: | |
| log_entry = { | |
| "timestamp": datetime.now(timezone.utc).isoformat(), | |
| "level": record.levelname, | |
| "logger": record.name, | |
| "message": record.getMessage(), | |
| "module": record.module, | |
| "function": record.funcName, | |
| "line": record.lineno, | |
| } | |
| if record.exc_info and record.exc_info[1]: | |
| log_entry["exception"] = str(record.exc_info[1]) | |
| if config.DRY_RUN: | |
| log_entry["mode"] = "DRY_RUN" | |
| elif config.TRADING_MODE == "paper": | |
| log_entry["mode"] = "PAPER" | |
| else: | |
| log_entry["mode"] = config.TRADING_MODE.upper() | |
| return json.dumps(log_entry) | |
| class ConsoleFormatter(logging.Formatter): | |
| """Colored console formatter.""" | |
| COLORS = { | |
| "DEBUG": "\033[36m", | |
| "INFO": "\033[32m", | |
| "WARNING": "\033[33m", | |
| "ERROR": "\033[31m", | |
| "CRITICAL": "\033[1;31m", | |
| } | |
| RESET = "\033[0m" | |
| def format(self, record: logging.LogRecord) -> str: | |
| color = self.COLORS.get(record.levelname, "") | |
| prefix = "[DRY_RUN] " if config.DRY_RUN else "" | |
| return ( | |
| f"{color}{record.levelname:8s}{self.RESET} " | |
| f"{prefix}{record.name}: {record.getMessage()}" | |
| ) | |
| def setup_logging(level: str = "INFO"): | |
| """Configure logging for the entire trading system.""" | |
| root = logging.getLogger() | |
| root.setLevel(getattr(logging, level.upper(), logging.INFO)) | |
| # Remove existing handlers | |
| root.handlers.clear() | |
| # Console handler | |
| console = logging.StreamHandler(sys.stdout) | |
| console.setFormatter(ConsoleFormatter()) | |
| console.setLevel(logging.INFO) | |
| root.addHandler(console) | |
| # JSON file handler | |
| today = datetime.now().strftime("%Y-%m-%d") | |
| log_file = LOG_DIR / f"trading_{today}.jsonl" | |
| file_handler = logging.FileHandler(str(log_file), encoding="utf-8") | |
| file_handler.setFormatter(JSONFormatter()) | |
| file_handler.setLevel(logging.DEBUG) | |
| root.addHandler(file_handler) | |
| # Error file handler | |
| error_file = LOG_DIR / f"errors_{today}.jsonl" | |
| error_handler = logging.FileHandler(str(error_file), encoding="utf-8") | |
| error_handler.setFormatter(JSONFormatter()) | |
| error_handler.setLevel(logging.ERROR) | |
| root.addHandler(error_handler) | |
| logging.getLogger("urllib3").setLevel(logging.WARNING) | |
| logging.getLogger("websocket").setLevel(logging.WARNING) | |
| logger = logging.getLogger("trading_system") | |
| logger.info("Logging initialized: console + %s", log_file) | |
| return logger | |