Skip to content

Commit

Permalink
CIRC-6667: Add support for /tag_cats and /tag_vals and Graphite API (#59
Browse files Browse the repository at this point in the history
)

* CIRC-6535: Add X-Snowth-Timeout header

* CIRC-6535: Update openhistogram

* CIRC-6535: Add functions to interact with IRONdb check tag metadata

* CIRC-6535: Update changelog

* CIRC-6535: No need to search for node again

* CIRC-6535: Added warning about update check tags function

* CIRC-6535: Add support for /tag_cats and /tag_vals

* CIRC-6667: Add IRONdb graphite API access
  • Loading branch information
dhaifley authored Jun 21, 2021
1 parent e70d2d9 commit cb6483a
Show file tree
Hide file tree
Showing 5 changed files with 555 additions and 0 deletions.
10 changes: 10 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ to [Semantic Versioning](http://semver.org/) rules.

## [Next Release]

## [v1.10.0] - 2021-06-14

* add: Added functions implementing access to the IRONdb read graphite API:
GraphiteFindMetrics(), GraphiteFindTags(), and GraphiteGetDatapoints().
* add: Added functions implementing access to the IRONdb find /tag_cats, and
find /tag_vals API's.

## [v1.9.0] - 2021-05-10

* add: Added functions to allow interactivity with IRONdb check tag metadata.
Expand Down Expand Up @@ -311,6 +318,9 @@ writing to histogram endpoints.
any delay, once started. Created: 2019-03-12. Fixed: 2019-03-13.

[Next Release]: https://github.com/circonus-labs/gosnowth
[v1.10.0]: https://github.com/circonus-labs/gosnowth/releases/tag/v1.10.0
[v1.9.0]: https://github.com/circonus-labs/gosnowth/releases/tag/v1.9.0
[v1.8.1]: https://github.com/circonus-labs/gosnowth/releases/tag/v1.8.1
[v1.8.0]: https://github.com/circonus-labs/gosnowth/releases/tag/v1.8.0
[v1.7.2]: https://github.com/circonus-labs/gosnowth/releases/tag/v1.7.2
[v1.7.1]: https://github.com/circonus-labs/gosnowth/releases/tag/v1.7.1
Expand Down
178 changes: 178 additions & 0 deletions graphite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package gosnowth

import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
)

// GraphiteOptions values contain optional parameters to be passed to the
// IRONdb graphite API call operations.
type GraphiteOptions struct {
Limit int64 `json:"limit"`
}

// GraphiteMetric values are used to describe metrics in graphite format.
type GraphiteMetric struct {
Leaf bool `json:"leaf"`
Name string `json:"name"`
Data map[string]string `json:"leaf_data,omitempty"`
}

// GraphiteLookup values are used to provide information needed to retrieve
// graphite datapoints.
type GraphiteLookup struct {
Start int64 `json:"start"`
End int64 `json:"end"`
Names []string `json:"names"`
}

// GraphiteDatapoints values are used to represent series of graphite
// datapoints.
type GraphiteDatapoints struct {
From int64 `json:"from"`
To int64 `json:"to"`
Step int64 `json:"step"`
Series map[string][]*float64 `json:"series"`
}

// GraphiteFindMetrics retrieves metrics that are associated with the provided
// graphite metric search query.
func (sc *SnowthClient) GraphiteFindMetrics(accountID int64,
prefix, query string, options *GraphiteOptions,
nodes ...*SnowthNode) ([]GraphiteMetric, error) {
return sc.GraphiteFindMetricsContext(context.Background(), accountID,
prefix, query, options, nodes...)
}

