diff --git a/Makefile b/Makefile index 0817c00..e613252 100644 --- a/Makefile +++ b/Makefile @@ -13,4 +13,4 @@ goreleaser: clean # test components of plugin/gcp testgcp: - go test -v ./plugin/gcp \ No newline at end of file + go test -v ./plugin/gcp -count=1 \ No newline at end of file diff --git a/plugin/gcp/README.md b/plugin/gcp/README.md index 18403e9..89618d0 100644 --- a/plugin/gcp/README.md +++ b/plugin/gcp/README.md @@ -15,22 +15,21 @@ - - TODO: - Metrics Client - Close metrics client - Metrics to collect: - - "CPUUtilization", + - "CPUUtilization" ~> `compute.googleapis.com/instance/cpu/utilization` - - "NetworkIn", - - "NetworkOut", + - "NetworkIn" ~> `compute.googleapis.com/instance/network/received_bytes_count` + - "NetworkOut" ~> `compute.googleapis.com/instance/network/sent_bytes_count` - - "mem_used_percent", + - "mem_used_percent" ~> `compute.googleapis.com/instance/memory/balloon/ram_size`/`compute.googleapis.com/instance/memory/balloon/ram_used` - - "VolumeReadBytes", - - "VolumeWriteBytes", + - "VolumeReadBytes" ~> `compute.googleapis.com/instance/disk/read_bytes_count` + - "VolumeWriteBytes" ~> `compute.googleapis.com/instance/disk/write_bytes_count` - - "VolumeReadOps", - - "VolumeWriteOps", \ No newline at end of file + - "VolumeReadOps" ~> `compute.googleapis.com/instance/disk/read_ops_count` + - "VolumeWriteOps" ~> `compute.googleapis.com/instance/disk/write_ops_count` \ No newline at end of file diff --git a/plugin/gcp/metrics.go b/plugin/gcp/metrics.go new file mode 100644 index 0000000..9790a15 --- /dev/null +++ b/plugin/gcp/metrics.go @@ -0,0 +1,89 @@ +package gcp + +import ( + "context" + "fmt" + "time" + + monitoring "cloud.google.com/go/monitoring/apiv3/v2" + "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +type CloudMonitoring struct { + client *monitoring.MetricClient + GCP +} + +func NewCloudMonitoring(scopes []string) *CloudMonitoring { + return &CloudMonitoring{ + GCP: NewGCP(scopes), + } +} + +func (c *CloudMonitoring) InitializeClient(ctx context.Context) error { + + c.GCP.GetCredentials(ctx) + + metricClient, err := monitoring.NewMetricClient(ctx) + if err != nil { + return err + } + + c.client = metricClient + + return nil +} + +func (c *CloudMonitoring) CloseClient() error { + err := c.client.Close() + if err != nil { + return err + } + return nil +} + +func (c *CloudMonitoring) NewInstanceMetricRequest( + metricName string, // fully qualified name of the metric + instanceID string, // compute instance ID + startTime time.Time, // start time of requested time series + endTime time.Time, // end time of requested time series + periodInSeconds int64, // period, for which the datapoints will be aggregated into one, in seconds +) *monitoringpb.ListTimeSeriesRequest { + + request := &monitoringpb.ListTimeSeriesRequest{ + Name: fmt.Sprintf("projects/%s", c.ProjectID), + Filter: fmt.Sprintf( + `metric.type="%s" AND resource.labels.instance_id="%s"`, + metricName, + instanceID, + ), + Interval: &monitoringpb.TimeInterval{ + EndTime: timestamppb.New(endTime), + StartTime: timestamppb.New(startTime), + }, + Aggregation: &monitoringpb.Aggregation{ + AlignmentPeriod: &durationpb.Duration{ + Seconds: periodInSeconds, + }, + PerSeriesAligner: monitoringpb.Aggregation_ALIGN_MEAN, // will represent all the datapoints in the above period, with a mean + }, + View: monitoringpb.ListTimeSeriesRequest_FULL, + } + + return request +} + +func (c *CloudMonitoring) GetMetric(request *monitoringpb.ListTimeSeriesRequest) *monitoringpb.TimeSeries { + + it := c.client.ListTimeSeries(context.Background(), request) + + resp, err := it.Next() + if err != nil { + panic(err) + } + + return resp + +} diff --git a/plugin/gcp/metrics_test.go b/plugin/gcp/metrics_test.go new file mode 100644 index 0000000..37a6244 --- /dev/null +++ b/plugin/gcp/metrics_test.go @@ -0,0 +1,55 @@ +package gcp + +import ( + "context" + "log" + "os" + "testing" + "time" +) + +// run this test as +// +// `TEST_INSTANCE_ID="" make testgcp` +func TestGetMetrics(t *testing.T) { + + //test variables + id := os.Getenv("TEST_INSTANCE_ID") + endtime := time.Now() + starttime := endtime.Add(-24 * 1 * time.Hour) // 24 hours before current time + + log.Printf("running %s", t.Name()) + + // creating and initializing client + metric := NewCloudMonitoring( + []string{ + "https://www.googleapis.com/auth/monitoring.read", + }, + ) + err := metric.InitializeClient(context.Background()) + if err != nil { + t.Errorf("[%s]: %s", t.Name(), err.Error()) + } + + // creating the metric request for the instance + request := metric.NewInstanceMetricRequest( + "compute.googleapis.com/instance/cpu/utilization", + id, + starttime, + endtime, + 60, + ) + + // execute the request + resp := metric.GetMetric(request) + + log.Printf("metrics: %s", resp.GetMetric().String()) + log.Printf("resource: %s", resp.GetResource().String()) + log.Printf("# of points: %d", len(resp.Points)) + + // for _, point := range resp.Points { + // log.Printf("Point : %.10f", point.GetValue().GetDoubleValue()) + // } + + metric.CloseClient() +}