1// Copyright 2016 Circonus, Inc. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Metric API support - Fetch, Create*, Update, Delete*, and Search
6// See: https://login.circonus.com/resources/api/calls/metric
7// *  : create and delete are handled via check_bundle or check_bundle_metrics
8
9package api
10
11import (
12	"encoding/json"
13	"fmt"
14	"net/url"
15	"regexp"
16
17	"github.com/circonus-labs/circonus-gometrics/api/config"
18)
19
20// Metric defines a metric. See https://login.circonus.com/resources/api/calls/metric for more information.
21type Metric struct {
22	Active         bool     `json:"_active,omitempty"`       // boolean
23	CheckActive    bool     `json:"_check_active,omitempty"` // boolean
24	CheckBundleCID string   `json:"_check_bundle,omitempty"` // string
25	CheckCID       string   `json:"_check,omitempty"`        // string
26	CheckTags      []string `json:"_check_tags,omitempty"`   // [] len >= 0
27	CheckUUID      string   `json:"_check_uuid,omitempty"`   // string
28	CID            string   `json:"_cid,omitempty"`          // string
29	Histogram      string   `json:"_histogram,omitempty"`    // string
30	Link           *string  `json:"link,omitempty"`          // string or null
31	MetricName     string   `json:"_metric_name,omitempty"`  // string
32	MetricType     string   `json:"_metric_type,omitempty"`  // string
33	Notes          *string  `json:"notes,omitempty"`         // string or null
34	Tags           []string `json:"tags,omitempty"`          // [] len >= 0
35	Units          *string  `json:"units,omitempty"`         // string or null
36}
37
38// FetchMetric retrieves metric with passed cid.
39func (a *API) FetchMetric(cid CIDType) (*Metric, error) {
40	if cid == nil || *cid == "" {
41		return nil, fmt.Errorf("Invalid metric CID [none]")
42	}
43
44	metricCID := string(*cid)
45
46	matched, err := regexp.MatchString(config.MetricCIDRegex, metricCID)
47	if err != nil {
48		return nil, err
49	}
50	if !matched {
51		return nil, fmt.Errorf("Invalid metric CID [%s]", metricCID)
52	}
53
54	result, err := a.Get(metricCID)
55	if err != nil {
56		return nil, err
57	}
58
59	if a.Debug {
60		a.Log.Printf("[DEBUG] fetch metric, received JSON: %s", string(result))
61	}
62
63	metric := &Metric{}
64	if err := json.Unmarshal(result, metric); err != nil {
65		return nil, err
66	}
67
68	return metric, nil
69}
70
71// FetchMetrics retrieves all metrics available to API Token.
72func (a *API) FetchMetrics() (*[]Metric, error) {
73	result, err := a.Get(config.MetricPrefix)
74	if err != nil {
75		return nil, err
76	}
77
78	var metrics []Metric
79	if err := json.Unmarshal(result, &metrics); err != nil {
80		return nil, err
81	}
82
83	return &metrics, nil
84}
85
86// UpdateMetric updates passed metric.
87func (a *API) UpdateMetric(cfg *Metric) (*Metric, error) {
88	if cfg == nil {
89		return nil, fmt.Errorf("Invalid metric config [nil]")
90	}
91
92	metricCID := string(cfg.CID)
93
94	matched, err := regexp.MatchString(config.MetricCIDRegex, metricCID)
95	if err != nil {
96		return nil, err
97	}
98	if !matched {
99		return nil, fmt.Errorf("Invalid metric CID [%s]", metricCID)
100	}
101
102	jsonCfg, err := json.Marshal(cfg)
103	if err != nil {
104		return nil, err
105	}
106
107	if a.Debug {
108		a.Log.Printf("[DEBUG] update metric, sending JSON: %s", string(jsonCfg))
109	}
110
111	result, err := a.Put(metricCID, jsonCfg)
112	if err != nil {
113		return nil, err
114	}
115
116	metric := &Metric{}
117	if err := json.Unmarshal(result, metric); err != nil {
118		return nil, err
119	}
120
121	return metric, nil
122}
123
124// SearchMetrics returns metrics matching the specified search query
125// and/or filter. If nil is passed for both parameters all metrics
126// will be returned.
127func (a *API) SearchMetrics(searchCriteria *SearchQueryType, filterCriteria *SearchFilterType) (*[]Metric, error) {
128	q := url.Values{}
129
130	if searchCriteria != nil && *searchCriteria != "" {
131		q.Set("search", string(*searchCriteria))
132	}
133
134	if filterCriteria != nil && len(*filterCriteria) > 0 {
135		for filter, criteria := range *filterCriteria {
136			for _, val := range criteria {
137				q.Add(filter, val)
138			}
139		}
140	}
141
142	if q.Encode() == "" {
143		return a.FetchMetrics()
144	}
145
146	reqURL := url.URL{
147		Path:     config.MetricPrefix,
148		RawQuery: q.Encode(),
149	}
150
151	result, err := a.Get(reqURL.String())
152	if err != nil {
153		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
154	}
155
156	var metrics []Metric
157	if err := json.Unmarshal(result, &metrics); err != nil {
158		return nil, err
159	}
160
161	return &metrics, nil
162}
163