Google Cloud Monitoringのカスタムメトリクスを使ってTask Queueを監視したいズラ๑◉ﻌ◉๑

**merry Xmas!**

Advent Calendar 2015も最終日になりました。

ずっとApp Engineばかりだった私ですが今年はついにCompute Engineにデビューしました！
＼(^o^)／

Compute Engineのpreemptibleインスタンスを数百台instance groupで構成して自動スケールさせています。

各サーバーはTask Queueを監視して動く様になっているので、Queueの滞留サイズ監視して閾値を超えたらslackにアラート飛ばしたいなー、と思ってチャレンジしました。

Google Cloud MonitoringそのものについてはGCP Advent Calendarで他の方が既に記事を書かれてましたのでここでは割愛しますm(_ _)m
http://qiita.com/FumihikoSHIROYAMA/items/6846630b44fbc3f22b8e

# 注意

Google Cloud Monitoringは現時点でまだbetaです。
ここに書かれている内容は古くなる可能性が高いです。

# 準備

Compute Engineの自動スケールはGoogle Cloud Monitoringのメトリクスを元に行うことができるらしいので、まずはTask Queueの滞留をカスタムメトリクスとして登録してみます。

カスタムメトリクスには軽量カスタムメトリクス（Lightweight custom metrics）とラベル付きカスタムメトリクス（Labeled custom metrics）があります。
今回はラベル付きカスタムメトリクスを使用します。

まずMetricDescriptorなるものを作成します。これがメトリックの定義になります。
※軽量カスタムメトリクスの場合はこのステップを省略出来ます（メトリックを書き込むと裏で勝手に作成されるらしい）。

現時点で管理コンソールからポチポチとは作れないみたいなので、APIで作成します。

API ManagerからGoogle Cloud Monitoring APIを有効にしておきます。

