Merge pull request #14562 from wchrisjohnson/cj-add-librato-metrics

provider/librato: Enable mgmt of Librato metrics
This commit is contained in:
Jake Champlin 2017-05-26 11:14:43 -04:00 committed by GitHub
commit 840f974853
7 changed files with 728 additions and 9 deletions

View File

@ -0,0 +1,14 @@
package librato
import (
"log"
"testing"
"time"
)
func sleep(t *testing.T, amount time.Duration) func() {
return func() {
log.Printf("[INFO] Sleeping for %d seconds...", amount)
time.Sleep(amount * time.Second)
}
}

View File

@ -28,6 +28,7 @@ func Provider() terraform.ResourceProvider {
ResourcesMap: map[string]*schema.Resource{ ResourcesMap: map[string]*schema.Resource{
"librato_space": resourceLibratoSpace(), "librato_space": resourceLibratoSpace(),
"librato_space_chart": resourceLibratoSpaceChart(), "librato_space_chart": resourceLibratoSpaceChart(),
"librato_metric": resourceLibratoMetric(),
"librato_alert": resourceLibratoAlert(), "librato_alert": resourceLibratoAlert(),
"librato_service": resourceLibratoService(), "librato_service": resourceLibratoService(),
}, },

View File

@ -0,0 +1,388 @@
package librato
import (
"encoding/json"
"fmt"
"log"
"time"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/henrikhodne/go-librato/librato"
)
func resourceLibratoMetric() *schema.Resource {
return &schema.Resource{
Create: resourceLibratoMetricCreate,
Read: resourceLibratoMetricRead,
Update: resourceLibratoMetricUpdate,
Delete: resourceLibratoMetricDelete,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: false,
},
"type": {
Type: schema.TypeString,
Required: true,
},
"display_name": {
Type: schema.TypeString,
Optional: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
},
"period": {
Type: schema.TypeInt,
Optional: true,
},
"composite": {
Type: schema.TypeString,
Optional: true,
},
"attributes": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"color": {
Type: schema.TypeString,
Optional: true,
},
"display_max": {
Type: schema.TypeString,
Optional: true,
},
"display_min": {
Type: schema.TypeString,
Optional: true,
},
"display_units_long": {
Type: schema.TypeString,
Optional: true,
},
"display_units_short": {
Type: schema.TypeString,
Optional: true,
},
"display_stacked": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"created_by_ua": {
Type: schema.TypeString,
Computed: true,
},
"gap_detection": {
Type: schema.TypeBool,
Optional: true,
},
"aggregate": {
Type: schema.TypeBool,
Optional: true,
},
},
},
},
},
}
}
func resourceLibratoMetricCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*librato.Client)
metric := librato.Metric{
Name: librato.String(d.Get("name").(string)),
Type: librato.String(d.Get("type").(string)),
}
if a, ok := d.GetOk("display_name"); ok {
metric.DisplayName = librato.String(a.(string))
}
if a, ok := d.GetOk("description"); ok {
metric.Description = librato.String(a.(string))
}
if a, ok := d.GetOk("period"); ok {
metric.Period = librato.Uint(uint(a.(int)))
}
if a, ok := d.GetOk("composite"); ok {
metric.Composite = librato.String(a.(string))
}
if a, ok := d.GetOk("attributes"); ok {
attributeData := a.([]interface{})
attributeDataMap := attributeData[0].(map[string]interface{})
attributes := new(librato.MetricAttributes)
if v, ok := attributeDataMap["color"].(string); ok && v != "" {
attributes.Color = librato.String(v)
}
if v, ok := attributeDataMap["display_max"].(string); ok && v != "" {
attributes.DisplayMax = librato.String(v)
}
if v, ok := attributeDataMap["display_min"].(string); ok && v != "" {
attributes.DisplayMin = librato.String(v)
}
if v, ok := attributeDataMap["display_units_long"].(string); ok && v != "" {
attributes.DisplayUnitsLong = *librato.String(v)
}
if v, ok := attributeDataMap["display_units_short"].(string); ok && v != "" {
attributes.DisplayUnitsShort = *librato.String(v)
}
if v, ok := attributeDataMap["created_by_ua"].(string); ok && v != "" {
attributes.CreatedByUA = *librato.String(v)
}
if v, ok := attributeDataMap["display_stacked"].(bool); ok {
attributes.DisplayStacked = *librato.Bool(v)
}
if v, ok := attributeDataMap["gap_detection"].(bool); ok {
attributes.GapDetection = *librato.Bool(v)
}
if v, ok := attributeDataMap["aggregate"].(bool); ok {
attributes.Aggregate = *librato.Bool(v)
}
metric.Attributes = attributes
}
_, err := client.Metrics.Edit(&metric)
if err != nil {
log.Printf("[INFO] ERROR creating Metric: %s", err)
return fmt.Errorf("Error creating Librato metric: %s", err)
}
retryErr := resource.Retry(1*time.Minute, func() *resource.RetryError {
_, _, err := client.Metrics.Get(*metric.Name)
if err != nil {
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
if retryErr != nil {
return fmt.Errorf("Error creating Librato metric: %s", retryErr)
}
d.SetId(*metric.Name)
return resourceLibratoMetricRead(d, meta)
}
func resourceLibratoMetricRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*librato.Client)
id := d.Id()
log.Printf("[INFO] Reading Librato Metric: %s", id)
metric, _, err := client.Metrics.Get(id)
if err != nil {
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
d.SetId("")
return nil
}
return fmt.Errorf("Error reading Librato Metric %s: %s", id, err)
}
d.Set("name", metric.Name)
d.Set("type", metric.Type)
if metric.Description != nil {
d.Set("description", metric.Description)
}
if metric.DisplayName != nil {
d.Set("display_name", metric.DisplayName)
}
if metric.Period != nil {
d.Set("period", metric.Period)
}
if metric.Composite != nil {
d.Set("composite", metric.Composite)
}
attributes := metricAttributesGather(d, metric.Attributes)
// Since attributes isn't a simple terraform type (TypeList), it's best to
// catch the error returned from the d.Set() function, and handle accordingly.
if err := d.Set("attributes", attributes); err != nil {
return err
}
return nil
}
func resourceLibratoMetricUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*librato.Client)
id := d.Id()
metric := new(librato.Metric)
metric.Name = librato.String(id)
if d.HasChange("type") {
metric.Type = librato.String(d.Get("type").(string))
}
if d.HasChange("description") {
metric.Description = librato.String(d.Get("description").(string))
}
if d.HasChange("display_name") {
metric.DisplayName = librato.String(d.Get("display_name").(string))
}
if d.HasChange("period") {
metric.Period = librato.Uint(uint(d.Get("period").(int)))
}
if d.HasChange("composite") {
metric.Composite = librato.String(d.Get("composite").(string))
}
if d.HasChange("attributes") {
attributeData := d.Get("attributes").([]interface{})
attributeDataMap := attributeData[0].(map[string]interface{})
attributes := new(librato.MetricAttributes)
if v, ok := attributeDataMap["color"].(string); ok && v != "" {
attributes.Color = librato.String(v)
}
if v, ok := attributeDataMap["display_max"].(string); ok && v != "" {
attributes.DisplayMax = librato.String(v)
}
if v, ok := attributeDataMap["display_min"].(string); ok && v != "" {
attributes.DisplayMin = librato.String(v)
}
if v, ok := attributeDataMap["display_units_long"].(string); ok && v != "" {
attributes.DisplayUnitsLong = *librato.String(v)
}
if v, ok := attributeDataMap["display_units_short"].(string); ok && v != "" {
attributes.DisplayUnitsShort = *librato.String(v)
}
if v, ok := attributeDataMap["created_by_ua"].(string); ok && v != "" {
attributes.CreatedByUA = *librato.String(v)
}
if v, ok := attributeDataMap["display_stacked"].(bool); ok {
attributes.DisplayStacked = *librato.Bool(v)
}
if v, ok := attributeDataMap["gap_detection"].(bool); ok {
attributes.GapDetection = *librato.Bool(v)
}
if v, ok := attributeDataMap["aggregate"].(bool); ok {
attributes.Aggregate = *librato.Bool(v)
}
metric.Attributes = attributes
}
log.Printf("[INFO] Updating Librato metric: %v", structToString(metric))
_, err := client.Metrics.Edit(metric)
if err != nil {
return fmt.Errorf("Error updating Librato metric: %s", err)
}
log.Printf("[INFO] Updated Librato metric %s", id)
// Wait for propagation since Librato updates are eventually consistent
wait := resource.StateChangeConf{
Pending: []string{fmt.Sprintf("%t", false)},
Target: []string{fmt.Sprintf("%t", true)},
Timeout: 5 * time.Minute,
MinTimeout: 2 * time.Second,
ContinuousTargetOccurence: 5,
Refresh: func() (interface{}, string, error) {
log.Printf("[INFO] Checking if Librato Metric %s was updated yet", id)
changedMetric, _, getErr := client.Metrics.Get(id)
if getErr != nil {
return changedMetric, "", getErr
}
return changedMetric, "true", nil
},
}
_, err = wait.WaitForState()
if err != nil {
log.Printf("[INFO] ERROR - Failed updating Librato Metric %s: %s", id, err)
return fmt.Errorf("Failed updating Librato Metric %s: %s", id, err)
}
return resourceLibratoMetricRead(d, meta)
}
func resourceLibratoMetricDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*librato.Client)
id := d.Id()
log.Printf("[INFO] Deleting Metric: %s", id)
_, err := client.Metrics.Delete(id)
if err != nil {
return fmt.Errorf("Error deleting Metric: %s", err)
}
log.Printf("[INFO] Verifying Metric %s deleted", id)
retryErr := resource.Retry(1*time.Minute, func() *resource.RetryError {
log.Printf("[INFO] Getting Metric %s", id)
_, _, err := client.Metrics.Get(id)
if err != nil {
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
log.Printf("[INFO] Metric %s not found, removing from state", id)
return nil
}
log.Printf("[INFO] non-retryable error attempting to Get metric: %s", err)
return resource.NonRetryableError(err)
}
log.Printf("[INFO] retryable error attempting to Get metric: %s", id)
return resource.RetryableError(fmt.Errorf("metric still exists"))
})
if retryErr != nil {
return fmt.Errorf("Error deleting librato metric: %s", retryErr)
}
return nil
}
// Flattens an attributes hash into something that flatmap.Flatten() can handle
func metricAttributesGather(d *schema.ResourceData, attributes *librato.MetricAttributes) []map[string]interface{} {
result := make([]map[string]interface{}, 0, 1)
if attributes != nil {
retAttributes := make(map[string]interface{})
if attributes.Color != nil {
retAttributes["color"] = *attributes.Color
}
if attributes.DisplayMax != nil {
retAttributes["display_max"] = attributes.DisplayMax
}
if attributes.DisplayMin != nil {
retAttributes["display_min"] = attributes.DisplayMin
}
if attributes.DisplayUnitsLong != "" {
retAttributes["display_units_long"] = attributes.DisplayUnitsLong
}
if attributes.DisplayUnitsShort != "" {
retAttributes["display_units_short"] = attributes.DisplayUnitsShort
}
if attributes.CreatedByUA != "" {
retAttributes["created_by_ua"] = attributes.CreatedByUA
}
retAttributes["display_stacked"] = attributes.DisplayStacked || false
retAttributes["gap_detection"] = attributes.GapDetection || false
retAttributes["aggregate"] = attributes.Aggregate || false
result = append(result, retAttributes)
}
return result
}
func structToString(i interface{}) string {
s, _ := json.Marshal(i)
return string(s)
}

