Skip to content

Commit

Permalink
Add resource type and resource label support to stackdriver output (i…
Browse files Browse the repository at this point in the history
  • Loading branch information
Legogris authored and Mathieu Lecarme committed Apr 17, 2020
1 parent 10653ac commit 9963e76
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 10 deletions.
13 changes: 13 additions & 0 deletions plugins/outputs/stackdriver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ Requires `project` to specify where Stackdriver metrics will be delivered to.

Metrics are grouped by the `namespace` variable and metric key - eg: `custom.googleapis.com/telegraf/system/load5`

[Resource type](https://cloud.google.com/monitoring/api/resources) is configured by the `resource_type` variable (default `global`).

Additional resource labels can be configured by `resource_labels`. By default the required `project_id` label is always set to the `project` variable.

### Configuration

```toml
Expand All @@ -16,6 +20,15 @@ Metrics are grouped by the `namespace` variable and metric key - eg: `custom.goo

# The namespace for the metric descriptor
namespace = "telegraf"

# Custom resource type
resource_type = "generic_node"

# Additonal resource labels
[outputs.stackdriver.resource_labels]
node_id = "$HOSTNAME"
namespace = "myapp"
location = "eu-north0"
```

### Restrictions
Expand Down
40 changes: 30 additions & 10 deletions plugins/outputs/stackdriver/stackdriver.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import (

// Stackdriver is the Google Stackdriver config info.
type Stackdriver struct {
Project string
Namespace string
Project string
Namespace string
ResourceType string `toml:"resource_type"`
ResourceLabels map[string]string `toml:"resource_labels"`

client *monitoring.MetricClient
}
Expand All @@ -47,11 +49,21 @@ const (
)

var sampleConfig = `
# GCP Project
project = "erudite-bloom-151019"
[[outputs.stackdriver]]
# GCP Project
project = "erudite-bloom-151019"
# The namespace for the metric descriptor
namespace = "telegraf"
# The namespace for the metric descriptor
namespace = "telegraf"
# Custom resource type
resource_type = "generic_node"
# Additonal resource labels
[outputs.stackdriver.resource_labels]
node_id = "$HOSTNAME"
namespace = "myapp"
location = "eu-north0"
`

// Connect initiates the primary connection to the GCP project.
Expand All @@ -64,6 +76,16 @@ func (s *Stackdriver) Connect() error {
return fmt.Errorf("Namespace is a required field for stackdriver output")
}

if s.ResourceType == "" {
s.ResourceType = "global"
}

if s.ResourceLabels == nil {
s.ResourceLabels = make(map[string]string, 1)
}

s.ResourceLabels["project_id"] = s.Project

if s.client == nil {
ctx := context.Background()
client, err := monitoring.NewMetricClient(ctx)
Expand Down Expand Up @@ -137,10 +159,8 @@ func (s *Stackdriver) Write(metrics []telegraf.Metric) error {
},
MetricKind: metricKind,
Resource: &monitoredrespb.MonitoredResource{
Type: "global",
Labels: map[string]string{
"project_id": s.Project,
},
Type: s.ResourceType,
Labels: s.ResourceLabels,
},
Points: []*monitoringpb.Point{
dataPoint,
Expand Down
36 changes: 36 additions & 0 deletions plugins/outputs/stackdriver/stackdriver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,42 @@ func TestWrite(t *testing.T) {
require.NoError(t, err)
err = s.Write(testutil.MockMetrics())
require.NoError(t, err)

request := mockMetric.reqs[0].(*monitoringpb.CreateTimeSeriesRequest)
require.Equal(t, request.TimeSeries[0].Resource.Type, "global")
require.Equal(t, request.TimeSeries[0].Resource.Labels["project_id"], "projects/[PROJECT]")
}

func TestWriteResourceTypeAndLabels(t *testing.T) {
expectedResponse := &emptypb.Empty{}
mockMetric.err = nil
mockMetric.reqs = nil
mockMetric.resps = append(mockMetric.resps[:0], expectedResponse)

c, err := monitoring.NewMetricClient(context.Background(), clientOpt)
if err != nil {
t.Fatal(err)
}

s := &Stackdriver{
Project: fmt.Sprintf("projects/%s", "[PROJECT]"),
Namespace: "test",
ResourceType: "foo",
ResourceLabels: map[string]string{
"mylabel": "myvalue",
},
client: c,
}

err = s.Connect()
require.NoError(t, err)
err = s.Write(testutil.MockMetrics())
require.NoError(t, err)

request := mockMetric.reqs[0].(*monitoringpb.CreateTimeSeriesRequest)
require.Equal(t, request.TimeSeries[0].Resource.Type, "foo")
require.Equal(t, request.TimeSeries[0].Resource.Labels["project_id"], "projects/[PROJECT]")
require.Equal(t, request.TimeSeries[0].Resource.Labels["mylabel"], "myvalue")
}

func TestWriteAscendingTime(t *testing.T) {
Expand Down

0 comments on commit 9963e76

Please sign in to comment.