| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- """Publish agent run logs: HTML visualize → OSS upload → MySQL record."""
- from __future__ import annotations
- import logging
- from pathlib import Path
- from typing import TYPE_CHECKING
- from supply_agent.logging.logger import slugify_agent_name
- from supply_agent.logging.visualize import generate_visualization
- from supply_infra.config import get_infra_settings
- from supply_infra.db.repositories.oss_log_repo import OssLogRepository
- from supply_infra.db.session import get_session
- from supply_infra.oss.client import OssClient
- if TYPE_CHECKING:
- from supply_agent.logging.logger import AgentLogger
- _log = logging.getLogger("supply_infra.agent_logging.publish")
- def publish_run_artifacts_to_oss(agent_logger: AgentLogger) -> str | None:
- """
- After a run finishes: generate HTML, upload .log/.jsonl/.html to OSS,
- and insert a row into ``oss_logs``.
- Returns the public HTML URL, or None if skipped / failed.
- Failures are logged and do not raise (so agent runs are not broken).
- """
- settings = get_infra_settings()
- if not settings.log_oss_upload_enabled:
- return None
- if not settings.aliyun_oss_access_key_id or not settings.aliyun_oss_access_key_secret:
- _log.debug("OSS credentials missing; skip log publish")
- return None
- log_file = agent_logger.log_file
- jsonl_file = agent_logger.jsonl_file
- if not log_file or not log_file.exists():
- _log.warning("No log file to publish")
- return None
- try:
- source = jsonl_file if jsonl_file and jsonl_file.exists() else log_file
- html_path = generate_visualization(source)
- agent_slug = slugify_agent_name(agent_logger.agent_name) or "agent"
- log_name = html_path.stem
- client = OssClient(settings)
- files = [p for p in (log_file, jsonl_file, html_path) if p and Path(p).exists()]
- html_url: str | None = None
- for path in files:
- key = client.object_key(agent_slug, Path(path).name)
- url = client.upload_file(path, key)
- if Path(path).suffix.lower() == ".html":
- html_url = url
- _log.info("Uploaded %s → %s", path.name, url)
- if not html_url:
- raise RuntimeError("HTML was not uploaded")
- with get_session() as session:
- OssLogRepository(session).create(
- log_name=log_name,
- agent_name=agent_logger.agent_name or agent_slug,
- oss_path=html_url,
- )
- _log.info("oss_logs saved: log_name=%s url=%s", log_name, html_url)
- print(f"[publish] 可视化已上传: {html_url}")
- return html_url
- except Exception:
- _log.exception("Failed to publish run artifacts")
- print("[publish] 日志上传/入库失败,详见日志;不影响本次 Agent 结果")
- return None
|