You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS Glue Python使用watchtower写入CloudWatch日志丢失问题

问题根因

你写的代码有4个典型的Glue+watchtower适配坑,直接导致日志丢失或者根本没发出去:

  • 权限不匹配:Glue作业绑定的默认IAM角色,仅允许向/aws-glue/python-job日志组下、名称包含当前作业运行ID的日志流写入内容,你硬编码my_stream_name作为流名,会直接被CloudWatch拒绝写入,且watchtower默认不会把自身的SDK报错打印出来,表面看没有任何报错,实际日志根本没发成功。
  • 缓冲机制丢日志:watchtower默认开启异步队列+批量攒包的推送逻辑,要攒够指定大小/等待固定间隔才会把日志发到CloudWatch。Glue Python作业执行速度快,代码跑完进程直接被回收,缓冲区里的日志根本没来得及推送就全丢了。
  • 日志层级冲突:Glue启动时会提前初始化根日志器,你直接getLogger(__name__)拿到的实例继承了根日志器的默认配置,你后加的CloudWatch handler会被传播规则拦截,根本不会触发。另外你直接传dict对象作为日志内容,watchtower默认没有开启JSON序列化,遇到非字符串内容会直接抛序列化错误被吞掉。
  • 区域配置缺失:watchtower初始化boto3客户端时默认读取系统默认区域配置,如果你没有显式指定Glue作业运行的区域,客户端可能连到其他区域的CloudWatch端点,日志自然写到错误的地方,你在当前区域找不到。
修复方案

直接替换成下面的可运行代码,同时做对应配置即可:

import logging
import sys
import watchtower

def initialize_log() -> logging.Logger:
    logger = logging.getLogger(__name__)
    # 清空Glue预初始化的冗余handler,避免冲突
    logger.handlers.clear()
    logger.setLevel(logging.INFO)
    # 关闭日志向上层传播,防止重复打印/丢日志
    logger.propagate = False

    log_format = "[%(name)s] %(asctime)s %(levelname)-8s %(message)s"
    date_format = "%a, %d %b %Y %H:%M:%S %Z"
    formatter = logging.Formatter(log_format, datefmt=date_format)

    # 标准输出handler,保证Glue作业运行控制台能实时看到日志
    stream_handler = logging.StreamHandler(sys.stdout)
    stream_handler.setFormatter(formatter)
    logger.addHandler(stream_handler)

    # 初始化CloudWatch日志handler
    try:
        # 从Glue启动参数里拿当前作业运行ID,拼到日志流名里,适配默认权限规则
        job_run_id = ""
        if "--JOB_RUN_ID" in sys.argv:
            job_run_id = sys.argv[sys.argv.index("--JOB_RUN_ID") + 1]
        stream_name = f"custom_log_{job_run_id}" if job_run_id else "local_test"

        cw_handler = watchtower.CloudWatchLogHandler(
            log_group='/aws-glue/python-job',
            stream_name=stream_name,
            use_queues=False, # 关闭异步队列,打一条推一条,实现实时推送同时避免进程退出丢日志
            create_log_group=False, # 复用Glue已经创建好的默认日志组,避免建组权限报错
            boto3_client_kwargs={"region_name": "ap-east-1"} # 替换成你自己Glue作业部署的区域
        )
        cw_handler.setFormatter(formatter)
        logger.addHandler(cw_handler)
    except Exception as e:
        logger.warning(f"CloudWatch日志组件初始化失败,仅输出到控制台: {str(e)}")

    return logger

def log(logger, message):
    logger.info(message)
    # 字典转字符串再打印,避免序列化报错
    logger.info(str(dict(foo="bar", details={})))

必须做的前置配置

  • 检查Glue作业绑定的IAM角色权限,确保包含logs:CreateLogStream、logs:PutLogEvents两个权限,资源范围配置为arn:aws-cn:logs:*:*:log-group:/aws-glue/python-job:*(如果是海外区把aws-cn改成aws即可)。
  • 安装适配版本的依赖:在Glue作业的--additional-python-modules参数里指定watchtower==2.0.1,不要用3.x以上的新版本,Glue内置的boto3版本偏旧,新版watchtower会有兼容问题。
  • 查日志的时候选对Glue运行的区域,日志流找名称带对应作业运行ID、前缀是custom_log_的即可,CloudWatch日志入库有10秒左右的延迟,作业刚跑完等一会再搜。

内容的提问来源于stack exchange,提问作者HouKaide

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 13:30:54