++
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from app.models.agent import AgentPersona
|
||||
@@ -12,28 +11,52 @@ from app.models.world import WorldMetrics
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
LOGS_DIR = Path(__file__).resolve().parent.parent.parent / "logs"
|
||||
|
||||
|
||||
class SimulationLogger:
|
||||
def __init__(self, sim_id: str):
|
||||
self._sim_id = sim_id
|
||||
LOGS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
self._path = LOGS_DIR / f"{sim_id}.jsonl"
|
||||
try:
|
||||
self._fh = open(self._path, "a", encoding="utf-8")
|
||||
except OSError as exc:
|
||||
logger.warning("SimulationLogger: cannot open %s: %s", self._path, exc)
|
||||
self._fh = None
|
||||
BACKEND_LOGS_DIR = Path(__file__).resolve().parent.parent.parent / "logs"
|
||||
PROJECT_LOGS_DIR = Path(__file__).resolve().parents[3] / "logs"
|
||||
|
||||
|
||||
class SimulationLogger:
|
||||
def __init__(self, sim_id: str):
|
||||
self._sim_id = sim_id
|
||||
# Keep the structured per-simulation log for programmatic inspection,
|
||||
# and create a human-readable text log in the project root at the
|
||||
# moment the user clicks "Create World".
|
||||
BACKEND_LOGS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
PROJECT_LOGS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
self._created_at = datetime.now().astimezone()
|
||||
self._path = BACKEND_LOGS_DIR / f"{sim_id}.jsonl"
|
||||
self.text_path = PROJECT_LOGS_DIR / (
|
||||
f"logs_{self._created_at.strftime('%Y%m%d_%H%M%S_%f')}.txt"
|
||||
)
|
||||
try:
|
||||
self._fh = open(self._path, "a", encoding="utf-8")
|
||||
except OSError as exc:
|
||||
logger.warning("SimulationLogger: cannot open %s: %s", self._path, exc)
|
||||
self._fh = None
|
||||
try:
|
||||
self._text_fh = open(self.text_path, "a", encoding="utf-8")
|
||||
self._text_fh.write(
|
||||
f"[{self._created_at.isoformat()}] simulation_started "
|
||||
f"sim_id={self._sim_id}\n"
|
||||
)
|
||||
self._text_fh.flush()
|
||||
except OSError as exc:
|
||||
logger.warning("SimulationLogger: cannot open %s: %s", self.text_path, exc)
|
||||
self._text_fh = None
|
||||
|
||||
def _write(self, record: dict[str, Any]):
|
||||
if not self._fh:
|
||||
return
|
||||
try:
|
||||
self._fh.write(json.dumps(record, default=str) + "\n")
|
||||
self._fh.flush()
|
||||
except Exception as exc:
|
||||
logger.debug("SimulationLogger write error: %s", exc)
|
||||
try:
|
||||
serialized = json.dumps(record, ensure_ascii=False, default=str)
|
||||
self._fh.write(serialized + "\n")
|
||||
self._fh.flush()
|
||||
if self._text_fh:
|
||||
ts = record.get("ts", datetime.now().astimezone().isoformat())
|
||||
self._text_fh.write(f"[{ts}] {serialized}\n")
|
||||
self._text_fh.flush()
|
||||
except Exception as exc:
|
||||
logger.debug("SimulationLogger write error: %s", exc)
|
||||
|
||||
def log_round(
|
||||
self,
|
||||
@@ -150,6 +173,16 @@ class SimulationLogger:
|
||||
if self._fh:
|
||||
try:
|
||||
self._fh.close()
|
||||
except Exception:
|
||||
pass
|
||||
self._fh = None
|
||||
except Exception:
|
||||
pass
|
||||
self._fh = None
|
||||
if self._text_fh:
|
||||
try:
|
||||
self._text_fh.write(
|
||||
f"[{datetime.now().astimezone().isoformat()}] simulation_log_closed\n"
|
||||
)
|
||||
self._text_fh.flush()
|
||||
self._text_fh.close()
|
||||
except Exception:
|
||||
pass
|
||||
self._text_fh = None
|
||||
|
||||
Reference in New Issue
Block a user