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

AWS CDK自定义资源触发Lambda改日志保留期报错求助

问题:CloudFormation自定义资源Lambda报错index.onEvent is undefined or not exported及日志查看问题

我需要修改/aws/codebuild/路径下CloudFormation日志的保留期来节约成本,已基于AWS Custom Resource做测试和调研,希望在onCreate、onUpdate、onDelete事件中触发Lambda脚本。但调试时出现问题:运行函数后收到错误提示:

Received response status [FAILED] from custom resource. Message returned: index.onEvent is undefined or not exported

且函数回滚后无法查看更多日志,现需相关解决指引。

相关代码

Custom-resource.ts

import * as cdk from "@aws-cdk/core";
import * as cr from "@aws-cdk/custom-resources";
import * as lambda from "@aws-cdk/aws-lambda";
import * as path from "path";

export class CfCustomResource extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: CfStackProps) {
    super(scope, id, props);
    const retention = new lambda.Function(this, "OnEventFunction", {
      memorySize: 512,
      timeout: cdk.Duration.seconds(120),
      runtime: lambda.Runtime.NODEJS_14_X,
      handler: "onEvent", 
      code: lambda.Code.fromAsset(path.join(__dirname, 'set_retention_policy'))
    });


      const getParameter = new cr.AwsCustomResource(this, 'updateRetentionPeriod', {
        onCreate: 
        { 
          service: 'Lambda',
          action: 'invoke',
          parameters: {
            FunctionName: retention.functionName
          },
          physicalResourceId: cr.PhysicalResourceId.of(Date.now().toString()),
        },
        policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
          resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
        }),
      });
    console.log(getParameter); 
  }
}

index.ts(onEvent处理器)

import { CloudFormationCustomResourceEvent, CloudFormationCustomResourceDeleteEvent, CloudFormationCustomResourceUpdateEvent, CloudFormationCustomResourceCreateEvent } from "aws-lambda";

interface Response {
  PhysicalResourceId: string
}

export function onEvent(
  event: CloudFormationCustomResourceEvent,
): string {
  console.log("Event 👉", event);
  let response: Response;
  switch (event.RequestType){
    case "Create":
      response = onCreate(event);
      break;
    case "Delete":
      response = onDelete(event);
      break;
    case "Update":
      response = onUpdate(event);
      break;
    default:
      throw new Error("Unknown Request Type of CloudFormation");
  }
  console.log("Return value:", JSON.stringify(response))
  return JSON.stringify(response);
}

function onCreate(event: CloudFormationCustomResourceCreateEvent) : Response {
  console.log("We are in the Create Event");
  updateRetention();
  return {
    PhysicalResourceId: "abcdef-" + event.RequestId
  }
}

function onDelete(event: CloudFormationCustomResourceDeleteEvent) : Response {
  console.log("We are in the Delete Event");
  return {
    PhysicalResourceId: event.PhysicalResourceId || ""
  }
}

function onUpdate(event: CloudFormationCustomResourceUpdateEvent) : Response {
  console.log("We are in the Update Event");
  return {
    PhysicalResourceId: event.PhysicalResourceId || ""
  }
}

解决指引

1. 修正Lambda Handler配置

Lambda的handler格式必须为文件名.导出函数名,当前配置的"onEvent"缺少文件名前缀。修改Custom-resource.ts中的Lambda配置:

handler: "index.onEvent", // 替换原有的"onEvent"

2. 调整自定义资源返回值格式

CloudFormation要求自定义资源的Lambda返回JSON对象,而非JSON字符串。修改index.ts中的onEvent函数:

export function onEvent(
  event: CloudFormationCustomResourceEvent,
): Response { // 将返回类型从string改为Response
  console.log("Event 👉", event);
  let response: Response;
  switch (event.RequestType){
    case "Create":
      response = onCreate(event);
      break;
    case "Delete":
      response = onDelete(event);
      break;
    case "Update":
      response = onUpdate(event);
      break;
    default:
      throw new Error("Unknown Request Type of CloudFormation");
  }
  console.log("Return value:", JSON.stringify(response))
  return response; // 直接返回Response对象,而非字符串化结果
}

3. 解决回滚后日志丢失问题

  • 提前配置日志组保留策略:在Custom-resource.ts中为Lambda的日志组添加保留和不删除策略,确保回滚后日志依然存在:
    import * as logs from "@aws-cdk/aws-logs";
    
    // 创建Lambda函数后添加以下代码
    new logs.LogGroup(this, "RetentionFunctionLogGroup", {
      logGroupName: `/aws/lambda/${retention.functionName}`,
      retention: logs.RetentionDays.THIRTY_DAYS, // 根据需求设置保留天数
      removalPolicy: cdk.RemovalPolicy.RETAIN, // 栈删除/回滚时保留日志组
    });
    
  • 通过CloudFormation事件追踪日志:在CloudFormation控制台的栈事件中,找到失败的自定义资源事件,复制其物理资源ID(或请求ID),然后到CloudWatch日志中搜索该ID,定位相关日志记录。

4. 优化自定义资源调用方式

当前用AwsCustomResource调用Lambda的方式存在额外层级,建议改用cr.Provider直接关联自定义资源,更符合最佳实践:

// 替换原有的AwsCustomResource代码
const provider = new cr.Provider(this, "RetentionProvider", {
  onEventHandler: retention,
});

new cdk.CustomResource(this, "UpdateRetention", {
  serviceToken: provider.serviceToken,
  properties: {
    // 可传递自定义参数,比如日志前缀、保留天数
    LogPrefix: "/aws/codebuild/",
    RetentionDays: 30,
  },
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 15:40:50