为AWS Lambda指定日志组?

90

有没有一种方法可以指定AWS Lambda记录日志的CloudWatch日志组?看起来日志组是直接从Lambda名称生成的,但是,例如将多个Lambda聚合到一个日志组中将特别方便。我们特别希望在CloudFormation模板创建Lambda时指定日志组。


4
请求在AWS::Lambda::Function中添加LogGroup属性:https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/147 - Pat Myron
7个回答

44

实际上,你至少可以在某种程度上做到。我也在寻找答案并尝试了一下。这里是两个资源的片段:lambda函数和日志组:

"MyLambdaFunction": {
    "Type": "AWS::Lambda::Function",
    "DependsOn": "ReadWriteRole",
    "Properties": {
        //snip
    }
},

"MyLambdaFunctionLogGroup": {
    "Type": "AWS::Logs::LogGroup",
    "DependsOn": "MyLambdaFunction",
    "Properties": {
        "LogGroupName": {"Fn::Join": ["", ["/aws/lambda/", {"Ref": "MyLambdaFunction"}]]},
        "RetentionInDays": 14
    }
},

我发现日志组是按照指示保留14天创建的。当Lambda函数运行时,它确实在该组中创建了日志流。但是,当我删除堆栈时,似乎日志组没有被删除,并且保留期设置为永不过期。也许这已足够,以避免流变得太混乱...


4
我对这个答案非常乐观,但遇到了LogGroup失败的问题,因为LogGroupName已经存在。 - Purefan
5
您可以删除DependsOn,因为我们在组名中使用了Lambda的ARN,所以它是隐式的。 - Manish Kasera
3
当我更新一个栈时,也遇到了相同的问题。我通过删除整个栈并重新创建解决了这个问题。 - rui
3
这个回答没有回答所问的问题。 - Leon
5
首先必须创建日志组。Lambda 函数必须依赖于该日志组。 - Felipe Alvarez
显示剩余9条评论

32

我认为这不可能。

即使它可能的,每个AWS Lambda实例仍将写入其自己的日志流。虽然同一Lambda的不同调用可以写入相同的日志流(当重复使用Lambda实例时),但不同的Lambda肯定不能这样做(因为它们必须使用不同的Lambda实例)。

因此,您必须拥有一个聚合多个日志流的工具。如果是这样,那么将它变得更加通用,让它能够聚合来自不同日志组的日志流,会有什么问题呢?