View File

@ -0,0 +1,232 @@
package librato
import (
"fmt"
"strings"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/henrikhodne/go-librato/librato"
)
func TestAccLibratoMetrics(t *testing.T) {
var metric librato.Metric
name := fmt.Sprintf("tftest-metric-%s", acctest.RandString(10))
typ := "counter"
desc1 := fmt.Sprintf("A test %s metric", typ)
desc2 := fmt.Sprintf("An updated test %s metric", typ)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibratoMetricDestroy,
Steps: []resource.TestStep{
{
Config: counterMetricConfig(name, typ, desc1),
Check: resource.ComposeTestCheckFunc(
testAccCheckLibratoMetricExists("librato_metric.foobar", &metric),
testAccCheckLibratoMetricName(&metric, name),
testAccCheckLibratoMetricType(&metric, typ),
resource.TestCheckResourceAttr(
"librato_metric.foobar", "name", name),
),
},
{
PreConfig: sleep(t, 5),
Config: counterMetricConfig(name, typ, desc2),
Check: resource.ComposeTestCheckFunc(
testAccCheckLibratoMetricExists("librato_metric.foobar", &metric),
testAccCheckLibratoMetricName(&metric, name),
testAccCheckLibratoMetricType(&metric, typ),
testAccCheckLibratoMetricDescription(&metric, desc2),
resource.TestCheckResourceAttr(
"librato_metric.foobar", "name", name),
),
},
},
})
name = fmt.Sprintf("tftest-metric-%s", acctest.RandString(10))
typ = "gauge"
desc1 = fmt.Sprintf("A test %s metric", typ)
desc2 = fmt.Sprintf("An updated test %s metric", typ)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibratoMetricDestroy,
Steps: []resource.TestStep{
{
Config: gaugeMetricConfig(name, typ, desc1),
Check: resource.ComposeTestCheckFunc(
testAccCheckLibratoMetricExists("librato_metric.foobar", &metric),
testAccCheckLibratoMetricName(&metric, name),
testAccCheckLibratoMetricType(&metric, typ),
resource.TestCheckResourceAttr(
"librato_metric.foobar", "name", name),
),
},
{
PreConfig: sleep(t, 5),
Config: gaugeMetricConfig(name, typ, desc2),
Check: resource.ComposeTestCheckFunc(
testAccCheckLibratoMetricExists("librato_metric.foobar", &metric),
testAccCheckLibratoMetricName(&metric, name),
testAccCheckLibratoMetricType(&metric, typ),
testAccCheckLibratoMetricDescription(&metric, desc2),
resource.TestCheckResourceAttr(
"librato_metric.foobar", "name", name),
),
},
},
})
name = fmt.Sprintf("tftest-metric-%s", acctest.RandString(10))
typ = "composite"
desc1 = fmt.Sprintf("A test %s metric", typ)
desc2 = fmt.Sprintf("An updated test %s metric", typ)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibratoMetricDestroy,
Steps: []resource.TestStep{
{
Config: compositeMetricConfig(name, typ, desc1),
Check: resource.ComposeTestCheckFunc(
testAccCheckLibratoMetricExists("librato_metric.foobar", &metric),
testAccCheckLibratoMetricName(&metric, name),
testAccCheckLibratoMetricType(&metric, typ),
resource.TestCheckResourceAttr(
"librato_metric.foobar", "name", name),
),
},
{
PreConfig: sleep(t, 5),
Config: compositeMetricConfig(name, typ, desc2),
Check: resource.ComposeTestCheckFunc(
testAccCheckLibratoMetricExists("librato_metric.foobar", &metric),
testAccCheckLibratoMetricName(&metric, name),
testAccCheckLibratoMetricType(&metric, typ),
testAccCheckLibratoMetricDescription(&metric, desc2),
resource.TestCheckResourceAttr(
"librato_metric.foobar", "name", name),
),
},
},
})
}
func testAccCheckLibratoMetricDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*librato.Client)
for _, rs := range s.RootModule().Resources {
if rs.Type != "librato_metric" {
continue
}
_, _, err := client.Metrics.Get(rs.Primary.ID)
if err == nil {
return fmt.Errorf("Metric still exists")
}
}
return nil
}
func testAccCheckLibratoMetricName(metric *librato.Metric, name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
if metric.Name == nil || *metric.Name != name {
return fmt.Errorf("Bad name: %s", *metric.Name)
}
return nil
}
}
func testAccCheckLibratoMetricDescription(metric *librato.Metric, desc string) resource.TestCheckFunc {
return func(s *terraform.State) error {
if metric.Description == nil || *metric.Description != desc {
return fmt.Errorf("Bad description: %s", *metric.Description)
}
return nil
}
}
func testAccCheckLibratoMetricType(metric *librato.Metric, wantType string) resource.TestCheckFunc {
return func(s *terraform.State) error {
if metric.Type == nil || *metric.Type != wantType {
return fmt.Errorf("Bad metric type: %s", *metric.Type)
}
return nil
}
}
func testAccCheckLibratoMetricExists(n string, metric *librato.Metric) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No Metric ID is set")
}
client := testAccProvider.Meta().(*librato.Client)
foundMetric, _, err := client.Metrics.Get(rs.Primary.ID)
if err != nil {
return err
}
if foundMetric.Name == nil || *foundMetric.Name != rs.Primary.ID {
return fmt.Errorf("Metric not found")
}
*metric = *foundMetric
return nil
}
}
func counterMetricConfig(name, typ, desc string) string {
return strings.TrimSpace(fmt.Sprintf(`
resource "librato_metric" "foobar" {
name = "%s"
type = "%s"
description = "%s"
attributes {
display_stacked = true
}
}`, name, typ, desc))
}
func gaugeMetricConfig(name, typ, desc string) string {
return strings.TrimSpace(fmt.Sprintf(`
resource "librato_metric" "foobar" {
name = "%s"
type = "%s"
description = "%s"
attributes {
display_stacked = true
}
}`, name, typ, desc))
}
func compositeMetricConfig(name, typ, desc string) string {
return strings.TrimSpace(fmt.Sprintf(`
resource "librato_metric" "foobar" {
name = "%s"
type = "%s"
description = "%s"
composite = "s(\"librato.cpu.percent.user\", {\"environment\" : \"prod\", \"service\": \"api\"})"
attributes {
display_stacked = true
}
}`, name, typ, desc))
}

