由cloudwatch日志触发的nodejs lambda函数的exports.handler中的“event”参数

时间:2017-09-22 02:19:28

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

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

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

"models"

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

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

非常感谢您提供任何帮助!

2 个答案:

答案 0 :(得分: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"
    }
  ]
}

以下内容如下:

  • messageTypeDATA_MESSAGECONTROL_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();
        }
    });
};

希望有所帮助。

答案 1 :(得分:0)

  

这是什么意思?!?

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

为什么数据是二进制的?

因为它被gzipped。 Gzip是一种压缩算法非常好并且在压缩文本方面非常快......但是Gzipping文本生成任意二进制数据,所以它不能用JSON序列化,JSON只支持文本(和数字以及true / false /空)。

因此,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