From 36fb590b7e03127434a98a1a20cb37da8f6ff71e Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Tue, 17 Jan 2023 11:34:15 +0100 Subject: [PATCH 01/10] add metrics --- client.go | 2 + metric.go | 334 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 336 insertions(+) create mode 100644 metric.go diff --git a/client.go b/client.go index bcd20a2..8b0ad91 100644 --- a/client.go +++ b/client.go @@ -213,6 +213,7 @@ var apiRoutes = struct { heartbeats string incidents string incidentTemplates string + metrics string numbers string schedules string services string @@ -232,6 +233,7 @@ var apiRoutes = struct { heartbeats: "/api/heartbeats", incidents: "/api/incidents", incidentTemplates: "/api/incident-templates", + metrics: "/api/metrics", numbers: "/api/numbers", schedules: "/api/schedules", services: "/api/services", diff --git a/metric.go b/metric.go new file mode 100644 index 0000000..a276ce1 --- /dev/null +++ b/metric.go @@ -0,0 +1,334 @@ +package ilert + +import ( + "encoding/json" + "errors" + "fmt" + "net/url" + "strconv" +) + +// Metric definition https://api.ilert.com/api-docs/#tag/Metrics +type Metric struct { + ID int64 `json:"id"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + AggregationType string `json:"aggregationType"` + DisplayType string `json:"displayType"` + InterpolateGaps bool `json:"interpolateGaps,omitempty"` + LockYAxisMax float64 `json:"lockYAxisMax,omitempty"` + LockYAxisMin float64 `json:"lockYAxisMin,omitempty"` + MouseOverDecimal int64 `json:"mouseOverDecimal,omitempty"` + ShowValuesOnMouseOver bool `json:"showValuesOnMouseOver,omitempty"` + Teams *TeamShort `json:"teams,omitempty"` + UnitLabel string `json:"unitLabel,omitempty"` + Metadata *ProviderMetadata `json:"metadata,omitempty"` + DataSource *MetricDataSource `json:"dataSource,omitempty"` +} + +// ProviderMetadata defines metadata for the provider +type ProviderMetadata struct { + query string `json:"query,omitempty"` // used for Datadog, Prometheus +} + +// MetricAggregationType defines aggregation type for the metric +var MetricAggregationType = struct { + Average string + Sum string + Minimum string + Maximum string + Last string +}{ + Average: "AVG", + Sum: "SUM", + Minimum: "MIN", + Maximum: "MAX", + Last: "LAST", +} + +// MetricAggregationType defines aggregation type list +var MetricAggregationTypeAll = []string{ + MetricAggregationType.Average, + MetricAggregationType.Sum, + MetricAggregationType.Minimum, + MetricAggregationType.Maximum, + MetricAggregationType.Last, +} + +// MetricDisplayType defines display type for the metric +var MetricDisplayType = struct { + Graph string + Single string +}{ + Graph: "GRAPH", + Single: "SINGLE", +} + +// MetricDisplayType defines display type list +var MetricDisplayTypeAll = []string{ + MetricDisplayType.Graph, + MetricDisplayType.Single, +} + +// CreateMetricInput represents the input of a CreateMetric operation. +type CreateMetricInput struct { + _ struct{} + Metric *Metric +} + +// CreateMetricOutput represents the output of a CreateMetric operation. +type CreateMetricOutput struct { + _ struct{} + Metric *Metric +} + +// CreateMetric creates a new metric. https://api.ilert.com/api-docs/#tag/Metrics/paths/~1metrics/post +func (c *Client) CreateMetric(input *CreateMetricInput) (*CreateMetricOutput, error) { + if input == nil { + return nil, errors.New("input is required") + } + if input.Metric == nil { + return nil, errors.New("Metric input is required") + } + if input.Metric.Metadata != nil && input.Metric.DataSource == nil { + return nil, errors.New("Data source id is required when setting provider metadata") + } + if input.Metric.DataSource != nil && input.Metric.Metadata == nil { + return nil, errors.New("Provider metadata is required when setting metric data source") + } + resp, err := c.httpClient.R().SetBody(input.Metric).Post(apiRoutes.metrics) + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 201); apiErr != nil { + return nil, apiErr + } + + metric := &Metric{} + err = json.Unmarshal(resp.Body(), metric) + if err != nil { + return nil, err + } + + return &CreateMetricOutput{Metric: metric}, nil +} + +// GetMetricsInput represents the input of a GetMetrics operation. +type GetMetricsInput struct { + _ struct{} + // an integer specifying the starting point (beginning with 0) when paging through a list of entities + // Default: 0 + StartIndex *int + + // the maximum number of results when paging through a list of entities. + // Default: 10, Maximum: 25 or 100 without include + MaxResults *int + + // describes optional properties that should be included in the response + // possible values: "dataSource", "integrationKey" + Include []*string +} + +// GetMetricsOutput represents the output of a GetMetrics operation. +type GetMetricsOutput struct { + _ struct{} + Metrics []*Metric +} + +// GetMetrics lists metric sources. https://api.ilert.com/api-docs/#tag/Metrics/paths/~1metrics/get +func (c *Client) GetMetrics(input *GetMetricsInput) (*GetMetricsOutput, error) { + if input == nil { + input = &GetMetricsInput{} + } + + q := url.Values{} + if input.StartIndex != nil { + q.Add("start-index", strconv.Itoa(*input.StartIndex)) + } else { + q.Add("start-index", "0") + } + if input.MaxResults != nil { + q.Add("max-results", strconv.Itoa(*input.MaxResults)) + } else { + q.Add("max-results", "10") + } + + for _, include := range input.Include { + q.Add("include", *include) + } + + resp, err := c.httpClient.R().Get(fmt.Sprintf("%s?%s", apiRoutes.metrics, q.Encode())) + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 200); apiErr != nil { + return nil, apiErr + } + + metrics := make([]*Metric, 0) + err = json.Unmarshal(resp.Body(), &metrics) + if err != nil { + return nil, err + } + + return &GetMetricsOutput{Metrics: metrics}, nil +} + +// GetMetricInput represents the input of a GetMetric operation. +type GetMetricInput struct { + _ struct{} + MetricID *int64 +} + +// GetMetricOutput represents the output of a GetMetric operation. +type GetMetricOutput struct { + _ struct{} + Metric *Metric +} + +// GetMetric gets a metric by ID. https://api.ilert.com/api-docs/#tag/Metrics/paths/~1metrics~1{id}/get +func (c *Client) GetMetric(input *GetMetricInput) (*GetMetricOutput, error) { + if input == nil { + return nil, errors.New("input is required") + } + if input.MetricID == nil { + return nil, errors.New("metric id is required") + } + + var url = fmt.Sprintf("%s/%d", apiRoutes.metrics, *input.MetricID) + + resp, err := c.httpClient.R().Get(url) + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 200); apiErr != nil { + return nil, apiErr + } + + metric := &Metric{} + err = json.Unmarshal(resp.Body(), metric) + if err != nil { + return nil, err + } + + return &GetMetricOutput{Metric: metric}, nil +} + +// SearchMetricInput represents the input of a SearchMetric operation. +type SearchMetricInput struct { + _ struct{} + MetricName *string +} + +// SearchMetricOutput represents the output of a SearchMetric operation. +type SearchMetricOutput struct { + _ struct{} + Metric *Metric +} + +// SearchMetric gets the metric with specified name. +func (c *Client) SearchMetric(input *SearchMetricInput) (*SearchMetricOutput, error) { + if input == nil { + return nil, errors.New("input is required") + } + if input.MetricName == nil { + return nil, errors.New("metric name is required") + } + + resp, err := c.httpClient.R().Get(fmt.Sprintf("%s/name/%s", apiRoutes.metrics, *input.MetricName)) + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 200); apiErr != nil { + return nil, apiErr + } + + metric := &Metric{} + err = json.Unmarshal(resp.Body(), metric) + if err != nil { + return nil, err + } + + return &SearchMetricOutput{Metric: metric}, nil +} + +// UpdateMetricInput represents the input of a UpdateMetric operation. +type UpdateMetricInput struct { + _ struct{} + MetricID *int64 + Metric *Metric +} + +// UpdateMetricOutput represents the output of a UpdateMetric operation. +type UpdateMetricOutput struct { + _ struct{} + Metric *Metric +} + +// UpdateMetric updates the specific metric. https://api.ilert.com/api-docs/#tag/Metrics/paths/~1metrics~1{id}/put +func (c *Client) UpdateMetric(input *UpdateMetricInput) (*UpdateMetricOutput, error) { + if input == nil { + return nil, errors.New("input is required") + } + if input.MetricID == nil { + return nil, errors.New("metric id is required") + } + if input.Metric == nil { + return nil, errors.New("metric input is required") + } + if input.Metric.Metadata != nil && input.Metric.DataSource == nil { + return nil, errors.New("Data source id is required when setting provider metadata") + } + + url := fmt.Sprintf("%s/%d", apiRoutes.metrics, *input.MetricID) + + resp, err := c.httpClient.R().SetBody(input.Metric).Put(url) + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 200); apiErr != nil { + return nil, apiErr + } + + metric := &Metric{} + err = json.Unmarshal(resp.Body(), metric) + if err != nil { + return nil, err + } + + return &UpdateMetricOutput{Metric: metric}, nil +} + +// DeleteMetricInput represents the input of a DeleteMetric operation. +type DeleteMetricInput struct { + _ struct{} + MetricID *int64 +} + +// DeleteMetricOutput represents the output of a DeleteMetric operation. +type DeleteMetricOutput struct { + _ struct{} +} + +// DeleteMetric deletes the specified metric. https://api.ilert.com/api-docs/#tag/Metrics/paths/~1metrics~1{id}/delete +func (c *Client) DeleteMetric(input *DeleteMetricInput) (*DeleteMetricOutput, error) { + if input == nil { + return nil, errors.New("input is required") + } + if input.MetricID == nil { + return nil, errors.New("metric id is required") + } + + url := fmt.Sprintf("%s/%d", apiRoutes.metrics, *input.MetricID) + + resp, err := c.httpClient.R().Delete(url) + + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 204); apiErr != nil { + return nil, apiErr + } + + return &DeleteMetricOutput{}, nil +} From 6d37438e02495499e65f07d31e179db9b95f649c Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Tue, 17 Jan 2023 12:36:45 +0100 Subject: [PATCH 02/10] add metric data sources --- client.go | 2 + metric.go | 43 +++---- metric_data_source.go | 292 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 314 insertions(+), 23 deletions(-) create mode 100644 metric_data_source.go diff --git a/client.go b/client.go index 8b0ad91..3d58d35 100644 --- a/client.go +++ b/client.go @@ -214,6 +214,7 @@ var apiRoutes = struct { incidents string incidentTemplates string metrics string + metricDataSources string numbers string schedules string services string @@ -234,6 +235,7 @@ var apiRoutes = struct { incidents: "/api/incidents", incidentTemplates: "/api/incident-templates", metrics: "/api/metrics", + metricDataSources: "/api/metric-data-sources", numbers: "/api/numbers", schedules: "/api/schedules", services: "/api/services", diff --git a/metric.go b/metric.go index a276ce1..99d2102 100644 --- a/metric.go +++ b/metric.go @@ -10,25 +10,25 @@ import ( // Metric definition https://api.ilert.com/api-docs/#tag/Metrics type Metric struct { - ID int64 `json:"id"` - Name string `json:"name"` - Description string `json:"description,omitempty"` - AggregationType string `json:"aggregationType"` - DisplayType string `json:"displayType"` - InterpolateGaps bool `json:"interpolateGaps,omitempty"` - LockYAxisMax float64 `json:"lockYAxisMax,omitempty"` - LockYAxisMin float64 `json:"lockYAxisMin,omitempty"` - MouseOverDecimal int64 `json:"mouseOverDecimal,omitempty"` - ShowValuesOnMouseOver bool `json:"showValuesOnMouseOver,omitempty"` - Teams *TeamShort `json:"teams,omitempty"` - UnitLabel string `json:"unitLabel,omitempty"` - Metadata *ProviderMetadata `json:"metadata,omitempty"` - DataSource *MetricDataSource `json:"dataSource,omitempty"` + ID int64 `json:"id,omitempty"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + AggregationType string `json:"aggregationType"` + DisplayType string `json:"displayType"` + InterpolateGaps bool `json:"interpolateGaps,omitempty"` + LockYAxisMax float64 `json:"lockYAxisMax,omitempty"` + LockYAxisMin float64 `json:"lockYAxisMin,omitempty"` + MouseOverDecimal int64 `json:"mouseOverDecimal,omitempty"` + ShowValuesOnMouseOver bool `json:"showValuesOnMouseOver,omitempty"` + Teams *TeamShort `json:"teams,omitempty"` + UnitLabel string `json:"unitLabel,omitempty"` + Metadata *MetricProviderMetadata `json:"metadata,omitempty"` + DataSource *MetricDataSource `json:"dataSource,omitempty"` } -// ProviderMetadata defines metadata for the provider -type ProviderMetadata struct { - query string `json:"query,omitempty"` // used for Datadog, Prometheus +// MetricProviderMetadata defines provider metadata for the metric +type MetricProviderMetadata struct { + Query string `json:"query,omitempty"` // used for Datadog, Prometheus } // MetricAggregationType defines aggregation type for the metric @@ -88,13 +88,13 @@ func (c *Client) CreateMetric(input *CreateMetricInput) (*CreateMetricOutput, er return nil, errors.New("input is required") } if input.Metric == nil { - return nil, errors.New("Metric input is required") + return nil, errors.New("metric input is required") } if input.Metric.Metadata != nil && input.Metric.DataSource == nil { - return nil, errors.New("Data source id is required when setting provider metadata") + return nil, errors.New("data source id is required when setting provider metadata") } if input.Metric.DataSource != nil && input.Metric.Metadata == nil { - return nil, errors.New("Provider metadata is required when setting metric data source") + return nil, errors.New("provider metadata is required when setting metric data source") } resp, err := c.httpClient.R().SetBody(input.Metric).Post(apiRoutes.metrics) if err != nil { @@ -276,9 +276,6 @@ func (c *Client) UpdateMetric(input *UpdateMetricInput) (*UpdateMetricOutput, er if input.Metric == nil { return nil, errors.New("metric input is required") } - if input.Metric.Metadata != nil && input.Metric.DataSource == nil { - return nil, errors.New("Data source id is required when setting provider metadata") - } url := fmt.Sprintf("%s/%d", apiRoutes.metrics, *input.MetricID) diff --git a/metric_data_source.go b/metric_data_source.go new file mode 100644 index 0000000..977fbed --- /dev/null +++ b/metric_data_source.go @@ -0,0 +1,292 @@ +package ilert + +import ( + "encoding/json" + "errors" + "fmt" + "net/url" + "strconv" +) + +// MetricDataSource definition https://api.ilert.com/api-docs/#tag/Metric-Data-Sources +type MetricDataSource struct { + ID int64 `json:"id,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + Teams *TeamShort `json:"teams,omitempty"` + Metadata *MetricDataSourceMetadata `json:"metadata"` +} + +// MetricDataSourceMetadata defines provider metadata for the metric data source +type MetricDataSourceMetadata struct { + Region string `json:"region,omitempty"` // used for Datadog + ApiKey string `json:"apiKey,omitempty"` // used for Datadog + ApplicationKey string `json:"applicationKey,omitempty"` // used for Datadog + AuthType string `json:"authType,omitempty"` // used for Prometheus + BasicUser string `json:"basicUser,omitempty"` // used for Prometheus + BasicPass string `json:"basicPass,omitempty"` // used for Prometheus + HeaderKey string `json:"headerKey,omitempty"` // used for Prometheus + HeaderValue string `json:"headerValue,omitempty"` // used for Prometheus +} + +// MetricDataSourceType defines provider type of the metric data source +var MetricDataSourceType = struct { + Datadog string + Prometheus string +}{ + Datadog: "DATADOG", + Prometheus: "PROMETHEUS", +} + +// MetricDataSourceType defines provider type list +var MetricDataSourceAll = []string{ + MetricDataSourceType.Datadog, + MetricDataSourceType.Prometheus, +} + +// CreateMetricDataSourceInput represents the input of a CreateMetricDataSource operation. +type CreateMetricDataSourceInput struct { + _ struct{} + MetricDataSource *MetricDataSource +} + +// CreateMetricDataSourceOutput represents the output of a CreateMetricDataSource operation. +type CreateMetricDataSourceOutput struct { + _ struct{} + MetricDataSource *MetricDataSource +} + +// CreateMetricDataSource creates a new metric data source. https://api.ilert.com/api-docs/#tag/Metric-Data-Sources/paths/~1metric-data-sources/post +func (c *Client) CreateMetricDataSource(input *CreateMetricDataSourceInput) (*CreateMetricDataSourceOutput, error) { + if input == nil { + return nil, errors.New("input is required") + } + if input.MetricDataSource == nil { + return nil, errors.New("metric data source input is required") + } + + resp, err := c.httpClient.R().SetBody(input.MetricDataSource).Post(apiRoutes.metricDataSources) + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 201); apiErr != nil { + return nil, apiErr + } + + metricdatasource := &MetricDataSource{} + err = json.Unmarshal(resp.Body(), metricdatasource) + if err != nil { + return nil, err + } + + return &CreateMetricDataSourceOutput{MetricDataSource: metricdatasource}, nil +} + +// GetMetricDataSourcesInput represents the input of a GetMetricDataSources operation. +type GetMetricDataSourcesInput struct { + _ struct{} + // an integer specifying the starting point (beginning with 0) when paging through a list of entities + // Default: 0 + StartIndex *int + + // the maximum number of results when paging through a list of entities. + // Default: 10, Maximum: 25 or 100 without include + MaxResults *int +} + +// GetMetricDataSourcesOutput represents the output of a GetMetricDataSources operation. +type GetMetricDataSourcesOutput struct { + _ struct{} + MetricDataSources []*MetricDataSource +} + +// GetMetricDataSources lists metricdatasource sources. https://api.ilert.com/api-docs/#tag/Metric-Data-Sources/paths/~1metric-data-sources/get +func (c *Client) GetMetricDataSources(input *GetMetricDataSourcesInput) (*GetMetricDataSourcesOutput, error) { + if input == nil { + input = &GetMetricDataSourcesInput{} + } + + q := url.Values{} + if input.StartIndex != nil { + q.Add("start-index", strconv.Itoa(*input.StartIndex)) + } else { + q.Add("start-index", "0") + } + if input.MaxResults != nil { + q.Add("max-results", strconv.Itoa(*input.MaxResults)) + } else { + q.Add("max-results", "10") + } + + resp, err := c.httpClient.R().Get(fmt.Sprintf("%s?%s", apiRoutes.metricDataSources, q.Encode())) + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 200); apiErr != nil { + return nil, apiErr + } + + metricdatasources := make([]*MetricDataSource, 0) + err = json.Unmarshal(resp.Body(), &metricdatasources) + if err != nil { + return nil, err + } + + return &GetMetricDataSourcesOutput{MetricDataSources: metricdatasources}, nil +} + +// GetMetricDataSourceInput represents the input of a GetMetricDataSource operation. +type GetMetricDataSourceInput struct { + _ struct{} + MetricDataSourceID *int64 +} + +// GetMetricDataSourceOutput represents the output of a GetMetricDataSource operation. +type GetMetricDataSourceOutput struct { + _ struct{} + MetricDataSource *MetricDataSource +} + +// GetMetricDataSource gets a metric data source by ID. https://api.ilert.com/api-docs/#tag/Metric-Data-Sources/paths/~1metric-data-sources~1{id}/get +func (c *Client) GetMetricDataSource(input *GetMetricDataSourceInput) (*GetMetricDataSourceOutput, error) { + if input == nil { + return nil, errors.New("input is required") + } + if input.MetricDataSourceID == nil { + return nil, errors.New("metric data source id is required") + } + + var url = fmt.Sprintf("%s/%d", apiRoutes.metricDataSources, *input.MetricDataSourceID) + + resp, err := c.httpClient.R().Get(url) + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 200); apiErr != nil { + return nil, apiErr + } + + metricDataSource := &MetricDataSource{} + err = json.Unmarshal(resp.Body(), metricDataSource) + if err != nil { + return nil, err + } + + return &GetMetricDataSourceOutput{MetricDataSource: metricDataSource}, nil +} + +// SearchMetricDataSourceInput represents the input of a SearchMetricDataSource operation. +type SearchMetricDataSourceInput struct { + _ struct{} + MetricDataSourceName *string +} + +// SearchMetricDataSourceOutput represents the output of a SearchMetricDataSource operation. +type SearchMetricDataSourceOutput struct { + _ struct{} + MetricDataSource *MetricDataSource +} + +// SearchMetricDataSource gets the metric data source with specified name. +func (c *Client) SearchMetricDataSource(input *SearchMetricDataSourceInput) (*SearchMetricDataSourceOutput, error) { + if input == nil { + return nil, errors.New("input is required") + } + if input.MetricDataSourceName == nil { + return nil, errors.New("metric data source name is required") + } + + resp, err := c.httpClient.R().Get(fmt.Sprintf("%s/name/%s", apiRoutes.metricDataSources, *input.MetricDataSourceName)) + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 200); apiErr != nil { + return nil, apiErr + } + + metricDataSource := &MetricDataSource{} + err = json.Unmarshal(resp.Body(), metricDataSource) + if err != nil { + return nil, err + } + + return &SearchMetricDataSourceOutput{MetricDataSource: metricDataSource}, nil +} + +// UpdateMetricDataSourceInput represents the input of a UpdateMetricDataSource operation. +type UpdateMetricDataSourceInput struct { + _ struct{} + MetricDataSourceID *int64 + MetricDataSource *MetricDataSource +} + +// UpdateMetricDataSourceOutput represents the output of a UpdateMetricDataSource operation. +type UpdateMetricDataSourceOutput struct { + _ struct{} + MetricDataSource *MetricDataSource +} + +// UpdateMetricDataSource updates the specific metric data source. https://api.ilert.com/api-docs/#tag/Metric-Data-Sources/paths/~1metric-data-sources~1{id}/put +func (c *Client) UpdateMetricDataSource(input *UpdateMetricDataSourceInput) (*UpdateMetricDataSourceOutput, error) { + if input == nil { + return nil, errors.New("input is required") + } + if input.MetricDataSourceID == nil { + return nil, errors.New("metric data source id is required") + } + if input.MetricDataSource == nil { + return nil, errors.New("metric data source input is required") + } + + url := fmt.Sprintf("%s/%d", apiRoutes.metricDataSources, *input.MetricDataSourceID) + + resp, err := c.httpClient.R().SetBody(input.MetricDataSource).Put(url) + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 200); apiErr != nil { + return nil, apiErr + } + + metricDataSource := &MetricDataSource{} + err = json.Unmarshal(resp.Body(), metricDataSource) + if err != nil { + return nil, err + } + + return &UpdateMetricDataSourceOutput{MetricDataSource: metricDataSource}, nil +} + +// DeleteMetricDataSourceInput represents the input of a DeleteMetricDataSource operation. +type DeleteMetricDataSourceInput struct { + _ struct{} + MetricDataSourceID *int64 +} + +// DeleteMetricDataSourceOutput represents the output of a DeleteMetricDataSource operation. +type DeleteMetricDataSourceOutput struct { + _ struct{} +} + +// DeleteMetricDataSource deletes the specified metric data source. https://api.ilert.com/api-docs/#tag/Metric-Data-Sources/paths/~1metric-data-sources~1{id}/delete +func (c *Client) DeleteMetricDataSource(input *DeleteMetricDataSourceInput) (*DeleteMetricDataSourceOutput, error) { + if input == nil { + return nil, errors.New("input is required") + } + if input.MetricDataSourceID == nil { + return nil, errors.New("metric data source id is required") + } + + url := fmt.Sprintf("%s/%d", apiRoutes.metricDataSources, *input.MetricDataSourceID) + + resp, err := c.httpClient.R().Delete(url) + + if err != nil { + return nil, err + } + if apiErr := getGenericAPIError(resp, 204); apiErr != nil { + return nil, apiErr + } + + return &DeleteMetricDataSourceOutput{}, nil +} From 726f7cdafe03e1c469934f81fcb6ad5fb9343d4b Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Tue, 17 Jan 2023 13:35:28 +0100 Subject: [PATCH 03/10] add series --- client.go | 2 ++ metric.go | 2 +- series.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 series.go diff --git a/client.go b/client.go index 3d58d35..314db55 100644 --- a/client.go +++ b/client.go @@ -217,6 +217,7 @@ var apiRoutes = struct { metricDataSources string numbers string schedules string + series string services string statusPages string uptimeMonitors string @@ -238,6 +239,7 @@ var apiRoutes = struct { metricDataSources: "/api/metric-data-sources", numbers: "/api/numbers", schedules: "/api/schedules", + series: "/api/series", services: "/api/services", statusPages: "/api/status-pages", uptimeMonitors: "/api/uptime-monitors", diff --git a/metric.go b/metric.go index 99d2102..bc1f0ca 100644 --- a/metric.go +++ b/metric.go @@ -18,7 +18,7 @@ type Metric struct { InterpolateGaps bool `json:"interpolateGaps,omitempty"` LockYAxisMax float64 `json:"lockYAxisMax,omitempty"` LockYAxisMin float64 `json:"lockYAxisMin,omitempty"` - MouseOverDecimal int64 `json:"mouseOverDecimal,omitempty"` + MouseOverDecimal float64 `json:"mouseOverDecimal,omitempty"` ShowValuesOnMouseOver bool `json:"showValuesOnMouseOver,omitempty"` Teams *TeamShort `json:"teams,omitempty"` UnitLabel string `json:"unitLabel,omitempty"` diff --git a/series.go b/series.go new file mode 100644 index 0000000..4230067 --- /dev/null +++ b/series.go @@ -0,0 +1,71 @@ +package ilert + +import ( + "errors" + "fmt" +) + +// SingleSeries definition https://api.ilert.com/api-docs/#tag/Series +type SingleSeries struct { + Timestamp int64 `json:"timestamp,omitempty"` + Value float64 `json:"value"` +} + +// MultipleSeries definition https://api.ilert.com/api-docs/#tag/Series +type MultipleSeries struct { + Series []SingleSeries `json:"series"` +} + +// CreateSingleSeriesInput represents the input of a CreateSingleSeries operation. +type CreateSingleSeriesInput struct { + _ struct{} + Series *SingleSeries + MetricKey *string +} + +// CreateSingleSeries ingests a series for a metric. https://api.ilert.com/api-docs/#tag/Series/paths/~1series~1{key}/post +func (c *Client) CreateSingleSeries(input *CreateSingleSeriesInput) error { + if input == nil { + return errors.New("input is required") + } + if input.MetricKey == nil { + return errors.New("metric integration key is required") + } + + resp, err := c.httpClient.R().SetBody(input.Series).Post(fmt.Sprintf("%s/%s", apiRoutes.series, *input.MetricKey)) + if err != nil { + return err + } + if apiErr := getGenericAPIError(resp, 202); apiErr != nil { + return apiErr + } + + return nil +} + +// CreateMultipleSeriesInput represents the input of a CreateMultipleSeries operation. +type CreateMultipleSeriesInput struct { + _ struct{} + Series *MultipleSeries + MetricKey *string +} + +// CreateMultipleSeries ingests multiple series for a metric. https://api.ilert.com/api-docs/#tag/Series/paths/~1series~1{key}/post +func (c *Client) CreateMultipleSeries(input *CreateMultipleSeriesInput) error { + if input == nil { + return errors.New("input is required") + } + if input.MetricKey == nil { + return errors.New("metric integration key is required") + } + + resp, err := c.httpClient.R().SetBody(input.Series).Post(fmt.Sprintf("%s/%s", apiRoutes.series, *input.MetricKey)) + if err != nil { + return err + } + if apiErr := getGenericAPIError(resp, 202); apiErr != nil { + return apiErr + } + + return nil +} From 687debb6d7b7ac0c560088531560520e0bb509ae Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Tue, 17 Jan 2023 16:06:38 +0100 Subject: [PATCH 04/10] add examples --- examples/metric/main.go | 33 +++++++++++++++++++++++++++++++ examples/metricdatasource/main.go | 32 ++++++++++++++++++++++++++++++ examples/series/main.go | 26 ++++++++++++++++++++++++ metric.go | 2 +- metric_data_source.go | 24 +++++++++++++++++++++- 5 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 examples/metric/main.go create mode 100644 examples/metricdatasource/main.go create mode 100644 examples/series/main.go diff --git a/examples/metric/main.go b/examples/metric/main.go new file mode 100644 index 0000000..e951951 --- /dev/null +++ b/examples/metric/main.go @@ -0,0 +1,33 @@ +package main + +import ( + "log" + + "github.com/iLert/ilert-go/v2" +) + +func main() { + var apiToken = "your API token" + client := ilert.NewClient(ilert.WithAPIToken(apiToken)) + + createMetricInput := &ilert.CreateMetricInput{ + Metric: &ilert.Metric{ + Name: "example", + AggregationType: ilert.MetricAggregationType.Average, + DisplayType: ilert.MetricDisplayType.Graph, + Metadata: &ilert.MetricProviderMetadata{ + Query: "your prometheus query", + }, + DataSource: &ilert.MetricDataSource{ + ID: 0, // your metric data source id + }, + }, + } + + result, err := client.CreateMetric(createMetricInput) + if err != nil { + log.Println(result) + log.Fatalln("ERROR:", err) + } + log.Printf("Metric:\n\n %+v\n", result.Metric) +} diff --git a/examples/metricdatasource/main.go b/examples/metricdatasource/main.go new file mode 100644 index 0000000..2eba15c --- /dev/null +++ b/examples/metricdatasource/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "log" + + "github.com/iLert/ilert-go/v2" +) + +func main() { + var apiToken = "your API token" + client := ilert.NewClient(ilert.WithAPIToken(apiToken)) + + createDataSourceInput := &ilert.CreateMetricDataSourceInput{ + MetricDataSource: &ilert.MetricDataSource{ + Name: "example", + Type: ilert.MetricDataSourceType.Prometheus, + Metadata: &ilert.MetricDataSourceMetadata{ + AuthType: ilert.MetricDataSourceAuthType.Basic, + BasicUser: "your prometheus username", + BasicPass: "your prometheus password", + Url: "your prometheus url", + }, + }, + } + + result, err := client.CreateMetricDataSource(createDataSourceInput) + if err != nil { + log.Println(result) + log.Fatalln("ERROR:", err) + } + log.Printf("Metric Data Source:\n\n %+v\n", result.MetricDataSource) +} diff --git a/examples/series/main.go b/examples/series/main.go new file mode 100644 index 0000000..798b865 --- /dev/null +++ b/examples/series/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "log" + + "github.com/iLert/ilert-go/v2" +) + +func main() { + var apiToken = "your API token" + client := ilert.NewClient(ilert.WithAPIToken(apiToken)) + + createSingleSeriesInput := &ilert.CreateSingleSeriesInput{ + Series: &ilert.SingleSeries{ + Value: 500, + }, + MetricKey: ilert.String("your metric integration key"), + } + + err := client.CreateSingleSeries(createSingleSeriesInput) + if err != nil { + log.Fatalln("ERROR:", err) + } else { + log.Println("Series submitted successfully") + } +} diff --git a/metric.go b/metric.go index bc1f0ca..9db2a4d 100644 --- a/metric.go +++ b/metric.go @@ -20,7 +20,7 @@ type Metric struct { LockYAxisMin float64 `json:"lockYAxisMin,omitempty"` MouseOverDecimal float64 `json:"mouseOverDecimal,omitempty"` ShowValuesOnMouseOver bool `json:"showValuesOnMouseOver,omitempty"` - Teams *TeamShort `json:"teams,omitempty"` + Teams []TeamShort `json:"teams,omitempty"` UnitLabel string `json:"unitLabel,omitempty"` Metadata *MetricProviderMetadata `json:"metadata,omitempty"` DataSource *MetricDataSource `json:"dataSource,omitempty"` diff --git a/metric_data_source.go b/metric_data_source.go index 977fbed..a55f492 100644 --- a/metric_data_source.go +++ b/metric_data_source.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "log" "net/url" "strconv" ) @@ -13,7 +14,7 @@ type MetricDataSource struct { ID int64 `json:"id,omitempty"` Name string `json:"name"` Type string `json:"type"` - Teams *TeamShort `json:"teams,omitempty"` + Teams []TeamShort `json:"teams,omitempty"` Metadata *MetricDataSourceMetadata `json:"metadata"` } @@ -27,6 +28,7 @@ type MetricDataSourceMetadata struct { BasicPass string `json:"basicPass,omitempty"` // used for Prometheus HeaderKey string `json:"headerKey,omitempty"` // used for Prometheus HeaderValue string `json:"headerValue,omitempty"` // used for Prometheus + Url string `json:"url,omitempty"` // used for Prometheus } // MetricDataSourceType defines provider type of the metric data source @@ -44,6 +46,24 @@ var MetricDataSourceAll = []string{ MetricDataSourceType.Prometheus, } +// MetricDataSourceAuthType defines provider authentication type of the metric data source +var MetricDataSourceAuthType = struct { + None string + Basic string + Header string +}{ + None: "NONE", + Basic: "BASIC", + Header: "HEADER", +} + +// MetricDataSourceAuthType defines provider authentication type list +var MetricDataSourceAuthTypeAll = []string{ + MetricDataSourceAuthType.None, + MetricDataSourceAuthType.Basic, + MetricDataSourceAuthType.Header, +} + // CreateMetricDataSourceInput represents the input of a CreateMetricDataSource operation. type CreateMetricDataSourceInput struct { _ struct{} @@ -65,6 +85,8 @@ func (c *Client) CreateMetricDataSource(input *CreateMetricDataSourceInput) (*Cr return nil, errors.New("metric data source input is required") } + // log.Print(&input.MetricDataSource) + log.Printf(`%+v`, input.MetricDataSource.Metadata) resp, err := c.httpClient.R().SetBody(input.MetricDataSource).Post(apiRoutes.metricDataSources) if err != nil { return nil, err From 628fac4bc3efd1d269696cfb0edf2d94342e134a Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Tue, 17 Jan 2023 16:06:48 +0100 Subject: [PATCH 05/10] correct typo in examples --- examples/{statuspage_group => statuspagegroup}/main.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{statuspage_group => statuspagegroup}/main.go (100%) diff --git a/examples/statuspage_group/main.go b/examples/statuspagegroup/main.go similarity index 100% rename from examples/statuspage_group/main.go rename to examples/statuspagegroup/main.go From 65034103d6576c49c4763d5328336305e547d5af Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Tue, 17 Jan 2023 16:06:56 +0100 Subject: [PATCH 06/10] bump version, edit changelog --- CHANGELOG.md | 6 ++++++ version.go | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a08c0e..da3e0c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 17.01.2023, Version 2.6.0 + +- add metrics +- add metric data sources +- add series + ## 13.01.2023, Version 2.5.1 - fix missing json params in status page group diff --git a/version.go b/version.go index db6375c..92376a2 100644 --- a/version.go +++ b/version.go @@ -1,4 +1,4 @@ package ilert // Version package version -const Version = "v2.5.1" +const Version = "v2.6.0" From 3a89b20ae1f9778d698424993fbcf3b3516fb259 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Tue, 17 Jan 2023 16:30:44 +0100 Subject: [PATCH 07/10] fix typos --- metric_data_source.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/metric_data_source.go b/metric_data_source.go index a55f492..a9df663 100644 --- a/metric_data_source.go +++ b/metric_data_source.go @@ -95,13 +95,13 @@ func (c *Client) CreateMetricDataSource(input *CreateMetricDataSourceInput) (*Cr return nil, apiErr } - metricdatasource := &MetricDataSource{} - err = json.Unmarshal(resp.Body(), metricdatasource) + metricDataSource := &MetricDataSource{} + err = json.Unmarshal(resp.Body(), metricDataSource) if err != nil { return nil, err } - return &CreateMetricDataSourceOutput{MetricDataSource: metricdatasource}, nil + return &CreateMetricDataSourceOutput{MetricDataSource: metricDataSource}, nil } // GetMetricDataSourcesInput represents the input of a GetMetricDataSources operation. @@ -148,13 +148,13 @@ func (c *Client) GetMetricDataSources(input *GetMetricDataSourcesInput) (*GetMet return nil, apiErr } - metricdatasources := make([]*MetricDataSource, 0) - err = json.Unmarshal(resp.Body(), &metricdatasources) + metricDataSource := make([]*MetricDataSource, 0) + err = json.Unmarshal(resp.Body(), &metricDataSource) if err != nil { return nil, err } - return &GetMetricDataSourcesOutput{MetricDataSources: metricdatasources}, nil + return &GetMetricDataSourcesOutput{MetricDataSources: metricDataSource}, nil } // GetMetricDataSourceInput represents the input of a GetMetricDataSource operation. From 9b20d946d5f089435306c776cca1234ae02a07f8 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Wed, 18 Jan 2023 11:02:34 +0100 Subject: [PATCH 08/10] fix typo --- metric_data_source.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metric_data_source.go b/metric_data_source.go index a9df663..d7aab67 100644 --- a/metric_data_source.go +++ b/metric_data_source.go @@ -41,7 +41,7 @@ var MetricDataSourceType = struct { } // MetricDataSourceType defines provider type list -var MetricDataSourceAll = []string{ +var MetricDataSourceTypeAll = []string{ MetricDataSourceType.Datadog, MetricDataSourceType.Prometheus, } From dbe274dd0609f7d9c9e064ceccadf452ce72b8cd Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Wed, 18 Jan 2023 12:10:02 +0100 Subject: [PATCH 09/10] edit comment --- metric_data_source.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metric_data_source.go b/metric_data_source.go index d7aab67..29e7b14 100644 --- a/metric_data_source.go +++ b/metric_data_source.go @@ -112,7 +112,7 @@ type GetMetricDataSourcesInput struct { StartIndex *int // the maximum number of results when paging through a list of entities. - // Default: 10, Maximum: 25 or 100 without include + // Default: 10, Maximum: 100 MaxResults *int } From 98b15d0184f495c4e3b3531eaef58720a40e6a0a Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Wed, 18 Jan 2023 12:17:31 +0100 Subject: [PATCH 10/10] remove comments --- metric_data_source.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/metric_data_source.go b/metric_data_source.go index 29e7b14..5108fa4 100644 --- a/metric_data_source.go +++ b/metric_data_source.go @@ -4,7 +4,6 @@ import ( "encoding/json" "errors" "fmt" - "log" "net/url" "strconv" ) @@ -85,8 +84,6 @@ func (c *Client) CreateMetricDataSource(input *CreateMetricDataSourceInput) (*Cr return nil, errors.New("metric data source input is required") } - // log.Print(&input.MetricDataSource) - log.Printf(`%+v`, input.MetricDataSource.Metadata) resp, err := c.httpClient.R().SetBody(input.MetricDataSource).Post(apiRoutes.metricDataSources) if err != nil { return nil, err