Commit 10194df1 by Daniel Lee

azuremonitor: simple alerting for Azure Monitor API

Lots of edge cases and functionality left to implement but
a simple query works for alerting now.
parent 0e228d58
...@@ -11,8 +11,8 @@ import ( ...@@ -11,8 +11,8 @@ import (
"path" "path"
"time" "time"
// "github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/api/pluginproxy" "github.com/grafana/grafana/pkg/api/pluginproxy"
"github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
...@@ -113,10 +113,12 @@ func (e *AzureMonitorExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*Azure ...@@ -113,10 +113,12 @@ func (e *AzureMonitorExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*Azure
azureMonitorTarget := query.Model.Get("azureMonitor").MustMap() azureMonitorTarget := query.Model.Get("azureMonitor").MustMap()
resourceGroup := azureMonitorTarget["resourceGroup"].(string) urlComponents := make(map[string]string)
metricDefinition := azureMonitorTarget["metricDefinition"].(string) urlComponents["resourceGroup"] = azureMonitorTarget["resourceGroup"].(string)
resourceName := azureMonitorTarget["resourceName"].(string) urlComponents["metricDefinition"] = azureMonitorTarget["metricDefinition"].(string)
azureURL := fmt.Sprintf("resourceGroups/%s/providers/%s/%s/providers/microsoft.insights/metrics", resourceGroup, metricDefinition, resourceName) urlComponents["resourceName"] = azureMonitorTarget["resourceName"].(string)
azureURL := fmt.Sprintf("resourceGroups/%s/providers/%s/%s/providers/microsoft.insights/metrics", urlComponents["resourceGroup"], urlComponents["metricDefinition"], urlComponents["resourceName"])
alias := azureMonitorTarget["alias"].(string) alias := azureMonitorTarget["alias"].(string)
...@@ -133,11 +135,12 @@ func (e *AzureMonitorExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*Azure ...@@ -133,11 +135,12 @@ func (e *AzureMonitorExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*Azure
} }
azureMonitorQueries = append(azureMonitorQueries, &AzureMonitorQuery{ azureMonitorQueries = append(azureMonitorQueries, &AzureMonitorQuery{
URL: azureURL, URL: azureURL,
Target: target, UrlComponents: urlComponents,
Params: params, Target: target,
RefID: query.RefId, Params: params,
Alias: alias, RefID: query.RefId,
Alias: alias,
}) })
} }
...@@ -247,5 +250,21 @@ func (e *AzureMonitorExecutor) unmarshalResponse(res *http.Response) (AzureMonit ...@@ -247,5 +250,21 @@ func (e *AzureMonitorExecutor) unmarshalResponse(res *http.Response) (AzureMonit
func (e *AzureMonitorExecutor) parseResponse(queryRes *tsdb.QueryResult, data AzureMonitorResponse, query *AzureMonitorQuery) error { func (e *AzureMonitorExecutor) parseResponse(queryRes *tsdb.QueryResult, data AzureMonitorResponse, query *AzureMonitorQuery) error {
slog.Info("AzureMonitor", "Response", data) slog.Info("AzureMonitor", "Response", data)
for _, series := range data.Value {
points := make([]tsdb.TimePoint, 0)
defaultMetricName := fmt.Sprintf("%s.%s", query.UrlComponents["resourceName"], series.Name.LocalizedValue)
for _, point := range series.Timeseries[0].Data {
value := point.Average
points = append(points, tsdb.NewTimePoint(null.FloatFrom(value), float64((point.TimeStamp).Unix())*1000))
}
queryRes.Series = append(queryRes.Series, &tsdb.TimeSeries{
Name: defaultMetricName,
Points: points,
})
}
return nil return nil
} }
package azuremonitor package azuremonitor
import ( import (
"encoding/json"
"fmt" "fmt"
"io/ioutil"
"testing" "testing"
"time" "time"
...@@ -57,5 +59,37 @@ func TestAzureMonitor(t *testing.T) { ...@@ -57,5 +59,37 @@ func TestAzureMonitor(t *testing.T) {
So(queries[0].Alias, ShouldEqual, "testalias") So(queries[0].Alias, ShouldEqual, "testalias")
}) })
}) })
Convey("Parse AzureMonitor API response in the time series format", func() {
Convey("when data from query aggregated to one time series", func() {
data, err := loadTestFile("./test-data/1-azure-monitor-response.json")
So(err, ShouldBeNil)
So(data.Interval, ShouldEqual, "PT1M")
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
query := &AzureMonitorQuery{
UrlComponents: map[string]string{
"resourceName": "grafana",
},
}
err = executor.parseResponse(res, data, query)
So(err, ShouldBeNil)
So(len(res.Series), ShouldEqual, 1)
So(res.Series[0].Name, ShouldEqual, "grafana.Percentage CPU")
So(len(res.Series[0].Points), ShouldEqual, 5)
})
})
}) })
} }
func loadTestFile(path string) (AzureMonitorResponse, error) {
var data AzureMonitorResponse
jsonBody, err := ioutil.ReadFile(path)
if err != nil {
return data, err
}
err = json.Unmarshal(jsonBody, &data)
return data, err
}
{
"cost": 0,
"timespan": "2019-02-08T10:13:50Z\/2019-02-08T16:13:50Z",
"interval": "PT1M",
"value": [
{
"id": "\/subscriptions\/44693801-6ee6-49de-9b2d-9106972f9572\/resourceGroups\/grafanastaging\/providers\/Microsoft.Compute\/virtualMachines\/grafana\/providers\/Microsoft.Insights\/metrics\/Percentage CPU",
"type": "Microsoft.Insights\/metrics",
"name": {
"value": "Percentage CPU",
"localizedValue": "Percentage CPU"
},
"unit": "Percent",
"timeseries": [
{
"metadatavalues": [
],
"data": [
{
"timeStamp": "2019-02-08T10:13:00Z",
"average": 2.0875
},
{
"timeStamp": "2019-02-08T10:14:00Z",
"average": 2.1525
},
{
"timeStamp": "2019-02-08T10:15:00Z",
"average": 2.155
},
{
"timeStamp": "2019-02-08T10:16:00Z",
"average": 3.6925
},
{
"timeStamp": "2019-02-08T10:17:00Z",
"average": 2.44
}
]
}
]
}
],
"namespace": "Microsoft.Compute\/virtualMachines",
"resourceregion": "westeurope"
}
...@@ -8,11 +8,12 @@ import ( ...@@ -8,11 +8,12 @@ import (
// AzureMonitorQuery is the query for all the services as they have similar queries // AzureMonitorQuery is the query for all the services as they have similar queries
// with a url, a querystring and an alias field // with a url, a querystring and an alias field
type AzureMonitorQuery struct { type AzureMonitorQuery struct {
URL string URL string
Target string UrlComponents map[string]string
Params url.Values Target string
RefID string Params url.Values
Alias string RefID string
Alias string
} }
// AzureMonitorResponse is the json response from the Azure Monitor API // AzureMonitorResponse is the json response from the Azure Monitor API
......
...@@ -158,5 +158,6 @@ ...@@ -158,5 +158,6 @@
}, },
"metrics": true, "metrics": true,
"annotations": true "annotations": true,
"alerting": true
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment