from __future__ import annotations import contextlib import json import os import sys import time import uuid from dataclasses import dataclass from typing import Any, Dict, Iterator REDACTIONS = [ ("OMNICRON_TOKEN", "***REDACTED***"), ] def _redact_env(data: Dict[str, Any]) -> Dict[str, Any]: out = dict(data) token = os.getenv("OMNICRON_TOKEN") if token: for k, v in list(out.items()): if isinstance(v, str) and token in v: out[k] = v.replace(token, "***REDACTED***") return out def _emit(payload: Dict[str, Any]) -> None: # Structured JSON log to stdout; redacts token in values payload = _redact_env(payload) try: sys.stdout.write(json.dumps(payload, ensure_ascii=False) + "\n") sys.stdout.flush() except Exception: # Avoid breaking callers on logging failures pass @contextlib.contextmanager def task(name: str, **fields: Any) -> Iterator[None]: run_id = str(uuid.uuid4()) start = time.time() _emit({ "ts": time.time(), "type": "task_start", "task": name, "run_id": run_id, **fields, }) try: yield status = "ok" err = None except Exception as exc: # pragma: no cover status = "error" err = { "type": exc.__class__.__name__, "msg": str(exc), } raise finally: _emit({ "ts": time.time(), "type": "task_end", "task": name, "run_id": run_id, "status": status, "err": err, "elapsed_s": round(time.time() - start, 6), **fields, }) def log(event: str, **fields: Any) -> None: _emit({ "ts": time.time(), "type": "event", "event": event, **fields, }) def notify(level: str, message: str, **ctx: Any) -> None: _emit({ "ts": time.time(), "type": "notify", "level": level, "message": message, **ctx, }) @dataclass class _Artifact: def put(self, path: str, name: str) -> None: # no-op shim log("artifact_put", path=path, name=name, provider="shim") def get(self, name: str, dest: str) -> None: # no-op shim log("artifact_get", name=name, dest=dest, provider="shim") artifact = _Artifact()