// GraphiteFindMetricsContext is the context aware version of
// GraphiteFindMetrics.
func (sc *SnowthClient) GraphiteFindMetricsContext(ctx context.Context,
accountID int64, prefix, query string, options *GraphiteOptions,
nodes ...*SnowthNode) ([]GraphiteMetric, error) {
var node *SnowthNode
if len(nodes) > 0 && nodes[0] != nil {
node = nodes[0]
} else {
node = sc.GetActiveNode()
}

u := fmt.Sprintf("%s?query=%s",
sc.getURL(node, fmt.Sprintf("/graphite/%d/%s/metrics/find",
accountID, url.QueryEscape(prefix))), url.QueryEscape(query))

hdrs := http.Header{}
if options != nil && options.Limit != 0 {
hdrs.Set("X-Snowth-Advisory-Limit",
strconv.FormatInt(options.Limit, 10))
}

body, _, err := sc.DoRequestContext(ctx, node, "GET", u, nil, hdrs)
if err != nil {
return nil, err
}

r := []GraphiteMetric{}
if err := decodeJSON(body, &r); err != nil {
return nil, fmt.Errorf("unable to decode IRONdb response: %w", err)
}

return r, nil
}

// GraphiteFindTags retrieves metrics that are associated with the provided
// graphite tag search query.
func (sc *SnowthClient) GraphiteFindTags(accountID int64,
prefix, query string, options *GraphiteOptions,
nodes ...*SnowthNode) ([]GraphiteMetric, error) {
return sc.GraphiteFindTagsContext(context.Background(), accountID,
prefix, query, options, nodes...)
}

// GraphiteFindTagsContext is the context aware version of
// GraphiteFindTags.
func (sc *SnowthClient) GraphiteFindTagsContext(ctx context.Context,
accountID int64, prefix, query string, options *GraphiteOptions,
nodes ...*SnowthNode) ([]GraphiteMetric, error) {
var node *SnowthNode
if len(nodes) > 0 && nodes[0] != nil {
node = nodes[0]
} else {
node = sc.GetActiveNode()
}

u := fmt.Sprintf("%s?query=%s",
sc.getURL(node, fmt.Sprintf("/graphite/%d/%s/tags/find",
accountID, url.QueryEscape(prefix))), url.QueryEscape(query))

hdrs := http.Header{}
if options != nil && options.Limit != 0 {
hdrs.Set("X-Snowth-Advisory-Limit",
strconv.FormatInt(options.Limit, 10))
}

body, _, err := sc.DoRequestContext(ctx, node, "GET", u, nil, hdrs)
if err != nil {
return nil, err
}

r := []GraphiteMetric{}
if err := decodeJSON(body, &r); err != nil {
return nil, fmt.Errorf("unable to decode IRONdb response: %w", err)
}

return r, nil
}

// GraphiteGetDatapoints retrieves graphite datapoint series for specified
// metrics for a specified time range.
func (sc *SnowthClient) GraphiteGetDatapoints(accountID int64,
prefix string, lookup *GraphiteLookup, options *GraphiteOptions,
nodes ...*SnowthNode) (*GraphiteDatapoints, error) {
return sc.GraphiteGetDatapointsContext(context.Background(), accountID,
prefix, lookup, options, nodes...)
}

// GraphiteGetDatapointsContext is the context aware version of
// GraphiteGetDatapoints.
func (sc *SnowthClient) GraphiteGetDatapointsContext(ctx context.Context,
accountID int64, prefix string, lookup *GraphiteLookup,
options *GraphiteOptions,
nodes ...*SnowthNode) (*GraphiteDatapoints, error) {
var node *SnowthNode
if len(nodes) > 0 && nodes[0] != nil {
node = nodes[0]
} else {
node = sc.GetActiveNode()
}

u := sc.getURL(node, fmt.Sprintf("/graphite/%d/%s/series_multi",
accountID, url.QueryEscape(prefix)))

buf := &bytes.Buffer{}
if err := json.NewEncoder(buf).Encode(&lookup); err != nil {
return nil, err
}

hdrs := http.Header{"Content-Type": {"application/json"}}
if options != nil && options.Limit != 0 {
hdrs.Set("X-Snowth-Advisory-Limit",
strconv.FormatInt(options.Limit, 10))
}

body, _, err := sc.DoRequestContext(ctx, node, "POST", u, buf, hdrs)
if err != nil {
return nil, err
}

r := &GraphiteDatapoints{}
if err := decodeJSON(body, &r); err != nil {
return nil, fmt.Errorf("unable to decode IRONdb response: %w", err)
}

return r, nil
}
Loading

0 comments on commit cb6483a

Please sign in to comment.