Skip to content

Adding timestamps to metrics in PutMetricDataRequest results in a MalformedInput exception #27

Closed
@ghost

Description

When constructing a MetricDatum for CloudWatch, it seems that setting the timestamp on any datum in the request will result in errors upon attempting to submit the data to CloudWatch via the CloudWatchClient.PutMetricData(...) function.

It looks like the issue is that the output format generated by the CloudWatchClient does not match the specification here:

https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_PutMetricData.html

The code below generates the following request body:

Action=PutMetricData
&Namespace=MyMetricTest
&MetricData.member.1.MetricName=MyMetricName
&MetricData.member.1.Timestamp=1.44409e+012
&MetricData.member.1.Value=100
&Version=2010-08-01

But according to the specification, it looks like it should actually be generating this request body instead (the timestamp is required to be ISO 8601 formatted):

Action=PutMetricData
&Namespace=MyMetricTest
&MetricData.member.1.MetricName=MyMetricName
&MetricData.member.1.Timestamp=2015-10-05T16:40:00Z
&MetricData.member.1.Value=100
&Version=2010-08-01

Here is a code snippet to fully reproduce the issue:

#include <iostream>

#include "aws/core/auth/AWSCredentialsProvider.h"
#include "aws/monitoring/CloudWatchClient.h"
#include "aws/monitoring/model/PutMetricDataRequest.h"

using namespace Aws;
using namespace Aws::Auth;
using namespace Aws::CloudWatch;
using namespace Aws::CloudWatch::Model;
using namespace Aws::Http;
using namespace Aws::Client;
using namespace std::chrono;

long long GetMillisSinceEpoch(const std::chrono::time_point<std::chrono::system_clock>& timePoint)
{
    return duration_cast<std::chrono::milliseconds>(timePoint.time_since_epoch()).count();
}

long long GetMillisSinceEpoch()
{
    return GetMillisSinceEpoch(system_clock::now());
}

int main()
{
    /*
    This code results in the following output:

    ERROR: MalformedInput::Unable to parse ExceptionName: MalformedInput Message: timestamp must follow ISO8601
    Transmission failure
    */

    const char* accessKey = "MY_ACCESS_KEY";
    const char* secretKey = "MY_SECRET_KEY";

    AWSCredentials basicCreds(accessKey,secretKey);
    CloudWatchClient client = CloudWatchClient(basicCreds);
    PutMetricDataRequest request;
    request.SetNamespace("MyMetricTest");

    MetricDatum datum;
    datum.SetMetricName("MyMetricName");
    datum.SetValue(100.0);

    //This line is the problem!
    //(it's also not clear from the documentation what this "double" value actually represents)
    datum.SetTimestamp(static_cast<double>(GetMillisSinceEpoch())); 

    Aws::Vector<MetricDatum> metrics;
    metrics.push_back(datum);
    request.SetMetricData(metrics);

    char requestDump[4096];
    request.GetBody()->getline(requestDump, 4096);
    std::cout << "REQUEST = " << requestDump << std::endl;

    PutMetricDataOutcome outcome = client.PutMetricData(request);
    if (!outcome.IsSuccess())
    {
        std::cout << "ERROR: " << outcome.GetError().GetExceptionName() << "::" << outcome.GetError().GetMessage() << std::endl;
    }
    std::cout << "Transmission " << (outcome.IsSuccess() ? "success" : "failure") << std::endl;

    char dummy[256];
    std::cin.getline(dummy, 256);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions