File size: 1,524 Bytes
1607c63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
"""Structured JSON logging for API Contract Validator.

Outputs one JSON object per log record to stdout (visible in docker logs)
and, when writable, to logs/episodes.jsonl for persistent episode history.
"""

import json
import logging
import os
import sys
from datetime import datetime, timezone
from pathlib import Path


class _JsonFormatter(logging.Formatter):
    def format(self, record: logging.LogRecord) -> str:
        payload: dict = {
            "ts": datetime.now(timezone.utc).isoformat(),
            "level": record.levelname,
            "logger": record.name,
            "msg": record.getMessage(),
        }
        if record.exc_info:
            payload["exc"] = self.formatException(record.exc_info)
        return json.dumps(payload)


def configure_logging() -> None:
    """Configure root logger: JSON to stdout + logs/episodes.jsonl."""
    log_level = os.getenv("LOG_LEVEL", "INFO").upper()

    root = logging.getLogger()
    if root.handlers:
        return  # already configured (e.g. during testing)

    root.setLevel(log_level)

    sh = logging.StreamHandler(sys.stdout)
    sh.setFormatter(_JsonFormatter())
    root.addHandler(sh)

    log_dir = Path(os.getenv("LOG_DIR", "logs"))
    try:
        log_dir.mkdir(parents=True, exist_ok=True)
        fh = logging.FileHandler(log_dir / "episodes.jsonl", encoding="utf-8")
        fh.setFormatter(_JsonFormatter())
        root.addHandler(fh)
    except OSError:
        pass  # read-only filesystem (HF Spaces free tier) — stdout only