Google BigQuery

GCP: 今月のGCP課金額をslackに自動的に書き込む

こんにちは、エクスチュアCTOの権です。

今回はGCPの課金額をslackに自動的に書き込むプログラムを作って見ます。

GCPは低コストでクラウド環境を構築できるのでとても良いのですが、うっかりテスト用の設定を作ったまま放置してしまって課金されてたり、なんてことありませんか?
毎日slackに今月の課金額をポストしてくれると、少しはダメージが少なくなるかも知れません。

やることは以下のとおりです。
1. GCPのBillingレポートをBigQueryにエクスポートする
2. BigQueryのBilligテーブルにクエリを投げて、レポートを抽出する
3. slackのwebhookを使って、レポートをslackのチャネルにポストする

1. GCPのBillingレポートをBigQueryにエクスポートする

まずはBigQueryにBillingエクスポート用のデータセットを作ります。
わかりやすく billing という名前にでもしておきます。

次にGCPのBillingメニューの中の、Billing Exportを開きます。
そして、先ほど作ったbillingデータセットを指定して、Enable Billing Exportボタンをクリックします。

BigQuery billing export has been successfully enabled というメッセージが表示されればOKです。
次は、このテーブルに対してクエリを投げて見ます。

2. BigQueryのBilligテーブルにクエリを投げて、レポートを抽出する

Billing Export設定をしてから小一時間ほどすると、billingデータセットの中に2つのテーブルが出て来ます。

gcp_billing_export_* というテーブルと、 gcp_billing_export_v1_* というテーブルです。

v1の方が今月発表された新しいスキーマのテーブルなので、新しいv1テーブルでクエリを書いて見ます。
今月の現時点の、プロジェクト名と製品名ごとに0.01ドル以上の課金額を表示します。

#standardSQL
select format_timestamp('%Y/%m', usage_start_time, 'Asia/Tokyo') as mon,
project.name as project,
service.description as service, 
round(sum(cost * 100)) / 100 as cost
from billing.gcp_billing_export_v1_008EC3_C14E1F_66E889
where format_timestamp('%Y/%m', usage_start_time, 'Asia/Tokyo') = format_timestamp('%Y/%m', current_timestamp, 'Asia/Tokyo')
and cost >= 0.01
group by mon, project, service
order by project

結果はこうなります。

次は、このデータをSlackのチャネルに定期的に投稿するプログラムを書いて見ます。

3. slackのwebhookを使って、レポートをslackのチャネルにポストする

SlackのIncoming Webhookという機能を使って、メッセージをSlackの特定のチャネルにポストします。

Slackのアカウントを持っている前提で、以下のURLからWebhook URLを取得します。

Incoming Webhook Integration

メッセージを書き込みたいチャネルを選んで、緑色のAdd Incoming Webhook integrationボタンをクリックすればOKです。

Webhook URLが表示されるので、これをメモしておきます。

そして、Webhook URLにBillingテーブルに対するクエリ結果をポストすればSlackにメッセージが表示されます。
Node.jsで書いて見ます。

var Slack = require('slack-node');
require('date-utils');

//webhook url
webhookUri = "https://hooks.slack.com/services/foo/bar/baz"; 
slack = new Slack();
slack.setWebhook(webhookUri);

var BigQuery = require('@google-cloud/bigquery');
var projectId = 'myprojectid'; // gcp project id
var bigquery = BigQuery({
    projectId: projectId
});
var datasetName = 'billing';
var dataset = bigquery.dataset(datasetName);
var table = dataset.table('gcp_billing_export_v1_hoge'); //billing table

//query
var query = 'SELECT format_timestamp(\'%Y/%m\', usage_start_time, \'Asia/Tokyo\') as mon, ' +
'project.name as project, service.description as service, round(sum(cost * 100)) / 100 as cost ' +
'FROM billing.gcp_billing_export_v1_hoge ' +
'where format_timestamp(\'%Y/%m\', usage_start_time, \'Asia/Tokyo\') = format_timestamp(\'%Y/%m\', current_timestamp, \'Asia/Tokyo\') ' +
'AND cost >= 0.01 ' +
'GROUP BY mon, project, service order by project';

var options = {
    query: query,
    useLegacySql: false
};