![スクリーンショット 2015-12-17 14.16.33.png](https://qiita-image-store.s3.amazonaws.com/0/31437/021bfcc3-497b-902d-c016-4fb6ebc843a4.png "スクリーンショット 2015-12-17 14.16.33.png")

↑画面で「Google cloud monitoring API」を検索して選択。

![スクリーンショット 2015-12-17 13.35.43.png](https://qiita-image-store.s3.amazonaws.com/0/31437/90999486-1e16-24f1-9c6a-ee2f37dae26b.png "スクリーンショット 2015-12-17 13.35.43.png")

「APIを有効にする」ボタンをクリックします。

API Explorerを使ってブラウザからAPIを実行することができます。
「このAPIをAPI Exploerで試す」をクリックするとAPI Explorerが開きます。

<img width="531" alt="スクリーンショット 2015-12-18 14.03.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/31437/58c434cc-39b7-ea76-7e62-847b631c81e1.png">

APIの一覧が表示されるので「cloudmonitoring.metricDescriptors.create」を選択します。

<img width="623" alt="スクリーンショット 2015-12-18 14.15.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/31437/d4187e25-e4d0-08ff-7a55-28cf5f2d9005.png">

右上の「Authorize requests using OAuth 2.0」のスイッチがOFFになっていたらクリック＆承認してONにします。

projectフィールドにGCPのproject ID、Request bodyに登録リクエストJSONを入力します。

```json
{
 "name": "custom.cloudmonitoring.googleapis.com/tasks_in_queue",
 "labels": [
  {
   "key": "custom.cloudmonitoring.googleapis.com/queue_name",
   "description": "A queue name."
  }
 ],
 "description": "Tasks in queue.",
 "typeDescriptor": {
  "metricType": "gauge",
  "valueType": "int64"
 },
 "project": "your_project_id"
}
```

APIの詳細は下記参照
https://cloud.google.com/monitoring/v2beta2/metricDescriptors#resource

nameにメトリック名、labelsでラベルを最大10個まで指定出来ます。
nameとlabelのkeyには「custom.cloudmonitoring.googleapis.com/」というプレフィックスが必要なので要注意です。
typeDescriptorのvalueTypeにはint64またはdoubleが指定出来ます。

上記ではタスク滞留を監視するメトリック「tasks_in_queue」を登録しました。

ついでに直近1分間に捌けたタスク数のメトリック「tasks_executed_min」も登録しておきます↓

```json
{
 "name": "custom.cloudmonitoring.googleapis.com/tasks_executed_min",
 "labels": [
  {
   "key": "custom.cloudmonitoring.googleapis.com/queue_name",
   "description": "A queue name."
  }
 ],
 "description": "Tasks executed in a minute.",
 "typeDescriptor": {
  "metricType": "gauge",
  "valueType": "int64"
 },
 "project": "your_project_id"
}
```

# メトリック収集

次にメトリックの収集ですが、Google App Engineのアプリをcronで定期起動して、そこからGoogle client libraryでcloud monitoring APIを呼び出してメトリックを書き込むことにします。

コード例はGoです。PythonやJavaなど他言語のライブラリも用意されています。

※記事の本筋からは外れるので抜粋です

```go
func MonitorQueues(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	appID := appengine.AppID(ctx)

	queues := []string{"assemble", "flip", "order", "render"}

	qstats, err := taskqueue.QueueStats(ctx, queues)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	hc := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, cloudmonitoring.MonitoringScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}

	service, err := cloudmonitoring.New(hc)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	t := time.Now().UTC().Format(time.RFC3339)

	var tpoints []*cloudmonitoring.TimeseriesPoint

	newTpoint := func(metric, queue string, value int64) *cloudmonitoring.TimeseriesPoint {
		return &cloudmonitoring.TimeseriesPoint{
			Point: &cloudmonitoring.Point{
				Start:      t,
				End:        t,
				Int64Value: &value,
			},
			TimeseriesDesc: &cloudmonitoring.TimeseriesDescriptor{
				Project: appID,
				Metric:  "custom.cloudmonitoring.googleapis.com/" + metric,
				Labels: map[string]string{
					"custom.cloudmonitoring.googleapis.com/queue_name": queue,
				},
			},
		}
	}

	for i, queue := range queues {
		tpoints = append(tpoints, newTpoint("tasks_in_queue", queue, int64(qstats[i].Tasks)))
		tpoints = append(tpoints, newTpoint("tasks_executed_min", queue, int64(qstats[i].Executed1Minute)))
	}

	req := cloudmonitoring.WriteTimeseriesRequest{Timeseries: tpoints}

	_, err = service.Timeseries.Write(appID, &req).Do()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	return
}
```

queueが4種類あるのですが、それぞれの統計情報から格納されているタスク数と直近1分間の実行数を取得し、メトリックとして書き込んでいます。

ラベルqueue_nameにはそれぞれのqueue名を指定しています。

TimeseriesDescriptorのProjectフィールドと、Timeseries.Writeメソッドの第一引数にはGCPのプロジェクトIDを渡す必要があります。App Engineの場合アプリケーションID==プロジェクトIDになるのでそれを渡しています。


# 監視

書き込んだカスタムメトリクスをCloud Monitoringでチャートに表示しましょう。

デフォルトのダッシュボードの画面右下の方に

![スクリーンショット 2015-12-25 8.55.00.png](https://qiita-image-store.s3.amazonaws.com/0/31437/08b146e0-d145-fc82-5700-6def2f8ed916.png)

こんなボタンがあります。これをクリックするとチャートが追加されます。
カスタムダッシュボードを作成してそこに追加することも出来ます。

<img width="321" alt="スクリーンショット 2015-12-25 9.02.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/31437/5b0725d4-8243-1a4d-564d-0061bbc4b24e.png">

Resource Typeに「Custom Metrics V2」、Metricに作成したメトリック名、Labelsに表示したいラベルを指定します（ここでは全queueの情報を一つのチャートに表示したいのでAnyを指定）。

「Save」をクリックするとチャートが追加されます。

同様にtasks_executed_minメトリックのチャートも追加します。

![スクリーンショット 2015-12-25 9.21.01.png](https://qiita-image-store.s3.amazonaws.com/0/31437/7be50f76-fd6a-ea90-da24-d462cc7ab710.png)

**出た！  ＼(^o^)／**

便利ですね！(^^)

# アラート

カスタムメトリクスを元にアラートを飛ばすことも出来ます(キューの滞留が1000を超えたらアラート、etc)。手順は通常のメトリクスに対する設定と同様です。

この辺も下記記事で既に書かれてましたので割愛しますm(_ _)m
http://qiita.com/FumihikoSHIROYAMA/items/6846630b44fbc3f22b8e

slackへのアラートも画面に従ってポチポチやっていくだけで驚くほど簡単に設定出来ました＼(^o^)／

# 悔恨

今回実は、
「Google Cloud Monitoringを使ってTask Queueの滞留を監視して、さらにそれを指標にしてインスタンスを自動スケールさせたいズラ๑◉ﻌ◉๑」
というテーマで記事を書く予定だったのですが、仕様を少し勘違いしていて実現出来ませんでしたorz

https://cloud.google.com/compute/docs/autoscaler/scaling-cloud-monitoring-metrics#choose_a_valid_custom_metric

オートスケール用メトリックはVMインスタンス単位で出力する必要があるのですね。

その辺りはまた次回の講釈で・・

良いお年を〜＼(^o^)／