diff --git a/README.md b/README.md index d682618..d2e029e 100644 --- a/README.md +++ b/README.md @@ -80,8 +80,14 @@ The value is provided by the provided variables as seen in the above table. Notice that while `interval_ms` is provided, we do not use it or define it anywhere in our query. One thing to keep in mind for your own queries is the type accepted by the GraphQL server for a given variable. In the case of that specific schema, the type of a `Long` is allowed to be a number or a string. -If your specific schema explicitly asks for a `String`, these variables may not work. -Please [raise and issue](https://github.com/wildmountainfarms/wild-graphql-datasource/issues) if this limitation becomes a roadblock. +If your schema does not have a `Long` type, you may consider changing the declaration of the query to use `Float` or `String`, +which are both types built into GraphQL. + +If you run into any issues using the `from` and `to` variables for your specific schema, +please [raise and issue](https://github.com/wildmountainfarms/wild-graphql-datasource/issues). +Alternatively, if you are making a query on the frontend (any query besides alerting queries), +you may consider reading the next section to define your own from and to variables and assigning their values to +[a global variable](https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#__from-and-__to). #### Grafana variable interpolation @@ -263,11 +269,13 @@ This section documents errors that may be common * `Failed to evaluate queries and expressions: input data must be a wide series but got type long (input refid)` * This error indicates that the query returns more fields than just the time and the datapoint. * For alerts, the response from the GraphQL query cannot contain more than the time and datapoint. At this time, you cannot use other attributes from the result to filter the data. +* `Failed to evaluate queries and expressions: failed to execute conditions: input data must be a wide series but got type not (input refid)` + * This may occur if you don't have any numeric data in your response (https://github.com/grafana/grafana/issues/46429) + * This error also occurs when you include labels and your response includes multiple data frames. + * To fix this, don't use labels in alerting queries. Alerting queries support the long data frame format, so it will automatically assume non-numeric fields are labels. + * This has the drawback that if your query returns data across a period of time, you cannot easily partition data by fields AND choose to only use the most recent data. ## Known Issues -* Alerting queries can only use fields provided in the response data. +* Alerting queries and annotation queries can only use fields provided in the response data. * We plan to mitigate this in the future by allowing custom fields to be added to the response -* When hovering your mouse over a field in the query inside the GraphiQL editor, clicking either the field name or its type will navigate you away from the page, rather than jumping to the reference in the documentation explorer. - * Beware of this issue. If you accidentally let this bug navigate you away from the page, your work will be lost since your last dashboard save. - * Track this issue here: [grafana #85044](https://github.com/grafana/grafana/issues/85044) diff --git a/pkg/plugin/parsing/parsing.go b/pkg/plugin/parsing/parsing.go index b9929f1..ad5db2d 100644 --- a/pkg/plugin/parsing/parsing.go +++ b/pkg/plugin/parsing/parsing.go @@ -134,7 +134,15 @@ func ParseData(graphQlResponseData *jsonnode.Object, parsingOption querymodel.Pa row.FieldMap[key] = typedValue.String() case jsonnode.Boolean: row.FieldMap[key] = typedValue.Bool() - case jsonnode.Null, jsonnode.Number: + case jsonnode.Number: + parsedValue, err := typedValue.Float64() + if err != nil { + return nil, errors.New(fmt.Sprintf("Could not parse number: %s", typedValue.String())), UNKNOWN_ERROR + } + row.FieldMap[key] = parsedValue + // NOTE: We are allowed to store a jsonnode.Number type directly into the FieldMap (it's part of the contract to support that), + // but we decide not to because alerting queries require float64s to be used + case jsonnode.Null: row.FieldMap[key] = typedValue default: return nil, errors.New(fmt.Sprintf("Unsupported type! type: %v", reflect.TypeOf(typedValue))), UNKNOWN_ERROR diff --git a/pkg/plugin/querymodel/querymodel.go b/pkg/plugin/querymodel/querymodel.go index 1810555..1758b6a 100644 --- a/pkg/plugin/querymodel/querymodel.go +++ b/pkg/plugin/querymodel/querymodel.go @@ -5,7 +5,7 @@ type QueryModel struct { QueryText string `json:"queryText"` // The name of the operation, or a blank string to let the GraphQL server infer the operation name OperationName string `json:"operationName"` - // The variables for the operation. May either be a string or a map[string]interface{} + // The variables for the operation. May either be a string or a map[string]interface{} or nil Variables interface{} `json:"variables"` ParsingOptions []ParsingOption `json:"parsingOptions"` } diff --git a/pkg/plugin/queryvariables/variables.go b/pkg/plugin/queryvariables/variables.go index 50affec..8f2008a 100644 --- a/pkg/plugin/queryvariables/variables.go +++ b/pkg/plugin/queryvariables/variables.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/log" + "reflect" ) func AutoPopulateVariables(query backend.DataQuery, variables map[string]interface{}) { @@ -59,9 +60,11 @@ func ParseVariables(query backend.DataQuery, rawVariables interface{}) (map[stri for key, value := range typedRawVariables { variables[key] = value } + case nil: + // do nothing default: noErrors = false - log.DefaultLogger.Error("Unable to parse variables for ref ID:" + query.RefID) + log.DefaultLogger.Error(fmt.Sprintf("Unable to parse variables for ref ID: %s. Type is %v", query.RefID, reflect.TypeOf(rawVariables))) } return variables, noErrors diff --git a/provisioning/alerting/solarthing-alerts.yaml b/provisioning/alerting/solarthing-alerts.yaml new file mode 100644 index 0000000..a60208a --- /dev/null +++ b/provisioning/alerting/solarthing-alerts.yaml @@ -0,0 +1,80 @@ +apiVersion: 1 +groups: + - orgId: 1 + name: SolarThing Alerts + folder: Alerts + interval: 1m + rules: + - uid: ea5bb5a0-55be-4f37-b9e0-4804b12d7a73 + title: Low Battery Voltage + condition: C + data: + - refId: A + relativeTimeRange: + from: 600 + to: 0 + datasourceUid: fa66cf68-c3d8-4490-a89d-0c3b6a87fff8 + model: + datasource: + type: retrodaredevil-wildgraphql-datasource + uid: fa66cf68-c3d8-4490-a89d-0c3b6a87fff8 + intervalMs: 1000 + maxDataPoints: 43200 + parsingOptions: + - dataPath: queryStatusLast.batteryVoltage + labelOptions: [] + timeFields: + - timePath: dateMillis + queryText: | + query ($to: Long!) { + queryStatusLast(sourceId: "default", to: $to) { + batteryVoltage { + fragmentIdString + packet { + batteryVoltage + identifier { + representation + } + } + } + } + } + refId: A + - refId: C + relativeTimeRange: + from: 600 + to: 0 + datasourceUid: __expr__ + model: + conditions: + - evaluator: + params: + - 22.4 + type: lt + operator: + type: and + query: + params: + - C + reducer: + params: [] + type: last + type: query + datasource: + type: __expr__ + uid: __expr__ + expression: A + intervalMs: 1000 + maxDataPoints: 43200 + refId: C + type: threshold + noDataState: NoData + execErrState: Error + for: 5m + annotations: + description: Triggers when the battery is below 22.4 + runbook_url: "" + summary: Low Battery + labels: + "": "" + isPaused: false