go-datadog-api icon indicating copy to clipboard operation
go-datadog-api copied to clipboard

GetDashboard Fails Fatal When Scatterplot Exists in Dashboard

Open blaines opened this issue 5 years ago • 5 comments

When a Dashboard in Datadog contains a scatterplot, the resulting API response from GetDashboard cannot be parsed.

Error:

2019/11/01 01:32:13 GetDashboard fatal: json: cannot unmarshal object into Go struct field GraphDefinition.requests of type []datadog.GraphDefinitionRequest

Related code: https://github.com/zorkian/go-datadog-api/blob/master/dashboards.go#L163

Requests []GraphDefinitionRequest `json:"requests,omitempty"`

A scatterplot in the API response looks like the following, note the viz type of scatterplot:

{
    "definition": {
        "yaxis": {
            "scale": "linear",
            "min": "auto",
            "max": "auto",
            "label": "",
            "includeZero": true
        },
        "color_by_groups": [],
        "xaxis": {
            "scale": "log",
            "includeZero": false
        },
        "viz": "scatterplot",
        "requests": {
            "y": {
                "q": "max:example.stat{*} by {example_tag}",
                "aggregator": "max"
            },
            "x": {
                "q": "max:example.stat{*} by {example_tag}",
                "aggregator": "max"
            }
        }
    }
}

As you can see "requests" is no longer a slice, causing deserialization issues.

Unfortunately I can't come up with a backwards compatible way to support scatterplots. Although I'm working on parsing this in a fork with a custom unmarshaler.

blaines avatar Nov 02 '19 00:11 blaines

Here's the functioning change I've come up with thus far.

type GraphDefinition struct {
	...
	RequestsRawMessage  json.RawMessage          `json:"requests,omitempty"`
	Requests            []GraphDefinitionRequest `json:"-"`
	ScatterplotRequests struct {
		Y struct {
			Q          string `json:"q"`
			Aggregator string `json:"aggregator"`
		} `json:"y"`
		X struct {
			Q          string `json:"q"`
			Aggregator string `json:"aggregator"`
		} `json:"x"`
	} `json:"-"`
	...
}

Further below I added a custom unmarshaler for GraphDefinition data:

func (gd *GraphDefinition) UnmarshalJSON(data []byte) error {
	type Alias GraphDefinition
	alias := &struct {
		*Alias
	}{
		Alias: (*Alias)(gd),
	}

	json.Unmarshal(data, &alias)

	if len(alias.RequestsRawMessage) != 0 {
		if *alias.Viz == "scatterplot" {
			err := json.Unmarshal(alias.RequestsRawMessage, &alias.ScatterplotRequests)
			if err != nil {
				panic(err)
			}
		} else {
			err := json.Unmarshal(alias.RequestsRawMessage, &alias.Requests)
			if err != nil {
				panic(err)
			}
		}
	}
	return nil
}

blaines avatar Nov 03 '19 02:11 blaines

I am also having this problem, and an additional problem with GetDashboard the following similar output:

cannot unmarshal string into Go struct field GraphDefinition.dash.graphs.definition.group of type []string

iancullinane avatar Dec 10 '19 21:12 iancullinane

I think that using the custom unmarshaller is a reasonable way to go forward in this issue - I'd accept a PR that implements that.

However, there is another way - using the /api/v1/dashboard API and the related *Board (GetBoard, ...) methods that seem to be handling this case fine. Would that be an option for you?

bkabrda avatar Feb 03 '20 13:02 bkabrda

@bkabrda please double check me, but when I used /api/v1/dashboard the result was not equivalent. I'll see if I can get specific details on that again.

blaines avatar Mar 04 '20 00:03 blaines

Am I missing something /api/v1/dashboard isn't supported yet by this lib? I added my own functionality in a fork.

blaines avatar Mar 05 '20 21:03 blaines