4
您是正确的。我向AWS支持团队询问了同样的问题,得到的答复是不可能实现,并且也许永远不会实现。然而,Lambda函数的多个实例无法记录到同一日志流的原因是因为有每秒5个请求/日志流的限制。因此,即使您尝试从多个Lambda实例手动写入单个日志流,您很快就会遇到这个限制。 - idbehold
遗憾的是,没有办法为单个Lambda函数指定日志组。像这样的工具(https://github.com/TylerBrock/saw),它可以从特定的日志组中流式传输聚合的多个日志流,将无法从中受益。 - onelaview
1
这个回答没有解决问题...抱歉,忍不住要说。但是说真的,如果你看一下最初的问题,这更关注于最后的用例而不是实际的问题,依我之见。 - Craig Brett
@CraigBrett 所问问题的答案在第一句话中。答案的实质是不能进行任何详细阐述的(也无法通过链接到文档提供证明,因为不支持的功能通常会在文档中被省略,这样的事实只在特殊情况下才会明确说明)。其余的答案是一些额外的想法,使其符合 SO 答案的标准(否则它将作为评论编写,并且无法接受)。 - Leon
@Leon,也许我有点儿开玩笑,因为你对其他人的答案不屑一顾。我很抱歉。但是当我遇到这个问题时,那些答案实际上对我有用。虽然不完全是日志聚合的附加功能,但至少想要一个经过CloudFormation处理的日志组,并保留日志。所以这是可能的。 - Craig Brett
1
@CraigBrett 如果有人来到这个页面的目的是为他们的AWS Lambda指定一个日志组,他们会发现他们最多只能指定一个与默认生成的日志组没有区别的日志组。因此,其他两个答案虽然在与OP问题无关的其他方面很有用,但并没有回答所提出的问题。因此,我的评论。我认为更适合发布一个新问题,重点关注日志保留(可能链接到这个问题),然后自己回答这个非常不同的问题。 - Leon

22

我发现@lingrlongr的回答部分正确。

首先,回答原问题,您无法为Lambda函数指定自定义日志组名称以进行写入。

Lambda日志组名称始终遵循此模式:

/aws/lambda/<function-name>

这个lambda函数首先会检查是否存在一个同名的日志组。

  • 如果存在,它会使用那个日志组。
  • 如果不存在,它会创建一个该名称的日志组。

因此,如果你想要添加设置,例如RetentionInDaysSubscriptionFilter,请确保你的CloudFormation或SAM模板在lambda函数之前创建LogGroup。如果先创建lambda函数,则在创建LogGroup时会抛出错误,显示LogGroup已经存在。因此,lambda函数应该有DependsOn: LogGroup而不是相反。

此外,请确保你没有在LogGroup内部使用RefGetAtt引用lambda函数,因为这会导致lambda函数被隐含地依赖,从而在LogGroup之前创建lambda函数。


9

按照答案中提到的方式创建日志组是可行的。如果要在删除堆栈后保留保留策略,只需添加 DeletionPolicy。

"MyLambdaFunctionLogGroup": {
  "Type": "AWS::Logs::LogGroup",
  "DependsOn": "MyLambdaFunction",
  "DeletionPolicy": "Retain",
  "Properties": {
    "LogGroupName": {"Fn::Join": ["", ["/aws/lambda/", {"Ref": "MyLambdaFunction"}]]},
    "RetentionInDays": 14
  }
}

2
这个回答并没有解决所提出的问题。 - Leon
Lambda应该依赖于日志组。必须先创建日志组。 - Felipe Alvarez

5

好的,我必须亲自操作,@pat-myron在回答下方发布了一条链接,介绍了如何进行操作。

他发布了一个功能请求,在这里,@benbridts概述了模板。

以下是在我的CloudFormation模板中运行的要点:

HelloWorldLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: "/aws/lambda/HelloWorld"
      RetentionInDays: 30

HelloWorldFunction:
  Type: AWS::Lambda::Function
  DependsOn: HelloWorldLogGroup
  Properties:
    FunctionName: HelloWorld
    Role:
      Fn::GetAtt:
        - LambdaExecRole
        - Arn

LambdaExecRole:
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument:
      Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
    Policies:
      - PolicyName: LambdaLogging
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Action:
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource: !GetAtt HelloWorldLogGroup.Arn

5
我已经将LogGroup附加到SAM模板中的Serverless函数,如下所示:
    MyFuncLogGroup:
        Type: AWS::Logs::LogGroup
        Properties:
            LogGroupName: '/aws/lambda/stackName-env-myFunc-v1'
            RetentionInDays: 30

    MyFunc:
        Type: AWS::Serverless::Function
        Properties:
            FunctionName: 'stackName-env-myFunc-v1'
            ...

有些用户提到了DependsOn属性的要求,但在我使用SAM时并不需要该属性。唯一的要求是LogGroupName必须为/aws/lambda/<FunctionName>。只要你没有在LogGroup中引用函数的逻辑ID,则SAM会在lambda函数之前创建日志组。

此外,如果您要向现有函数添加LogGroup,只需像上面那样更新template.yaml文件,并在函数资源中添加FunctionName属性即可。显然,FunctionName应与现有lambda函数名称不同,该名称出现在lambda的ARN中。

警告:FunctionName属性需要进行替换。您的现有lambda将被删除并创建新的lambda。


这似乎最初是有效的,但当 Lambda 函数被创建时,保留时间会重置为 3 天。 - davegallant
davegallant,你有CloudWatch的一些全局设置吗?我已经在多个项目中使用了这个配置,并且保留期对所有项目都是持久的。可能是从控制台修改了保留期。 - sziraqui
没有。我通过事后使用awscli命令aws logs put-retention-policy解决了这个问题,虽然不太美观但是有效! - davegallant

0
从2023年11月开始,您现在可以在创建Lambda函数时指定自定义的CloudWatch Logs日志组名称。
在CloudFormation中,对于您的Lambda函数,您可以指定日志组名称,如下所示:
Type: AWS::Lambda::Function
Properties:
  FunctionName: <my function name>
  LoggingConfig:
    ApplicationLogLevel: TRACE
    LogFormat: <optional custom format>
    LogGroup: <custom log group name>
    SystemLogLevel: WARN

请注意,您现在可以指定应用程序日志级别(DEBUG | ERROR | FATAL | INFO | TRACE | WARN)和系统日志级别(DEBUG | INFO | WARN),这是以前无法做到的,还有日志格式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接