Eyes, JAPAN Blog > Herokuの利用料金をメールで通知する

Herokuの利用料金をメールで通知する

shimizu

この記事は1年以上前に書かれたもので、内容が古い可能性がありますのでご注意ください。

はじめに

クラウド・アプリケーション・プラットフォームの老舗であるHerokuは、様々な規模のプロジェクトに利用できるPaaSとして手軽な試用から本格的な運用まで対応でき、弊社でもプロトタイピング、開発環境、本番環境などに幅広く活用しています。

ところで、Herokuに限ったことではありませんが、クラウドサービスを利用する上で気になるのが、月額の利用料金額の状況です。課金対象となるリソースの量についてあらかじめ概算を出して作成したとしても、項目の見落としで想定外の課金が発生していないか、作業ミス等で不要なリソースが作成されてしまっていないだろうかと心配になるものです。

そのような問題ないことを確認するには、月初からの累計請求額の状況をこまめにチェックすることが確実ですが、数字を見るために毎回手動でWeb上のダッシュボード画面を開くのは手間がかかります。そこで、「今の段階で請求額はいくらか」という情報を毎日メールで通知してくれる機能を考えます。

実装する

Herokuでは、Platform APIを使うことでHeroku内部の情報を取得したりアプリを操作したりすることが可能です。ここには請求書の情報を取得するエンドポイントがあり、利用料金の請求額を調べることができます。

GET /account/invoices

curl の例
$ curl -n https://api.heroku.com/account/invoices \
-H “Accept: application/vnd.heroku+json; version=3”

引用元: 請求書の情報

ここで取得した請求書の中で最新のものが、昨日までの月内の利用金額を表しています。

なお、APIでのリクエストの際に自分のHerokuアカウントの情報を取得するために認証が必要になりますが、それにはAPIキーを使用します。具体的には、各APIリクエストの際に「Authorization: Bearer (APIキー)」というHTTPヘッダーを付加します。詳しくはこちらをご覧ください。(自分のアカウントのAPIキーは、Herokuにログインし「Account Settings→API Key→Revealボタン」で確認できます)

それでは、Google Apps Scriptで実装してみましょう。コードは以下のとおりです。

const accessToken = '(ここにHerokuアカウントのAPIキーを入れる)';  // アクセストークン
 
function main() {
  let result;
  let period = '';
  let totalAmount = 0;

  // 最新の請求書を取得する
  result = getLatestInvoice(accessToken);
  // 請求書の対象期間
  period = result.period_start? `${result.period_start}〜${result.period_end}` : '';
  // 請求額
  totalAmount = result.total;
 
  // 送信するメールの内容
  const recipient = '[email protected]'; // 送信先のメールアドレス
  const subject = 'Heroku利用料金 ' + new Date().toISOString().slice(0, 10);
  const body = 'Heroku利用料金を通知します。\n'
    + '\n'
    + `期間: ${period}\n`
    + `請求額: $${totalAmount}\n`;
  const options = { name: '[email protected]' };

  // メールを送信する
  GmailApp.sendEmail(recipient, subject, body, options);
}
 
// アクセストークンを用いて最新の請求書を取得する(Personal or Team)
function getLatestInvoice(accessToken) {
  let invoices;
  let latestInvoice;
  let period_start, period_end;
  let total = 0;
 
  // 請求書を取得する
  invoices = fetchGetRequest('/account/invoices', accessToken);
  invoices = JSON.parse(invoicesResult);
 
  // 日付が新しい順に並べ替え、最新の請求書を取り出す
  sortInvoices(invoices);
  latestInvoice = invoices[0];
 
 // 最新の請求書から対象期間と金額を取り出す
  if (latestInvoice) {
    period_start = latestInvoice.period_start;
    period_end = latestInvoice.period_end;
    total = latestInvoice.total / 100;
  }
 
  return {
    period_start: period_start,
    period_end: period_end,
    total: total,
  };
}
 
// 請求書の配列を新しい順にソートする
function sortInvoices(invoices) {
  invoices.sort((a, b) => {
    if (a.period_start < b.period_start) {
      return -1;
    }
    if (a.period_start > b.period_start) {
      return 1;
    }
    return 0;
  }).reverse();
}
 
// Heroku Platform APIに認証情報を付加してGETリクエストを行う
// 詳細はここを参照→https://devcenter.heroku.com/ja/articles/platform-api-quickstart
function fetchGetRequest(path, accessToken) {
  const params = {
    headers: {
      "Accept": "application/vnd.heroku+json; version=3",
      "Authorization": `Bearer ${accessToken}`,
    }
  };
 
  return UrlFetchApp.fetch(`https://api.heroku.com${path}`, params);
}

このスクリプトをApps Scriptのトリガー機能を利用して1日1回実行すれば、以下のようなメールが届き、利用料金を知ることができます。

To: [email protected]
Subject: Heroku利用料金 2022-03-11

Heroku利用料金を通知します。

期間: 2022-03-01〜2022-03-10
請求額: $123.45

おわりに

クラウドプラットフォームのサービスは手間なく効率的にサーバー環境をセットアップし運用するのに便利で、開発業務に不可欠なものとなりましたが、利用の際の不備による意図しない請求を防止するための配慮が必要です。そこで、今回取り上げたような自動化によって、効率的に状況把握を行うことが大切です。メールだけでなくSlackに通知したり、閾値の超過で警告を発するようにするなど、状況に応じてカスタマイズするとより効果が高まります。

Comments are closed.