DataDog / datadog-api-client-python

Python client for the Datadog API

Home Page:https://datadoghq.dev/datadog-api-client-python/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error submitting metrics with async api client

dxmaxwell opened this issue · comments

Describe the bug
When using the Datadog API async client, an error occurs when submitting metrics data:

HTTP response body: Payload is not in the expected format: invalid character 's' looking for beginning of value

Exact same metrics data can be successfully submitted using the non-async client.

To Reproduce
The following code (adapted from the async example in the README) will reproduce the error:

from datadog_api_client.v1 import AsyncApiClient, Configuration
from datadog_api_client.v1.api.metrics_api import MetricsApi
from datadog_api_client.v1.model.metrics_payload import MetricsPayload
from datadog_api_client.v1.model.point import Point
from datadog_api_client.v1.model.series import Series

try:
    body = MetricsPayload(
        series=[
            Series(
                metric="system.load.1",
                type="gauge",
                points=[Point([datetime.now().timestamp(), 2.1])],
                tags=["test:ExampleSubmitmetricsreturnsPayloadacceptedresponse"],
            )
        ]
    )

    configuration = Configuration()
    async with AsyncApiClient(configuration) as api_client:
        api_instance = MetricsApi(api_client)
        response = await api_instance.submit_metrics(body=body)
        print(response)

except BaseException as ex:
    logger.exception('Error submitting metrics to datadog: {}', ex)

Error response:

datadog_api_client.v1.exceptions.ApiException: (400)
Reason: Bad
HTTP response headers: HttpHeaders({'Date': 'Fri, 08 Apr 2022 20:26:30 GMT', 'Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '91', 'Connection': 'keep-alive', 'x-content-type-options': 'nosniff', 'strict-transport-security': 'max-age=15724800;', 'content-security-policy': "frame-ancestors 'self'; report-uri https://logs.browser-intake-datadoghq.com/api/v2/logs?dd-api-key=pube4f163c23bbf91c16b8f57f56af9fc58&dd-evp-origin=content-security-policy&ddsource=csp-report&ddtags=site%3Adatadoghq.com", 'x-frame-options': 'SAMEORIGIN'})
HTTP response body: Payload is not in the expected format: invalid character 's' looking for beginning of value

Expected behavior
Request should succeed and metrics data should be available in the DataDog metrics explorer. (Like it is when making the request with the non-async client.)

Screenshots
If applicable, add screenshots to help explain your problem.

Environment and Versions (please complete the following information):
Linux with Python v3.8.10 and datadog-api-client = {extras = ["async"], version = "^1.10.0"}

Additional context
After looking at the differences between the non-async and async API clients, I noticed that it appears the async client never actually serializes the provided body data.

For reference, the non-async client does it here, but I did not see similar code for the async client.

Thanks for the report, reproduced. We're indeed missing the serialization step in the async case. I'll fix it, sorry for the troubles.

My original bug report had a small mistake, for the body I used a plan dictionary, but if I follow the examples for the non-async client I should be sending a MetricsPayload object:

    body = MetricsPayload(
        series=[
            Series(
                metric="system.load.1",
                type="gauge",
                points=[Point([datetime.now().timestamp(), 2.1])],
                tags=["test:ExampleSubmitmetricsreturnsPayloadacceptedresponse"],
            )
        ]
    )

But for some reason the MetricsPayload object is not serializable to json, but I don't understand why since I thought that's what the non-async client is actually doing?

Ok, I found the problem looks like I needed to call body.to_dict() first before serializing to json. That must be done by one of the intermediate layers in the client.