概要
GCPの監視を行うため、StackDriver
から値を取得し
しきい値を超えていないかチェックする Nagios 用のプラグインをGolnag
で作成しました。
https://github.com/yuukichi-nankou/check-stackdriver-go
その際、苦戦したので Golang
で StackDriver Monitoring API
から値を取得する方法をまとめます。
つい先日、StackDriverが管理コンソールに統合されました。
https://cloud.google.com/blog/products/management-tools/cloud-monitoring-dashboards-using-an-api
それに伴い、管理画面では単に Monitoring という名称になっていますが、
本記事では StackDriver Monitoring と記載しています。
StackDriverからSDKを使って値を取得する
StackDriver
は、GCPコンソール上で収集したメトリックやログの閲覧
しきい値を指定したアラート通知が可能な監視サービスです。
※ AWSのCloudWatch
のようなイメージです。
今回はStackDriver Monitoring
のデータを取得しました。
StackDriver Monitoring
には GCP上のインスタンス数や、CPU使用率などの
リソース状態が自動で収集されています。
メトリックの一覧
取得できるメトリックの一覧が公式ドキュメントに公開されています。
https://cloud.google.com/monitoring/api/metrics_gcp?hl=ja
今回はCloud Storageバケット内の、ファイル数を取得します。
StackDriver SDK
他のGCPのサービスと同様に、StackDriver
もAPIとそれをプログラムから呼び出すSDKが公開されています。
Golang用のSDKも公開されているので、これを利用します。
データの取得処理
メトリックを指定し、一覧を取得する
以下は、SDKを利用し、Cloud Storage
のメトリックを取得したサンプルです。
フィルタの指定で、メトリックを指定します。
metric.type = storage.googleapis.com/storage/object_count
メトリックデータを取得するサンプル
package main
import (
"fmt"
"os"
monitoring "cloud.google.com/go/monitoring/apiv3"
googlepb "github.com/golang/protobuf/ptypes/timestamp"
"golang.org/x/net/context"
"google.golang.org/api/iterator"
monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
)
func main() {
// StackDriverAPIに接続する際の認証鍵ファイルを指定する
key_path := "./path/to/auth-key.json"
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", key_path)
// GCPのプロジェクト名を指定する
priject_id := "your-project-id"
// フィルタを指定し、取得するデータを絞る
filter_query := "metric.type = storage.googleapis.com/storage/object_count AND resource.type = gcs_bucket "
// 取得期間をunixtimeで指定する
var end_time int64 = 1583766000
var start_time int64 = 1583809200
// リクエストデータを作成する
req := &monitoringpb.ListTimeSeriesRequest{
Name: "projects/" + priject_id,
Filter: filter_query,
Interval: &monitoringpb.TimeInterval{
EndTime: &googlepb.Timestamp{
Seconds: end_time,
},
StartTime: &googlepb.Timestamp{
Seconds: start_time,
},
},
}
ctx := context.Background()
client, _ := monitoring.NewMetricClient(ctx)
it := client.ListTimeSeries(ctx, req)
for {
resp, err := it.Next()
if err == iterator.Done {
break
}
fmt.Println(resp)
}
}
また以下が、実際にサンプルコードを実行した結果です。
サンプルの実行結果
$ go run sample/sample.go
metric:<type:"storage.googleapis.com/storage/object_count" labels:<key:"storage_class" value:"MULTI_REGIONAL" > > resource:<type:"gcs_bucket" labels:<key:"bucket_name" value:"asia.artifacts.hogehoge-bucket.appspot.com" > labels:<key:"location" value:"asia" > labels:<key:"project_id" value:"hogehoge-bucket" > > metric_kind:GAUGE value_type:INT64 points:<interval:<end_time:<seconds:1583841600 > start_time:<seconds:1583841600 > > value:<int64_value:76 > >
metric:<type:"storage.googleapis.com/storage/object_count" labels:<key:"storage_class" value:"REGIONAL" > > resource:<type:"gcs_bucket" labels:<key:"bucket_name" value:"hogehoge-bucket" > labels:<key:"location" value:"asia-northeast2" > labels:<key:"project_id" value:"hogehoge-bucket" > > metric_kind:GAUGE value_type:INT64 points:<interval:<end_time:<seconds:1583841600 > start_time:<seconds:1583841600 > > value:<int64_value:43 > >
metric:<type:"storage.googleapis.com/storage/object_count" labels:<key:"storage_class" value:"REGIONAL" > > resource:<type:"gcs_bucket" labels:<key:"bucket_name" value:"hogehoge-bucket-frontend" > labels:<key:"location" value:"asia-northeast2" > labels:<key:"project_id" value:"hogehoge-bucket" > > metric_kind:GAUGE value_type:INT64 points:<interval:<end_time:<seconds:1583841600 > start_time:<seconds:1583841600 > > value:<int64_value:575 > >
metric:<type:"storage.googleapis.com/storage/object_count" labels:<key:"storage_class" value:"REGIONAL" > > resource:<type:"gcs_bucket" labels:<key:"bucket_name" value:"hogehoge-bucket-frontend-staging" > labels:<key:"location" value:"asia-northeast2" > labels:<key:"project_id" value:"hogehoge-bucket" > > metric_kind:GAUGE value_type:INT64 points:<interval:<end_time:<seconds:1583841600 > start_time:<seconds:1583841600 > > value:<int64_value:568 > >
フィルタを使い取得するメトリックを制限する
ListTimeSeries の結果はイテレータ形式で取得でき、サンプルのように複数件返ることがあります。
返る件数はメトリックによって変わります。
サンプルコードでは各バケット単位で取得していますが、
GCEのCPU使用率を取得するとインスタンス単位で値が返ります。
取得する件数を絞りたい場合は、フィルタを追加します。
例えば、サンプルコードで特定のバケットのみの値を取得したい場合
フィルタを以下のように追加すると
filter_query := "metric.type = \"storage.googleapis.com/storage/object_count\" AND resource.type = \"gcs_bucket\" "
// フィルタを追加する
filter_query += "AND resource.labels.bucket_name = \"xtrans-friends-frontend-staging\" "
取得する値を絞ることが可能です。
$ go run sample/sample.go
metric:<type:"storage.googleapis.com/storage/object_count" labels:<key:"storage_class" value:"REGIONAL" > > resource:<type:"gcs_bucket" labels:<key:"bucket_name" value:"xtrans-friends-frontend-staging" > labels:<key:"location" value:"asia-northeast2" > labels:<key:"project_id" value:"xtrans-friends" > > metric_kind:GAUGE value_type:INT64 points:<interval:<end_time:<seconds:1583841600 > start_time:<seconds:1583841600 > > value:<int64_value:568 > > points:<interval:<end_time:<seconds:1583841300 > start_time:<seconds:1583841300 > > value:<int64_value:568 > >
取得したメトリックから値を取り出す
メトリックの値はサンプルコードの resp.Points
に配列として格納されています。
この値も取得期間に応じ複数取得することがあります。
また、値の取り出しは、メトリックのデータ型に応じて呼び出す関数が異なります。
メトリックのデータ型は resp.ValueType.String()
で確認が可能です。
サンプルコードを一部修正すると、値を確認できます。
fmt.Println(resp)
// 追加
fmt.Println(resp.ValueType.String())
fmt.Println(resp.Points)
storage/object_count
メトリックは INT64
型で値が格納されていることが分かります。
$ go run sample/sample.go
metric:<type:"storage.googleapis.com/storage/object_count" labels:<key:"storage_class" value:"REGIONAL" > > resource:<type:"gcs_bucket" labels:<key:"bucket_name" value:"xtrans-friends-frontend-staging" > labels:<key:"location" value:"asia-northeast2" > labels:<key:"project_id" value:"xtrans-friends" > > metric_kind:GAUGE value_type:INT64 points:<interval:<end_time:<seconds:1583841600 > start_time:<seconds:1583841600 > > value:<int64_value:568 > > points:<interval:<end_time:<seconds:1583841300 > start_time:<seconds:1583841300 > > value:<int64_value:568 > >
INT64
[interval:<end_time:<seconds:1583841600 > start_time:<seconds:1583841600 > > value:<int64_value:568 > interval:<end_time:<seconds:1583841300 > start_time:<seconds:1583841300 > > value:<int64_value:568 > ]
INT64
型の値を取り出す際は GetInt64Value()
関数を利用しますが、DOUBLE
型の値を取り出す際は GetDoubleValue()
関数を利用します。
詳しくはSDKのドキュメントを参照してください。
サンプルコードを変更し値を取得します。
fmt.Println(resp)
// 追加
fmt.Println(resp.ValueType.String())
fmt.Println(resp.Points)
// 先頭の値を取得する
fmt.Println(resp.Points[0].GetValue().GetInt64Value())
メトリックの値を取得できました。
$ go run sample/sample.go
metric:<type:"storage.googleapis.com/storage/object_count" labels:<key:"storage_class" value:"REGIONAL" > > resource:<type:"gcs_bucket" labels:<key:"bucket_name" value:"xtrans-friends-frontend-staging" > labels:<key:"location" value:"asia-northeast2" > labels:<key:"project_id" value:"xtrans-friends" > > metric_kind:GAUGE value_type:INT64 points:<interval:<end_time:<seconds:1583841600 > start_time:<seconds:1583841600 > > value:<int64_value:568 > > points:<interval:<end_time:<seconds:1583841300 > start_time:<seconds:1583841300 > > value:<int64_value:568 > >
INT64
[interval:<end_time:<seconds:1583841600 > start_time:<seconds:1583841600 > > value:<int64_value:568 > interval:<end_time:<seconds:1583841300 > start_time:<seconds:1583841300 > > value:<int64_value:568 > ]
568
まとめ
Golangで StackDriver Monitoring APIから値を取得することができました。
フィルタの指定方法や、値の取得など、ドキュメントに詳しく載っておらず苦労したので
StackDriver の値を Golangで取得したい 奇特な 方の助けになれば幸いです。