【问题标题】:"event" argument in exports.handler of nodejs lambda function triggered by cloudwatch logcloudwatch日志触发的nodejs lambda函数的exports.handler中的“event”参数
【发布时间】:2017-09-25 18:53:08
【问题描述】:

我有一个用 NodeJS 编写的 AWS Lambda 函数,它由 CloudWatch 订阅过滤器触发。有人告诉我,Lambda 函数中的exports.handler 的“事件”参数是我用来获取日志数据的。

当我打印时,我看到了以下内容,这与我在实际 CloudWatch 控制台中看到的人类可读数据完全不同。这是什么意思?!?这是我得到的:

{ awslogs: { data: 'H4sIAAAAAAAAAKWS207jMBRFf8XyMwFfYztvURpQpFIqEmYeUIV8S4nUJlXizggh/p3D7Qt4Xfvs47O3/IqPcVnsPnYvp4gLvCq78um2btvypsYXePo/xhmwNlQSKZk0QgE+TPubeTqfQCn/ts2U1tN++eJtmqM9guBD0JzF2CuleiWJ9rLvuZfWyyAAM0u4NULaGIxw1hjgOvggeueYYBHWLWe3+Hk4pWEar4dDivOCi0e8tkcX7NdDTzaEahrH6D+Gumnl7BLx7vOU+l8c04fjFQ8BLuJcaqm1ZkTo3EAUKSUEy3NNieQiJ1wzRSEpBQa61oRSQjRckgaoKdkjJIYiciI4p4Lk/OKnPljPCFUZMRljiNCC0UKKSxhB3X1Z1c2qyF2vvPU00yr6zFCjMglhM+cFM8oCpRRt75tN1WzLNRh+2yB6bDbXdzuE6j/1piu2Z3cYlufPVlB3t22qTXlbF80YhnhFOKnkSvCrdkgRfX+AH0szojbZdF4K1D5UFYj4bff2DvK/Lnc7AgAA' } }

根据下面的链接,这个数据没有错: http://docs.aws.amazon.com/lambda/latest/dg/eventsources.html#eventsources-cloudwatch-logs

根据 StackOverflow 中的这个答案,这是数据也没有错: KeyError: 'awslogs' ... outEvent = str(event['awslogs']['data']) - Python

非常感谢您的任何帮助!

