"""结构化日志:JSON 行日志,含时间、级别、服务、任务 id、事件。 只用标准库 logging。日志绝不写任何密钥、API key、环境变量值: 调用方只传任务 id、状态、事件名这类非敏感字段。 """ import json import logging import sys import time class JsonFormatter(logging.Formatter): """把每条记录格式化成一行 JSON,方便后续按字段过滤聚合。""" def format(self, record): payload = { "ts": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(record.created)), "level": record.levelname, "service": "cloud-control-plane", "logger": record.name, "message": record.getMessage(), } for key in ("task_id", "project_id", "event", "status"): if hasattr(record, key): payload[key] = getattr(record, key) if record.exc_info and record.exc_info[0] is not None: payload["error_type"] = record.exc_info[0].__name__ return json.dumps(payload, ensure_ascii=False) def setup_logging(level=logging.INFO, stream=None): """配置根 logger 为 JSON 行日志;重复调用不重复加 handler。""" handler = logging.StreamHandler(stream or sys.stderr) handler.setFormatter(JsonFormatter()) root = logging.getLogger() root.handlers = [handler] root.setLevel(level) return root def get_logger(name="cloud"): return logging.getLogger(name) def log_event(logger, event, task_id=None, project_id=None, status=None, message=None): """记一条结构化事件日志;message 默认就是事件名。""" logger.info(message or event, extra={ "event": event, "task_id": task_id, "project_id": project_id, "status": status, })