View File

@ -14,28 +14,37 @@ type MetricsService struct {
// Metric represents a Librato Metric. // Metric represents a Librato Metric.
type Metric struct { type Metric struct {
Name *string `json:"name"` Name *string `json:"name"`
Description *string `json:"description,omitempty"`
Type *string `json:"type"`
Period *uint `json:"period,omitempty"` Period *uint `json:"period,omitempty"`
DisplayName *string `json:"display_name,omitempty"` DisplayName *string `json:"display_name,omitempty"`
Composite *string `json:"composite,omitempty"`
Attributes *MetricAttributes `json:"attributes,omitempty"` Attributes *MetricAttributes `json:"attributes,omitempty"`
} }
// MetricAttributes are named attributes as key:value pairs.
type MetricAttributes struct { type MetricAttributes struct {
Color *string `json:"color"` Color *string `json:"color"`
// These are interface{} because sometimes the Librato API // These are interface{} because sometimes the Librato API
// returns strings, and sometimes it returns integers // returns strings, and sometimes it returns integers
DisplayMax interface{} `json:"display_max"` DisplayMax interface{} `json:"display_max"`
DisplayMin interface{} `json:"display_min"` DisplayMin interface{} `json:"display_min"`
DisplayUnitsLong string `json:"display_units_long"`
DisplayUnitsShort string `json:"display_units_short"` DisplayUnitsShort string `json:"display_units_short"`
DisplayStacked bool `json:"display_stacked"` DisplayStacked bool `json:"display_stacked"`
DisplayTransform string `json:"display_transform"` DisplayTransform string `json:"display_transform"`
CreatedByUA string `json:"created_by_ua,omitempty"`
GapDetection bool `json:"gap_detection,omitempty"`
Aggregate bool `json:"aggregate,omitempty"`
} }
// ListMetricsOptions are used to coordinate paging of metrics.
type ListMetricsOptions struct { type ListMetricsOptions struct {
*PaginationMeta *PaginationMeta
Name string `url:"name,omitempty"` Name string `url:"name,omitempty"`
} }
// Advance to the specified page in result set, while retaining // AdvancePage advances to the specified page in result set, while retaining
// the filtering options. // the filtering options.
func (l *ListMetricsOptions) AdvancePage(next *PaginationMeta) ListMetricsOptions { func (l *ListMetricsOptions) AdvancePage(next *PaginationMeta) ListMetricsOptions {
return ListMetricsOptions{ return ListMetricsOptions{
@ -44,6 +53,7 @@ func (l *ListMetricsOptions) AdvancePage(next *PaginationMeta) ListMetricsOption
} }
} }
// ListMetricsResponse represents the response of a List call against the metrics service.
type ListMetricsResponse struct { type ListMetricsResponse struct {
ThisPage *PaginationResponseMeta ThisPage *PaginationResponseMeta
NextPage *PaginationMeta NextPage *PaginationMeta
@ -51,7 +61,7 @@ type ListMetricsResponse struct {
// List metrics using the provided options. // List metrics using the provided options.
// //
// Librato API docs: https://www.librato.com/docs/api/#retrieve-metrics // Librato API docs: https://www.librato.com/docs/api/#list-a-subset-of-metrics
func (m *MetricsService) List(opts *ListMetricsOptions) ([]Metric, *ListMetricsResponse, error) { func (m *MetricsService) List(opts *ListMetricsOptions) ([]Metric, *ListMetricsResponse, error) {
u, err := urlWithOptions("metrics", opts) u, err := urlWithOptions("metrics", opts)
if err != nil { if err != nil {
@ -83,7 +93,7 @@ func (m *MetricsService) List(opts *ListMetricsOptions) ([]Metric, *ListMetricsR
// Get a metric by name // Get a metric by name
// //
// Librato API docs: https://www.librato.com/docs/api/#retrieve-metric-by-name // Librato API docs: https://www.librato.com/docs/api/#retrieve-a-metric-by-name
func (m *MetricsService) Get(name string) (*Metric, *http.Response, error) { func (m *MetricsService) Get(name string) (*Metric, *http.Response, error) {
u := fmt.Sprintf("metrics/%s", name) u := fmt.Sprintf("metrics/%s", name)
req, err := m.client.NewRequest("GET", u, nil) req, err := m.client.NewRequest("GET", u, nil)
@ -100,6 +110,7 @@ func (m *MetricsService) Get(name string) (*Metric, *http.Response, error) {
return metric, resp, err return metric, resp, err
} }
// MeasurementSubmission represents the payload to submit/create a metric.
type MeasurementSubmission struct { type MeasurementSubmission struct {
MeasureTime *uint `json:"measure_time,omitempty"` MeasureTime *uint `json:"measure_time,omitempty"`
Source *string `json:"source,omitempty"` Source *string `json:"source,omitempty"`
@ -107,6 +118,7 @@ type MeasurementSubmission struct {
Counters []*Measurement `json:"counters,omitempty"` Counters []*Measurement `json:"counters,omitempty"`
} }
// Measurement represents a Librato Measurement.
type Measurement struct { type Measurement struct {
Name string `json:"name"` Name string `json:"name"`
Value *float64 `json:"value,omitempty"` Value *float64 `json:"value,omitempty"`
@ -114,6 +126,7 @@ type Measurement struct {
Source *string `json:"source,omitempty"` Source *string `json:"source,omitempty"`
} }
// GaugeMeasurement represents a Librato measurement gauge.
type GaugeMeasurement struct { type GaugeMeasurement struct {
*Measurement *Measurement
Count *uint `json:"count,omitempty"` Count *uint `json:"count,omitempty"`
@ -125,7 +138,7 @@ type GaugeMeasurement struct {
// Submit metrics // Submit metrics
// //
// Librato API docs: https://www.librato.com/docs/api/#submit-metrics // Librato API docs: https://www.librato.com/docs/api/#create-a-measurement
func (m *MetricsService) Submit(measurements *MeasurementSubmission) (*http.Response, error) { func (m *MetricsService) Submit(measurements *MeasurementSubmission) (*http.Response, error) {
req, err := m.client.NewRequest("POST", "/metrics", measurements) req, err := m.client.NewRequest("POST", "/metrics", measurements)
if err != nil { if err != nil {
@ -137,7 +150,7 @@ func (m *MetricsService) Submit(measurements *MeasurementSubmission) (*http.Resp
// Edit a metric. // Edit a metric.
// //
// Librato API docs: https://www.librato.com/docs/api/#update-metric-by-name // Librato API docs: https://www.librato.com/docs/api/#update-a-metric-by-name
func (m *MetricsService) Edit(metric *Metric) (*http.Response, error) { func (m *MetricsService) Edit(metric *Metric) (*http.Response, error) {
u := fmt.Sprintf("metrics/%s", *metric.Name) u := fmt.Sprintf("metrics/%s", *metric.Name)
@ -151,7 +164,7 @@ func (m *MetricsService) Edit(metric *Metric) (*http.Response, error) {
// Delete a metric. // Delete a metric.
// //
// Librato API docs: https://www.librato.com/docs/api/#delete-metric-by-name // Librato API docs: https://www.librato.com/docs/api/#delete-a-metric-by-name
func (m *MetricsService) Delete(name string) (*http.Response, error) { func (m *MetricsService) Delete(name string) (*http.Response, error) {
u := fmt.Sprintf("metrics/%s", name) u := fmt.Sprintf("metrics/%s", name)
req, err := m.client.NewRequest("DELETE", u, nil) req, err := m.client.NewRequest("DELETE", u, nil)

6
vendor/vendor.json vendored
View File

@ -2248,10 +2248,10 @@
"revisionTime": "2016-07-20T23:31:40Z" "revisionTime": "2016-07-20T23:31:40Z"
}, },
{ {
"checksumSHA1": "jq2E42bB0kwKaerHXwJslUea4eM=", "checksumSHA1": "HtxHX0u0oN+aiTN1Pd67Y4ilMdI=",
"path": "github.com/henrikhodne/go-librato/librato", "path": "github.com/henrikhodne/go-librato/librato",
"revision": "6e9aa4b1a8a8b735ad14b4f1c9542ef183e82dc2", "revision": "1bca649ee479cdfcf2e19f30ecb74b6f23345e5a",
"revisionTime": "2016-08-11T07:26:26Z" "revisionTime": "2017-05-13T14:06:44Z"
}, },
{ {
"checksumSHA1": "K6exl2ouL7d8cR2i378EzZOdRVI=", "checksumSHA1": "K6exl2ouL7d8cR2i378EzZOdRVI=",

View File

@ -0,0 +1,71 @@
---
layout: "librato"
page_title: "Librato: librato_metric"
sidebar_current: "docs-librato-resource-metric"
description: |-
Provides a Librato Metric resource. This can be used to create and manage metrics on Librato.
---
# librato\_metric
Provides a Librato Metric resource. This can be used to create and manage metrics on Librato.
## Example Usage
```hcl
# Create a new Librato metric
resource "librato_metric" "mymetric" {
name = "MyMetric"
type = "counter"
description = "A Test Metric"
attributes {
display_stacked = true
}
}
```
## Argument Reference
The following arguments are supported:
* `type` - (Required) The type of metric to create (gauge, counter, or composite).
* `name` - (Required) The unique identifier of the metric.
* `display_name` - The name which will be used for the metric when viewing the Metrics website.
* `description` - Text that can be used to explain precisely what the metric is measuring.
* `period` - Number of seconds that is the standard reporting period of the metric.
* `attributes` - The attributes hash configures specific components of a metrics visualization.
* `composite` - The definition of the composite metric.
## Attributes Reference
The following attributes are exported:
* `name` - The identifier for the metric.
* `display_name` - The name which will be used for the metric when viewing the Metrics website.
* `type` - The type of metric to create (gauge, counter, or composite).
* `description` - Text that describes precisely what the metric is measuring.
* `period` - Number of seconds that is the standard reporting period of the metric. Setting the period enables Metrics to detect abnormal interruptions in reporting and aids in analytics. For gauge metrics that have service-side aggregation enabled, this option will define the period that aggregation occurs on.
* `source_lag` -
* `composite` - The composite definition. Only used when type is composite.
Attributes (`attributes`) support the following:
* `color` - Sets a default color to prefer when visually rendering the metric. Must be a seven character string that represents the hex code of the color e.g. #52D74C.
* `display_max` - If a metric has a known theoretical maximum value, set display_max so that visualizations can provide perspective of the current values relative to the maximum value.
* `display_min` - If a metric has a known theoretical minimum value, set display_min so that visualizations can provide perspective of the current values relative to the minimum value.
* `display_units_long` - A string that identifies the unit of measurement e.g. Microseconds. Typically the long form of display_units_short and used in visualizations e.g. the Y-axis label on a graph.
* `display_units_short` - A terse (usually abbreviated) string that identifies the unit of measurement e.g. uS (Microseconds). Typically the short form of display_units_long and used in visualizations e.g. the tooltip for a point on a graph.
* `display_stacked` - A boolean value indicating whether or not multiple metric streams should be aggregated in a visualization (e.g. stacked graphs). By default counters have display_stacked enabled while gauges have it disabled.
* `summarize_function` - Determines how to calculate values when rolling up from raw values to higher resolution intervals. Must be one of: average, 'sum, 'count, 'min, 'max. If summarize_function is not set the behavior defaults to average.
If the values of the measurements to be rolled up are: 2, 10, 5:
* average: 5.67
* sum: 17
* count: 3
* min: 2
* max: 10
* `aggregate` - Enable service-side aggregation for this metric. When enabled, measurements sent using the same tag set will be aggregated into single measurements on an interval defined by the period of the metric. If there is no period defined for the metric then all measurements will be aggregated on a 60-second interval.
This option takes a value of true or false. If this option is not set for a metric it will default to false.