【问题讨论】:

    标签: node.js amazon-web-services aws-lambda amazon-cloudwatch


    【解决方案1】:

    您准确找到了Amazon CloudWatch Logs Sample Event。因此,基于此,您的 event 对象的结构类似于:

    {
      "awslogs": {
        "data": "H4sIAAAAAAAAAHWPwQqCQBCGX0Xm7EFtK+smZBEUgXoLCdMhFtKV3akI8d0bLYmibvPPN3wz00CJxmQnTO41whwWQRIctmEcB6sQbFC3CjW3XW8kxpOpP+OC22d1Wml1qZkQGtoMsScxaczKN3plG8zlaHIta5KqWsozoTYw3/djzwhpLwivWFGHGpAFe7DL68JlBUk+l7KSN7tCOEJ4M3/qOI49vMHj+zCKdlFqLaU2ZHV2a4Ct/an0/ivdX8oYc1UVX860fQDQiMdxRQEAAA=="
      }
    }
    

    这是什么?

    让我们打开它以更好地了解这里发生了什么。在这种情况下,event.awslogs.data 将具有以下值:

    "H4sIAAAAAAAAAHWPwQqCQBCGX0Xm7EFtK+smZBEUgXoLCdMhFtKV3akI8d0bLYmibvPPN3wz00CJxmQnTO41whwWQRIctmEcB6sQbFC3CjW3XW8kxpOpP+OC22d1Wml1qZkQGtoMsScxaczKN3plG8zlaHIta5KqWsozoTYw3/djzwhpLwivWFGHGpAFe7DL68JlBUk+l7KSN7tCOEJ4M3/qOI49vMHj+zCKdlFqLaU2ZHV2a4Ct/an0/ivdX8oYc1UVX860fQDQiMdxRQEAAA=="
    

    这个值实际上是一个 GZIPPED 负载的 Base64 编码字符串。这样做是为了压缩有效负载,并使其保持较小,同时允许它以 JSON 格式传输。

    如果我们对它进行 Base64 解码,然后解压缩,我们最终会得到以下值:

    {
      "messageType": "DATA_MESSAGE",
      "owner": "123456789123",
      "logGroup": "testLogGroup",
      "logStream": "testLogStream",
      "subscriptionFilters": [
        "testFilter"
      ],
      "logEvents": [
        {
          "id": "eventId1",
          "timestamp": 1440442987000,
          "message": "[ERROR] First test message"
        },
        {
          "id": "eventId2",
          "timestamp": 1440442987001,
          "message": "[ERROR] Second test message"
        }
      ]
    }
    

    其中的元素如下:

    • messageType:要么是DATA_MESSAGE 要么是CONTROL_MESSAGE,如果我的理解是正确的,CONTROL_MESSAGE 用于检查你的 lambda 的可达性
    • owner:原始日志的 AWS 账户 ID
    • logGroup:原始日志的日志组
    • logStream:原始日志的日志流
    • subscriptionFilter:匹配的订阅过滤器名称
    • logEvents:与您在控制台中看到的内容相关的实际日志

    如何使用它?

    您可以使用 CloudWatches Subscription Filters with AWS Lambda 中的以下示例在 Node.js Lambda 中轻松实现类似的功能:

    var zlib = require('zlib');
    exports.handler = function(input, context) {
        var payload = new Buffer(input.awslogs.data, 'base64');
        zlib.gunzip(payload, function(e, result) {
            if (e) { 
                context.fail(e);
            } else {
                result = JSON.parse(result.toString('ascii'));
                console.log("Event Data:", JSON.stringify(result, null, 2));
                context.succeed();
            }
        });
    };
    

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      这是什么意思?!?

      当您看到仅由字符 [A-Z][a-z][0-9][+/=] 组成的字符串时,这通常表示 Base64 编码。 Base64 允许不支持任意二进制数据的传输...携带任意二进制数据,方法是使用每字节仅传输 6(而不是 8)位的格式重新编码,使用 64(2^6)个符号,所有其中是标准的 ASCII 字符,因此与文本传输兼容。

      为什么数据是二进制的?

      因为它是 gzip 压缩的。 Gzip 是一种压缩算法,在压缩文本方面非常好并且非常快......但是 Gzipping 文本会产生任意二进制数据,因此它不能在 JSON 中序列化,它只支持文本(以及数字和真/假/空) .

      因此,gzip 压缩的数据以 base64 编码,以便在 JSON 中传输。

      您需要将 base64 表示转换为二进制,然后 g-un-zip。

      来自http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#LambdaFunctionExample的示例:

      var zlib = require('zlib');
      exports.handler = function(input, context) {
          var payload = new Buffer(input.awslogs.data, 'base64'); // decode base64 to binary
          zlib.gunzip(payload, function(e, result) { // gunzip the binary data
              if (e) { 
                  context.fail(e);
              } else {
                  result = JSON.parse(result.toString('ascii'));
                  console.log("Event Data:", JSON.stringify(result, null, 2));
                  context.succeed();
              }
          });
      };
      

      请注意,这使用旧的context.fail()context.succeed() 约定,显然仍支持向后兼容,但不应在新代码中使用。见http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-using-old-runtime.html#nodejs-prog-model-oldruntime-context-methods

      【讨论】:

        猜你喜欢
        • 2017-06-19
        • 2020-06-25
        • 2018-12-12
        • 1970-01-01
        • 1970-01-01
        • 2020-02-17
        • 2018-11-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多