- teleo-pipeline.py: async daemon with 4 stage loops (ingest/validate/evaluate/merge) - lib/: config, db, evaluate, validate, merge, breaker, costs, health, log modules - INFRASTRUCTURE.md: comprehensive deep-dive for onboarding - teleo-pipeline.service: systemd unit file Pentagon-Agent: Leo <294C3CA1-0205-4668-82FA-B984D54F48AD>
48 lines
1.5 KiB
Python
48 lines
1.5 KiB
Python
"""Structured JSON logging with rotation."""
|
|
|
|
import json
|
|
import logging
|
|
import logging.handlers
|
|
from datetime import datetime, timezone
|
|
|
|
from . import config
|
|
|
|
|
|
class JSONFormatter(logging.Formatter):
|
|
"""Format log records as JSON lines."""
|
|
|
|
def format(self, record):
|
|
entry = {
|
|
"ts": datetime.now(timezone.utc).isoformat(),
|
|
"level": record.levelname,
|
|
"logger": record.name,
|
|
"msg": record.getMessage(),
|
|
}
|
|
if record.exc_info and record.exc_info[0]:
|
|
entry["exception"] = self.formatException(record.exc_info)
|
|
# Include extra fields if present
|
|
for key in ("stage", "source", "pr", "model", "cost", "event"):
|
|
if hasattr(record, key):
|
|
entry[key] = getattr(record, key)
|
|
return json.dumps(entry)
|
|
|
|
|
|
def setup_logging():
|
|
"""Configure structured JSON logging with rotation."""
|
|
config.LOG_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
handler = logging.handlers.RotatingFileHandler(
|
|
str(config.LOG_FILE),
|
|
maxBytes=config.LOG_ROTATION_MAX_BYTES,
|
|
backupCount=config.LOG_ROTATION_BACKUP_COUNT,
|
|
)
|
|
handler.setFormatter(JSONFormatter())
|
|
|
|
# Also log to stderr for systemd journal
|
|
console = logging.StreamHandler()
|
|
console.setFormatter(logging.Formatter("%(name)s [%(levelname)s] %(message)s"))
|
|
|
|
root = logging.getLogger()
|
|
root.setLevel(logging.INFO)
|
|
root.addHandler(handler)
|
|
root.addHandler(console)
|