SORACOMのコストダッシュボードを作ってみた

こちらは[SORACOM Advent Calendar 2020](https://qiita.com/advent-calendar/2020/soracom)の15日目の記事です。

# TL;DR
- SORACOM APIを叩いてコスト詳細をGrafanaで見えるようにした
- ユーザコンソールの「ご利用料金詳細」の「CSV形式でダウンロード」からexcelでピボットテーブルを都度作るの飽きたので
- 料金明細csvをGrafanaでみえるようにしただけではある

![grafana.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26677/8133bbc4-cc0c-a57a-20c8-4f2570d4e7c8.png)
(これだと上のグラフで全体のコスト感の時間変化、下で単位時間あたりにkddiなるsimのs1.fast dlが急に増えたのがわかる!みたいな。データ量少ないけど...)

# やりたいこと
- simごとbill item(s1.fastとかbeamとか基本使用料とか)の内訳を見たい
- ダッシュボードで時系列としてぱぱっと見たい

# 実装
(またこの人SORACOM API叩いてnode_exporterのtext collectorに食わせてるな...とか去年を思い出してはいけない)
## システム構成
![system.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26677/06fe71fd-d341-1131-8f23-b3df719e8289.png)


```bash:ファイル構成例えば
./
    prometheus/
        (prometheus本体とかconfとか)
    node_exporter/
        node_exporter(bin本体)
        text_collector/
            soracom_cost.prom
    soracom_cost_exporter/
        main.py(作ったbatch) 
```

- batch
    - crondとかでhourlyで起動
  - SORACOM APIの[POST /bills/latest/export](https://dev.soracom.io/jp/docs/api/#!/Billing/exportLatestBilling)を叩く
  - csvを集計してprometheus metricsをtextで出力
  - ユーザコンソール上でsimごとtagを指定してるとさらにcsvには追加されたりするのでよしなに調整を
- それをnode exporterのtext collectorで読み取ってあとはprometheusやgrafanaへ
  - prometheus側はnode exporterをscrapeする設定いれてるだけ
  - node_exporterは起動オプションで[text collector](https://github.com/prometheus/node_exporter)を有効に 

## batchのコード
```python:soracom_cost_exporter/main.py
import io
import json

import pandas as pd
import requests
from prometheus_client import CollectorRegistry, Gauge, write_to_textfile

# get cost csv
auth_response = requests.post(  # get soracom access token
    url="https://api.soracom.io/v1/auth",
    headers={"Content-Type": "application/json"},
    data=json.dumps(
        {
            "authKeyId": "keyId-(自分の)",
            "authKey": "secret-(自分の)"
        }
    )
)
export_response = requests.post(  # get latest bill report url
    url="https://api.soracom.io/v1/bills/latest/export?export_mode=sync",
    headers={
        "X-Soracom-API-Key": auth_response.json().get("apiKey"),
        "X-Soracom-Token": auth_response.json().get("token"),
        "Accept": "application/json",
    }
)
cost_csv_url = export_response.json().get("url")  # download cost csv
cost_csv_response = requests.get(cost_csv_url)

# tally a cost csv
df = pd.read_csv(io.BytesIO(cost_csv_response.content))
df = pd.pivot_table(
    df,
    values="amount",
    index=["name", "billItemName", "group:name"],
    columns=[],
    aggfunc="sum"
)

# write metrics file
registry = CollectorRegistry()
soracom_cost_gauge = Gauge(
    "soracom_cost_jpy",
    "soracom cost jpy",
    ["name", "bill_item", "group_name"],
    registry=registry
)
for d in df.itertuples(name=None):
    name, bill_item_name, group_name = d[0]
    amount = d[1]
    soracom_cost_gauge.labels(name, bill_item_name, group_name).set(amount)
write_to_textfile("../node_exporter/text_collector/soracom_cost.prom", registry)

```

## metricsの設計
- name/bill_item/group_nameごとに料金明細csvのamountを割当
- monthlyのcostがずっと増えていって月初でresetされる感じ
- 出力されるファイルの中身はこんな

```bash
$ cat node_exporter/text_collector/soracom_cost.prom
# HELP soracom_cost_jpy soracom cost jpy
# TYPE soracom_cost_jpy gauge
soracom_cost_jpy{bill_item="basicCharge-active",group_name="default",name="docomo"} 140.0
soracom_cost_jpy{bill_item="soracomHarvestCharge",group_name="default",name="docomo"} 70.0
soracom_cost_jpy{bill_item="basicCharge-active",group_name="default",name="kddi"} 140.0
soracom_cost_jpy{bill_item="soracomHarvestCharge",group_name="default",name="kddi"} 70.0
soracom_cost_jpy{bill_item="downloadDataCharge-s1.fast-daytime",group_name="default",name="kddi"} 150.0
```

## grafanaの設定
### ダッシュボードの中身

- "Total so far"ではmetricsをそのままだし、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26677/730f2f37-24ac-0c4a-84ca-d2b9d3f12c30.png)

- "Hourly delta"ではprometheusのquery的にdeltaをとっています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26677/0dc6c485-a236-28cc-3ef4-108c126b5f12.png)


- ダッシュボードのvariableを設定しているので全体を"All"で眺めて、どれか多いのあったらfilterする感じの使い方を想定
  - dashboard variableをlabels_valuesで定義して自動でとってきて、グラフ側name=~"${name:pipe}"みたいに展開して個別でもALLでも見れるようにしてるのがおしゃれポイントです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26677/906898f1-4910-71ac-70a3-630930de7f2e.png)



### 取得できたmetricsについての言い訳
- docomoとかkddiとかがsimのtag:Nameです(分かりづらいですが...)
- データの更新頻度などは嘘っぱちです
    - 表にだせるそれっぽい利用料金のデータがなかったので個人のを加工してます
    - データが蓄積されてなくて(直前で記事書いてるからｹﾞﾌﾝｹﾞﾌﾝ...)

# やってみて
- 結構がっつりSORACOMさんを使っているのでcostを真面目にみないとなと
- んでAWS web consoleでいうとこのcost expolorerが欲しかった
- が、SORACOMユーザコンソールだと通信量などのダッシュボードはあれどコストの画面はシンプル...
- SORACOM Harvest Dataに料金データを突っ込んでLagoonでみるか?とも思ったが、流石に用途違いな感じで...
- やっぱGrafanaでぐりぐりいじれるとexcelのピボットテーブルとにらめっこには戻れないw 気軽に見えるようにするのが肝要
- きっとこんなの自作しなくとも、おいおいソラコムさんがかっこいいダッシュボードを実装してくれるはず!(ﾁﾗｯ

おわり