var bqresult = "";
var project_name = "";
var cnt = 0;
var subtotal = 0;
var total = 0;

//query結果をproject毎にまとめる
bigquery.query(options, function(err, rows) {
    if (!err) { 
        for (var i=0; i<rows.length; i++) {
            var row = rows[i];
            if (cnt == 0) {
                project_name = row["project"];
                cnt = 1;
            }
            //projectとprojectの間には罫線を入れる
            if (project_name != row["project"]) {
                bqresult += "----------\n";
                bqresult += "小計 $" + (Math.floor(subtotal * Math.pow(10, 2)) / Math.pow(10, 2)) + "\n\n";
                subtotal = 0;
            }
            bqresult += row["project"] + "\t" + row["service"] + "\t$" + row["cost"] + "\n";
            subtotal += row["cost"];
            total += row["cost"];
            project_name = row["project"];
        }
        bqresult += "----------\n";
        bqresult += "小計 $" + (Math.floor(subtotal * Math.pow(10, 2)) / Math.pow(10, 2)) + "\n\n";
        bqresult += "合計 $" + (Math.floor(total * Math.pow(10, 2)) / Math.pow(10, 2)) + "\n"; 
        
        var dt = new Date();
        var fd = dt.toFormat("YYYY-MM-DD");
        //slackに投稿        
        slack.webhook({
          channel: "#alert",
          username: "ctobot",
          icon_emoji: ":dollar:",
          text: "今月のGCPコスト (as of " + fd + ")\n" + bqresult
        }, function(err, response) {
          console.log(response);
        });
    }
});

実行すると、Slackのチャネルにメッセージが表示されます。

モザイクだらけでアレなのと、通貨設定がドルなのですが、そこはスルーしてください。

注意点として、GCPの課金エクスポートは、エクスポート設定をしたタイミングからの課金額しか反映されません。
月の途中でエクスポート設定をしても月初の金額は分からないので気をつけてください。

あとは、このプログラムをGCE上のLinuxインスタンスで毎日cronすれば良いですね。

以上、今回はGCP課金額をslackに自動投稿する方法についてでした。
弊社ではGCPを利用した分析基盤の構築支援などを行なっております。
お問い合わせはこちらからどうぞ。

関連記事

  1. Adobe Analytics

    Adobe Analytics: BigQueryにロードしたデータフィードをDataStudioで…

    こんにちは、CTOの権です。前回のブログで、BigQueryに…

  2. Adobe Analytics

    Adobe Analytics: データフィードをGoogle BigQueryのテーブルにロードす…

    こんにちは、CTOの権です。前回のブログの続きです。今回は…

  3. プログラミング

    Node.jsでCSVファイル内のダブルクオートで囲まれたカラム内のカンマを除去する

    こんにちは、エクスチュアCTOの権です。いろんなデータを扱う業…

  4. Adobe Analytics

    Adobe Analytics: SegmentsAPIを使って大量のセグメント設定を作成・更新する…

    こんにちは、エクスチュアCTOの権です。今回はAdobe Ma…

  5. Adobe Analytics

    BigQuery: Adobe Datafeed: event_listカラムの手軽な扱い方

    こんにちは、エクスチュアCTOの権です。今回は、AdobeAn…

  6. Adobe Analytics

    Adobe Analytics: データフィードをGoogle Compute EngineのLin…

    こんにちは、CTOの権です。もはやWeb解析だけの時代は終わり、様…

最近の記事

  1. Adobe Target: at.jsの「チラつき」を手っ取…
  2. Tableau:LOD徹底解説 – FIXED編…
  3. BigQuery: Adobe Datafeed: even…
  4. Adobe Analytics: SegmentsAPIを使…
  5. Google Compute Engine のLinuxVM…
  1. Adobe Audience Manager

    Adobe Audience Manager: REST APIを使ってTrai…
  2. Google BigQuery

    GCP: 今月のGCP課金額をslackに自動的に書き込む
  3. Adobe Analytics

    Adobe Analytics: AppMeasurement.jsの実装開発作…
  4. Adobe Analytics

    Adobe Analytics: Webサイト内で発生したJavascriptエ…
  5. Adobe Analytics

    Adobe Analytics:Report Builderの小技:リクエストの…
PAGE TOP