输入对象表单S3上的JSON.parse问题-Node.js

时间:2018-08-26 02:41:06

标签: javascript node.js amazon-s3 aws-lambda

这里的Node newbie,我遇到了一个问题,我已经将自己的头撞了几天,我确定我缺少一些小东西,但到目前为止,我的google也使我失败了。

我有一个AWS Firehose,它将CloudWatch日志写入S3,然后由解析并提取到Elasticsearch中的lambda函数提取。或至少那是计划。我之所以使用Firehose是因为数据来自远程AWS账户并将所有日志发送到一个地方s3。我能够在S3中提取一次日志。默认情况下,云监视日志已压缩,因此firehose只需将文件写入S3即可,无需任何转换。现在的问题:)。从S3读取文件后,我尝试将其发送到函数转换以解析数据,但是在尝试循环通过JSON日志时失败。我做了一个console.log(payload),它似乎是JSON格式,但是通过JSON.stringify运行它来返回解析没有任何作用。 JSON.parse可以使用,但JSON无效。
我附上下面的代码。我不是公司中的原始作者,有人在GitHub上找到它。我刚刚添加了S3部件。 我添加了一个作为日志示例的文件作为示例,如果有人想要抓住它,它位于公共s3存储桶中。不用担心它的所有测试数据没什么特别的。

https://s3.amazonaws.com/node-issue-stackoverflow/cwl-test-11-2018-08-26-00-45-34-84a4c3de-179a-4bf2-9376-895cdc063e6b+(1)

垃圾箱Link

// v1.1.2
var https = require('https');
var zlib = require('zlib');
var crypto = require('crypto');
var AWS = require('aws-sdk');

var endpoint = process.env.es_endpoint;
var s3 = new AWS.S3();
var params;

exports.handler = function(input, context) {
    // Get the event from S3 based on input
    params = {Bucket: input.Records[0].s3.bucket.name, Key: input.Records[0].s3.object.key};
    console.log(input.Records[0].s3);
    s3.getObject(params, function(error, event){
        if (error) { context.fail(error); return; }
        console.log(event);
        console.log(event.Body);
        // decode input from base64
        var zippedInput = new Buffer(event.Body, 'base64');
        // decompress the input
        zlib.gunzip(zippedInput, function(error, buffer) {
            if (error) { context.fail(error); return; }
            // console.log(buffer.toString());
            // parse the input from JSON
            var awslogsData = buffer.toString('utf8');

            // transform the input to Elasticsearch documents
            var elasticsearchBulkData = transform(awslogsData);

            // skip control messages
            if (!elasticsearchBulkData) {
                console.log('Received a control message');
                context.succeed('Control message handled successfully');
                return;
            }

            // post documents to the Amazon Elasticsearch Service
            post(elasticsearchBulkData, function(error, success, statusCode, failedItems) {
                console.log('Response: ' + JSON.stringify({
                    "statusCode": statusCode
                }));

                if (error) {
                    console.log('Error: ' + JSON.stringify(error, null, 2));

                    if (failedItems && failedItems.length > 0) {
                        console.log("Failed Items: " +
                            JSON.stringify(failedItems, null, 2));
                    }

                    context.fail(JSON.stringify(error));
                } else {
                    console.log('Success: ' + JSON.stringify(success));
                    context.succeed('Success');
                }
            });
        });
    });
};

function transform(payload) {
    if (payload.messageType === 'CONTROL_MESSAGE') {
        return null;
    }

    var bulkRequestBody = '';

    payload.logEvents.forEach(function(logEvent) {
        var timestamp = new Date(1 * logEvent.timestamp);

        // index name format: cwl-YYYY.MM.DD
        var indexName = [
            'cwl-' + timestamp.getUTCFullYear(),              // year
            ('0' + (timestamp.getUTCMonth() + 1)).slice(-2),  // month
            ('0' + timestamp.getUTCDate()).slice(-2)          // day
        ].join('.');

        var source = buildSource(logEvent.message, logEvent.extractedFields);
        source['@id'] = logEvent.id;
        source['@timestamp'] = new Date(1 * logEvent.timestamp).toISOString();
        source['@message'] = logEvent.message;
        source['@owner'] = payload.owner;
        source['@log_group'] = payload.logGroup;
        source['@log_stream'] = payload.logStream;

        var action = { "index": {} };
        action.index._index = indexName;
        action.index._type = payload.logGroup;
        action.index._id = logEvent.id;

        bulkRequestBody += [
            JSON.stringify(action),
            JSON.stringify(source),
        ].join('\n') + '\n';
    });
    return bulkRequestBody;
}

