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

如何阻止Python AWS Lambda记录未处理异常且保留FunctionError属性

如何阻止Python 3.8 AWS Lambda记录未处理的异常?

我们有一个仅支持直接调用的Python 3.8 AWS Lambda函数,并非通过API Gateway或其他AWS服务触发。我们已配置自定义日志系统,可将日志格式化为第三方服务能解析的规范格式。

简化示例代码

custom_logging.py

import json
import logging
from contextlib import contextmanager
from typing import Generator, List

metadata_stack: List[dict] = [{}]

@contextmanager
def add_metadata(metadata: dict) -> Generator[None, None, None]:
    metadata_stack.append({ **metadata_stack[-1], **metadata})
    yield
    metadata_stack.pop()

class CustomFormatter(logging.Formatter):
    def formatMessage(self, record: logging.LogRecord) -> str:
        record.message = json.dumps(
            {
                'status': record.levelname,
                'message': record.message,
                'metadata': metadata_stack[-1],
            },
            separators=(',',':'),
            default=str,
        )
        return super().formatMessage(record)

def _init_root_logger():
    logger = logging.root
    logger.setLevel(logging.DEBUG)
    if logger.hasHandlers():
        handler = logger.handlers[0]
        class_name = handler.__class__.__name__
        if (class_name == 'LambdaLoggerHandler'):
            handler.setFormatter(CustomFormatter())
            logger.info('Identified AWS Lambda logger')
        else:
            logger.info('Unidentified logger handler: ' + class_name)
    else:
        logger.info('Identified no logger. Assuming logging to console.')        

_init_root_logger()

lambda-handler.py

import logging
import custom_logging

class LambdaHandler:
    def __init__(self, logger):
        self.logger = logger

    def handle(self, event, context):
        with custom_logging.add_metadata({ 'foo': 'bar' }):
            try:
                self.logger.info('Lambda initialised.')
                self.main()
            except:
                self.logger.exception('An error occurred.')
                raise
    
    def main(self):
        raise ValueError('I have no values.')

def handle(event, context):
    logger = logging.getLogger('LambdaHandler')
    return LambdaHandler(logger).handle(event, context)

执行测试

当Lambda发生异常时,我们希望它执行失败。测试时通过CLI执行以下命令:

aws lambda invoke --function-name mylambda response.json &&
cat response.json | jq .

调用响应(第一条命令的输出):

{
    "StatusCode": 200,
    "FunctionError": "Unhandled",
    "ExecutedVersion": "$LATEST"
}

返回的负载(第二条命令的输出):

{
  "errorMessage": "I have no values.",
  "errorType": "ValueError",
  "requestId": "526834fc-4bf8-4b39-b695-6c0525aecead",
  "stackTrace": [
    "  File \"/var/task/lambda_handler.py\", line 22, in handle\n    return LambdaHandler(logger).handle(event, context)\n",
    "  File \"/var/task/lambda_handler.py\", line 12, in handle\n    self.main()\n",
    "  File \"/var/task/lambda_handler.py\", line 18, in main\n    raise ValueError('I have no values.')\n"
  ]
}

整体表现符合预期,但Python崩溃时,AWS会使用默认日志记录器(推测是stderr)记录该异常,而非我们的自定义日志记录器,这会干扰与第三方日志聚合服务的集成。

日志内容

执行后生成的日志如下:

INIT_START Runtime Version: python:3.9.v23  Runtime Version ARN: arn:aws:lambda:ap-southeast-2::runtime:bf3c2cf12ad277455c3732549ac6b43321b08f1eb445e825bd941721e0415621
{
    "status": "INFO",
    "message": "Identified AWS Lambda logger",
    "metadata": {}
}
START RequestId: 526834fc-4bf8-4b39-b695-6c0525aecead Version: $LATEST
{
    "status": "INFO",
    "message": "Lambda initialised.",
    "metadata": {
        "foo": "bar"
    }
}

以下日志需优化以将异常纳入JSON格式,此问题将另行处理,暂未干扰集成:

{
    "status": "ERROR",
    "message": "An error occurred.",
    "metadata": {
        "foo": "bar"
    }
}

Traceback (most recent call last):
  File "/var/task/lambda_handler.py", line 12, in handle
    self.main()
  File "/var/task/lambda_handler.py", line 18, in main
    raise ValueError('I have no values.')
ValueError: I have no values.

我们需要移除以下由AWS的bootstrap.py生成的日志:

[ERROR] ValueError: I have no values.
Traceback (most recent call last):
  File "/var/task/lambda_handler.py", line 22, in handle
    return LambdaHandler(logger).handle(event, context)
  File "/var/task/lambda_handler.py", line 12, in handle
    self.main()
  File "/var/task/lambda_handler.py", line 18, in main
    raise ValueError('I have no values.')
END RequestId: 526834fc-4bf8-4b39-b695-6c0525aecead

已尝试的解决方案

我们尝试用try/except包裹整个Lambda函数并显式记录日志,但这会导致客户端响应中丢失"FunctionError": "Unhandled"字段。返回包含"statusCode": 500的负载也无济于事,只会将其作为普通返回负载。

响应内容:

{
  "StatusCode": 200,
  "ExecutedVersion": "$LATEST"
}

负载内容:

{
  "statusCode": 500
}

这会破坏AWS SDK和Step Functions状态机的原生行为。

如何在保留"FunctionError"属性的同时,避免触发自动错误日志?


内容的提问来源于stack exchange,提问作者Hand-E-Food

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 08:48:10