GoogleAnalyticsのPV数をGoとMackerelで可視化する
はじめに
今回はGoとMackerelを使ってGoogleAnalyticsのデータ(PV数)をMackerelにカスタムメトリクスとして投稿・可視化について書いていきます。
アーキテクチャ
- CloudWatch EventでLambdaを定期実行
- Lmabda ( Go ) でGoogleAnalyticsにAPIでデータを取得
- Lambda ( Go ) でMackerelにメトリクスを投げる
Google Cloud Platformについて
GoogleAnalyticsのAPIを有効にして、認証キーを作成します。
この鍵ファイルを使ってAPIを実行します。
GoogleAnalyticsについて
今回はGoogleAnalyticsの初期設定は完了している状態で進めます。
GCPで作成したサービスアカウントをGoogleAnalyticsに登録します。
ビューIDを確認する。
Lambda ( Go )について
LambdaにはGoogleAnalyticsにAPIでデータを取得してMackerelにメトリクスをPostする処理を定義して CloudWatch Eventを連携させます。Lambda関数やCloudwatchEventなどはServerlessFrameworkを利用してデプロイしました。
GoでGoogleAnalyticsのデータ取得にはこちらのパッケージを利用しました。
そして、Mackerelに取得したデータをメトリクスとして投稿にするところはこちらを利用!
*) Go: 1.12.4
- main.go
package main import ( "context" "fmt" "os" "strconv" "time" "github.com/aws/aws-lambda-go/lambda" "github.com/mackerelio/mackerel-client-go" "golang.org/x/oauth2/google" "google.golang.org/api/analytics/v3" "google.golang.org/api/option" ) var ( mkrKey = os.Getenv("MKRKEY") client = mackerel.NewClient(mkrKey) json = os.Getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON") viewID = os.Getenv("VIEW_ID") ) const ( // GA startDate = "today" endDate = "today" metricsUsers = "users" metricsPVs = "pagePath!=/preview" metricsPageViews = "pageviews" // Mackerel serviceName = "GoogleAnalytics" // Lambda timezone = "Asia/Tokyo" offset = 9 * 60 * 60 ) func main() { lambda.Start(Handler) } // Handler Lambda func Handler() { jst := time.FixedZone(timezone, offset) nowTime := time.Now().In(jst) ctx := context.Background() jwtConfig, err := google.JWTConfigFromJSON([]byte(json), analytics.AnalyticsReadonlyScope) if err != nil { fmt.Println(err) } ts := jwtConfig.TokenSource(ctx) client, err := analytics.NewService(ctx, option.WithTokenSource(ts)) // Get Users resUsers, err := client.Data.Ga.Get("ga:"+viewID, startDate, endDate, "ga:"+metricsUsers).Do() if err != nil { fmt.Println(err) } // Get PVs resPVs, err := client.Data.Ga.Get( "ga:"+viewID, startDate, endDate, "ga:"+metricsPageViews).Filters("ga:" + metricsPVs).Do() if err != nil { fmt.Println(err) } intResultUsers, _ := strconv.Atoi(resUsers.TotalsForAllResults["ga:"+metricsUsers]) intResultPVs, _ := strconv.Atoi(resPVs.TotalsForAllResults["ga:"+metricsPageViews]) mkrErr := PostValuesToMackerel(intResultUsers, intResultPVs, nowTime) if err != nil { fmt.Println(mkrErr) } } // PostValuesToMackerel Post Metrics to Mackerel func PostValuesToMackerel(intResultUsers int, intResultPVs int, nowTime time.Time) error { // Post users errUser := client.PostServiceMetricValues(serviceName, []*mackerel.MetricValue{ &mackerel.MetricValue{ Name: "Users.users", Time: nowTime.Unix(), Value: intResultUsers, }, }) if errUser != nil { fmt.Println(errUser) } // Post PV errPV := client.PostServiceMetricValues(serviceName, []*mackerel.MetricValue{ &mackerel.MetricValue{ Name: "PV.PVs", Time: nowTime.Unix(), Value: intResultPVs, }, }) if errPV != nil { fmt.Println(errPV) } return nil }
認証ファイル(json)のセット方法
序盤でGoogleAnalyticsの認証に使うjsonファイルを生成しました。環境変数でFilePathを指定して実行してもいいみたいです。( 下記リンクに記載があります )
今回は認証ファイル(json)を環境変数に中身をセットして読み込む方法にしました。 ( Lambdaの環境変数にkey/valueでセットしたかったので )
以下、コードの一部抜粋です。
- main.go
jwtConfig, err := google.JWTConfigFromJSON([]byte(json), analytics.AnalyticsReadonlyScope) if err != nil { fmt.Println(err) } ts := jwtConfig.TokenSource(ctx) client, err := analytics.NewService(ctx, option.WithTokenSource(ts))
WTConfigFromJSON
の定義 ( google.go )
func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) { var f credentialsFile if err := json.Unmarshal(jsonKey, &f); err != nil { return nil, err } if f.Type != serviceAccountKey { return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey) } scope = append([]string(nil), scope...) // copy return f.jwtConfig(scope), nil }
credentialsFile
の定義 ( google.go )
// credentialsFile is the unmarshalled representation of a credentials file. type credentialsFile struct { Type string `json:"type"` // serviceAccountKey or userCredentialsKey // Service Account fields ClientEmail string `json:"client_email"` PrivateKeyID string `json:"private_key_id"` PrivateKey string `json:"private_key"` TokenURL string `json:"token_uri"` ProjectID string `json:"project_id"` // User Credential fields // (These typically come from gcloud auth.) ClientSecret string `json:"client_secret"` ClientID string `json:"client_id"` RefreshToken string `json:"refresh_token"` }
→ 認証ファイル(json)をパースして利用しています。
- 参考
認証ファイルを環境変数にセットできるように加工
そのままだとjsonの中身をbashで exportで環境変数にセットできないので以下のように修正しました。
変更パターン
"
-->\"
\n
-->"'\n'"
変更前 ( 一部抜粋 )
"type": "service_account", "private_key": "-----BEGIN PRIVATE KEY-----\n"
- 変更後 ( 一部抜粋 )
\"type\": \"service_account\", \"private_key\": \"-----BEGIN PRIVATE KEY-----"'\n'"\"
- こちらを参考にさせていただきました 🙏
GoogleAnalyticsから欲しい情報を取得する
今回取得するのは、今日のPV数です。クエリパラメータは以下のようにセットしました。 取得したデータに合わせて、クエリパラメータのページを参考に書けばいいかと。
( metricsPVs = "pagePath!=/preview"
ではてブロで執筆中に確認するプレビューはカウントしないようにしています )
- main.go ( 一部抜粋 )
const ( // GA startDate = "today" endDate = "today" metricsUsers = "users" metricsPVs = "pagePath!=/preview" metricsPageViews = "pageviews" dimensionsTitle = "pageTitle" dimensionsPath = "pagePath" // Mackerel serviceName = "GoogleAnalytics" // Lambda timezone = "Asia/Tokyo" offset = 9 * 60 * 60 ) // Get PVs resPVs, err := client.Data.Ga.Get( "ga:"+viewID, startDate, endDate, "ga:"+metricsPageViews).Filters("ga:" + metricsPVs).Do()
以下のページにクエリパラメータについて記載されています。
- 参考 github.com
Lambdaの定期実行
CloudWatch Eventを利用して定期実行させます。今回は15分ごとに実行するようにしました。
Mackerelにメトリクスを投稿する
GoでMackerelにメトリクスを投稿する方法は以前のブログに書いているのでよければ参照ください!
今回書いたMackerelにメトリクスをPostするコードは以下の通りです。
- main.go ( 一部抜粋 )
// PostValuesToMackerel Post Metrics to Mackerel func PostValuesToMackerel(intResultUsers int, intResultPVs int, nowTime time.Time) error { // Post users errUser := client.PostServiceMetricValues(serviceName, []*mackerel.MetricValue{ &mackerel.MetricValue{ Name: "Users.users", Time: nowTime.Unix(), Value: intResultUsers, }, }) if errUser != nil { fmt.Println(errUser) } // Post PV errPV := client.PostServiceMetricValues(serviceName, []*mackerel.MetricValue{ &mackerel.MetricValue{ Name: "PV.PVs", Time: nowTime.Unix(), Value: intResultPVs, }, }) if errPV != nil { fmt.Println(errPV) } return nil }
- Mackerelの画面 ( 実行結果 )
デプロイ
- 環境変数をセットする
export MKRKEY=XXX export GOOGLE_APPLICATION_CREDENTIALS_JSON="{...}"
- Mackerelにサービスを作成する
- 名前は
GoogleAnalytics
で作成する
- 名前は
curl -X POST https://api.mackerelio.com/api/v0/services \ -H "X-Api-Key: ${MKRKEY}" \ -H "Content-Type: application/json" \ -d '{"name": "GoogleAnalytics", "memo": "google analytics"}'
- goをコンパイルする
make build
- ServerlessFrameworkでデプロイする
sls deploy --aws-profile <PROFILE> --viewid <VIEW-ID> --mkrkey ${MKRKEY} --google-apikey ${GOOGLE_APPLICATION_CREDENTIALS_JSON}
- ソースコード等はこちらにおいています。 ( Makefileや ServelessFrameworkのyamlファイルなども置いています ) github.com
さいごに
Goで利用してGoogleAnalyticsのデータをMackerelのメトリクスとして投稿・可視化をしました。 今回はじめて Google Cloud Servicesに接続するためのライブラリを利用したので、これから活用していくいいきっかけになりました。 他にも個人的に可視化したいメトリクスがあり、最近ありがたいことにアンバサダプランになったとこもあるので、どんどん活用していこうと思います!