function buildSource(message, extractedFields) {
    if (extractedFields) {
        var source = {};

        for (var key in extractedFields) {
            if (extractedFields.hasOwnProperty(key) && extractedFields[key]) {
                var value = extractedFields[key];

                if (isNumeric(value)) {
                    source[key] = 1 * value;
                    continue;
                }

                jsonSubString = extractJson(value);
                if (jsonSubString !== null) {
                    source['$' + key] = JSON.parse(jsonSubString);
                }

                source[key] = value;
            }
        }
        return source;
    }

    jsonSubString = extractJson(message);
    if (jsonSubString !== null) {
        return JSON.parse(jsonSubString);
    }

    return {};
}

function extractJson(message) {
    var jsonStart = message.indexOf('{');
    if (jsonStart < 0) return null;
    var jsonSubString = message.substring(jsonStart);
    return isValidJson(jsonSubString) ? jsonSubString : null;
}

function isValidJson(message) {
    try {
        JSON.parse(message);
    } catch (e) { return false; }
    return true;
}

function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

function post(body, callback) {
    var requestParams = buildRequest(endpoint, body);

    var request = https.request(requestParams, function(response) {
        var responseBody = '';
        response.on('data', function(chunk) {
            responseBody += chunk;
        });
        response.on('end', function() {
            var info = JSON.parse(responseBody);
            var failedItems;
            var success;

            if (response.statusCode >= 200 && response.statusCode < 299) {
                failedItems = info.items.filter(function(x) {
                    return x.index.status >= 300;
                });

                success = {
                    "attemptedItems": info.items.length,
                    "successfulItems": info.items.length - failedItems.length,
                    "failedItems": failedItems.length
                };
            }

            var error = response.statusCode !== 200 || info.errors === true ? {
                "statusCode": response.statusCode,
                "responseBody": responseBody
            } : null;

            callback(error, success, response.statusCode, failedItems);
        });
    }).on('error', function(e) {
        callback(e);
    });
    request.end(requestParams.body);
}

function buildRequest(endpoint, body) {
    var endpointParts = endpoint.match(/^([^\.]+)\.?([^\.]*)\.?([^\.]*)\.amazonaws\.com$/);
    var region = endpointParts[2];
    var service = endpointParts[3];
    var datetime = (new Date()).toISOString().replace(/[:\-]|\.\d{3}/g, '');
    var date = datetime.substr(0, 8);
    var kDate = hmac('AWS4' + process.env.AWS_SECRET_ACCESS_KEY, date);
    var kRegion = hmac(kDate, region);
    var kService = hmac(kRegion, service);
    var kSigning = hmac(kService, 'aws4_request');

    var request = {
        host: endpoint,
        method: 'POST',
        path: '/_bulk',
        body: body,
        headers: {
            'Content-Type': 'application/json',
            'Host': endpoint,
            'Content-Length': Buffer.byteLength(body),
            'X-Amz-Security-Token': process.env.AWS_SESSION_TOKEN,
            'X-Amz-Date': datetime
        }
    };

    var canonicalHeaders = Object.keys(request.headers)
        .sort(function(a, b) { return a.toLowerCase() < b.toLowerCase() ? -1 : 1; })
        .map(function(k) { return k.toLowerCase() + ':' + request.headers[k]; })
        .join('\n');

    var signedHeaders = Object.keys(request.headers)
        .map(function(k) { return k.toLowerCase(); })
        .sort()
        .join(';');

    var canonicalString = [
        request.method,
        request.path, '',
        canonicalHeaders, '',
        signedHeaders,
        hash(request.body, 'hex'),
    ].join('\n');

    var credentialString = [ date, region, service, 'aws4_request' ].join('/');

    var stringToSign = [
        'AWS4-HMAC-SHA256',
        datetime,
        credentialString,
        hash(canonicalString, 'hex')
    ] .join('\n');

    request.headers.Authorization = [
        'AWS4-HMAC-SHA256 Credential=' + process.env.AWS_ACCESS_KEY_ID + '/' + credentialString,
        'SignedHeaders=' + signedHeaders,
        'Signature=' + hmac(kSigning, stringToSign, 'hex')
    ].join(', ');

    return request;
}

function hmac(key, str, encoding) {
    return crypto.createHmac('sha256', key).update(str, 'utf8').digest(encoding);
}

function hash(str, encoding) {
    return crypto.createHash('sha256').update(str, 'utf8').digest(encoding);
}

0 个答案:

没有答案