poetry‘不是内部或外部命令也不是可运行的程序
2025/12/17 14:55:26
import logging import json class JsonFormatter(logging.Formatter): def format(self, record): log_entry = { "timestamp": self.formatTime(record), "level": record.levelname, "agent": getattr(record, "agent", "unknown"), "message": record.getMessage(), "context": getattr(record, "context", {}) } return json.dumps(log_entry) logger = logging.getLogger("langgraph.agent") handler = logging.StreamHandler() handler.setFormatter(JsonFormatter()) logger.addHandler(handler) logger.setLevel(logging.INFO)上述代码定义了一个 JSON 格式的日志输出器,包含时间戳、Agent 名称、日志级别和上下文信息,适用于容器化环境中的集中日志采集。json-file或fluentd以实现与 ELK 或 Loki 等系统的对接。可在容器启动时指定日志配置:docker run命令指定日志驱动:--log-driver=json-file --log-opt max-size=10m--log-driver=fluentd --log-opt fluentd-address=localhost:24224| 日志驱动 | 适用场景 | 优点 |
|---|---|---|
| json-file | 本地调试与小规模部署 | 默认支持,易于查看 |
| fluentd | 大规模日志聚合 | 高可扩展性,支持过滤与转发 |
/var/lib/docker/containers/<container-id>/<container-id>-json.log。每条日志包含时间戳、流类型(stdout/stderr)及消息内容。{ "log": "Hello from container\n", "stream": "stdout", "time": "2023-04-01T12:00:00.000000000Z" }该格式便于解析,但长期运行可能导致磁盘占用过高。{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }上述配置启用日志轮转,单个文件最大 10MB,最多保留 3 个历史文件,有效防止磁盘溢出。/var/log/containers/<pod_name>_<namespace>_<container>-<hash>.log该文件每行包含日志内容、时间戳和流类型(stdout/stderr),结构如下:{"log":"Hello from app\n","stream":"stdout","time":"2023-10-01T12:00:00.000Z"}[INPUT] Name tail Path /var/log/containers/*.log Parser docker Tag kube.*其中Parser docker解析 JSON 日志并提取结构化字段,Tag用于路由。docker run \ --log-driver=json-file \ --log-opt max-size=10m \ --log-opt max-file=3 \ your-application上述配置表示:单个日志文件最大为 10MB,最多保留 3 个历史文件(即总容量不超过 30MB)。当日志达到上限时,Docker 自动轮转并生成新文件,旧文件被重命名归档。{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }修改后需重启 Docker 服务使配置生效。该方式适用于所有新建容器,提升运维一致性。syslog驱动可将日志直接转发至集中式日志服务器,配置简单且兼容性强。{ "log-driver": "syslog", "log-opts": { "syslog-address": "tcp://192.168.1.100:514", "tag": "app-container" } }该配置将容器日志通过 TCP 发送至远程 syslog 服务器,syslog-address指定接收地址,tag用于标识来源容器,便于后续过滤分析。<match>和<source>定义输入输出规则,实现结构化采集与转发。docker logs <container_id>该命令输出容器的标准输出和标准错误日志。若无输出,需检查应用是否正确启动或日志级别设置过严。--tail 100:仅查看末尾100行,适用于快速定位最新异常;-f:实时跟踪日志输出,模拟“tail -f”行为;--since 1h:筛选最近一小时日志,缩小时间范围。| 现象 | 可能原因 |
|---|---|
| docker logs 无输出 | 应用未启动、日志重定向至文件 |
| 日志不完整 | 日志驱动限制、缓冲区溢出 |
import logging from langgraph.agent import AgentExecutor logging.basicConfig(level=logging.DEBUG) agent = AgentExecutor(graph, log_level="DEBUG") result = agent.invoke({"input": "查询用户订单"})上述代码开启 DEBUG 级别日志后,LangGraph 会在每个节点执行前后输出结构化日志,包括当前状态、调用的工具及其返回值。import logging.config LOGGING_CONFIG = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s' }, }, 'handlers': { 'default': { 'level': 'INFO', 'formatter': 'standard', 'class': 'logging.StreamHandler', }, 'file': { 'level': 'DEBUG', 'formatter': 'standard', 'class': 'logging.FileHandler', 'filename': 'agent.log', }, }, 'loggers': { 'agent.core': { 'handlers': ['default', 'file'], 'level': 'DEBUG', 'propagate': False } } } logging.config.dictConfig(LOGGING_CONFIG)上述配置中,`version` 表示配置格式版本;`formatters` 定义日志输出格式,包含时间、级别、模块名和消息;`handlers` 设置多个输出目标,如控制台和文件;`loggers` 针对不同模块设置独立日志策略,避免全局污染。agent.network、agent.task),实现精细化控制propagate,防止日志重复输出FileHandler结合RotatingFileHandler防止日志文件过大context.Context显式传递日志元数据:ctx := context.WithValue(context.Background(), "trace_id", "abc123") go func(ctx context.Context) { log.Printf("trace_id=%s", ctx.Value("trace_id")) }(ctx)该代码确保子协程继承父上下文中的 trace_id,避免日志碎片化。关键在于所有异步分支都必须接收并使用原始上下文。RUN mkdir -p创建专用日志路径,并通过chown分配非 root 用户权限,避免运行时权限拒绝。RUN mkdir -p /var/log/app && \ chown -R appuser:appgroup /var/log/app && \ chmod -R 755 /var/log/app上述指令创建了/var/log/app目录,分配给应用专用用户组,保证容器以最小权限运行,符合安全最佳实践。/var/log下的子目录,便于统一管理root用户直接写入日志文件VOLUME声明挂载点,支持外部持久化export LANGGRAPH_LOG_LEVEL=DEBUG python app.py上述命令将 LangGraph 的日志级别设为 DEBUG,输出详细的执行轨迹,适用于问题排查。logging模块实现,启动时读取环境变量并映射至对应日志等级,实现零侵入式配置管理。[program:myapp] command=/usr/bin/python app.py numprocs=4 stdout_logfile=/var/log/supervisor/myapp.log stderr_logfile=/var/log/supervisor/myapp_error.log loglevel=info上述配置中,numprocs=4启动四个进程实例,所有进程的 stdout 和 stderr 被重定向至同一文件,便于集中查看。使用loglevel控制日志详细程度,提升运维效率。logrotate工具可避免日志文件无限增长:# 示例:LangGraph 调试中间件 def audit_middleware(node_func): def wrapper(state): logging.info(f"Executing {node_func.__name__}, trace_id={state['trace_id']}") result = node_func(state) logging.info(f"Output: {mask_pii(result)}") return result return wrapper该中间件封装节点逻辑,自动输出结构化日志,并集成脱敏函数,确保审计信息安全可用。// 示例:gRPC 客户端连接池优化 conn, err := grpc.Dial( "service-payment.default.svc.cluster.local", grpc.WithTimeout(500*time.Millisecond), grpc.WithKeepaliveParams(keepalive.ClientParameters{ Time: 30 * time.Second, Timeout: 10 * time.Second, PermitWithoutStream: true, }), ) if err != nil { log.Fatal("failed to connect: ", err) }| 技术方向 | 当前成熟度 | 典型应用场景 |
|---|---|---|
| Serverless Kubernetes | 生产可用 | CI/CD 构建节点弹性伸缩 |
| AI 驱动的 APM | 早期采用 | 异常根因自动定位 |
| 零信任网络代理 | 快速发展 | 跨组织服务调用鉴权 |
架构演进路径图
单体 → 微服务 → 服务网格 → 函数化 + WASM 沙箱
安全模型:边界防御 → 零信任 → 属性基访问控制(ABAC)