DatadogでHerokuを監視してみる

# はじめに

Herokuのアプリケーションの稼働状況って正直見えづらいと思うので、ちゃんとこちらでコントロールできるように監視してやる必要があると思うんだ。
ということで、Datadogはメトリクス、APM、ログをまとめて見られるということで、Herokuの監視をしてみることにした。

# 環境
コミュニティのSlack招待ページをGithubのコードからHerokuにデプロイしてあるので、それを監視する。
[Github - outsideris/slack-invite-automation](https://github.com/outsideris/slack-invite-automation)
![join-page.jpg](https://qiita-image-store.s3.amazonaws.com/0/174837/60a64b12-718c-b8c5-694c-156fe6214656.jpeg)

FreeプランのHerokuを使ったので、Dynoは一つ
言語はnode.js

# セットアップ
参考にしたサイトは↓
https://docs.datadoghq.com/agent/basic_agent_usage/heroku/?tab=ussite

## メトリクス

### Datadog AgentをDynoにインストール
まずはAgentをインストールして各種システムメトリクスを取得
Datadog用のBuild Packをインストールすればいいみたい

```bash
# Enable Heroku Labs Dyno Metadata
heroku labs:enable runtime-dyno-metadata --app <HEROKU_APP_NAME>
```
`<HEROKU_APP_NAME>` はHerokuのアプリケーションの名前


```bash
# Add this buildpack and set your Datadog API key
heroku buildpacks:add --index 1 https://github.com/DataDog/heroku-buildpack-datadog.git
heroku config:add DD_API_KEY=<DD_API_KEY>
```
`<DD_API_KEY>` はDatadogのAPI Key

```bash
# Deploy to Heroku
git push heroku master
```

これでエージェントのインストール＆セットアップ完了

### ホスト名変更
Datadogはホスト単位で課金されるがDynoは名前が変わりやすいから、その度にDatadog上では別ホストとしてカウントされて課金が大きく跳ね上がってしまうリスクがあるとのこと
つまり、DynoがDatadogでのホストになるということですね

> Heroku dynos are ephemeral-they can move to different host machines whenever new code is deployed, configuration changes are made, or resouce needs/availability changes. This makes Heroku flexible and responsive, but can potentially lead to a high number of reported hosts in Datadog. Datadog bills on a per-host basis, and the buildpack default is to report actual hosts, which can lead to higher than expected costs.

Refer to: https://docs.datadoghq.com/agent/basic_agent_usage/heroku/?tab=ussite#hostname

実際にDatadogではDynoのGUID(?)がホスト名になってるっぽい
**Host Map**
<img width="1280" alt="Image 2019-02-03 at 9.14.14 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/a9a989dc-fa0a-340f-3a93-791baa501a85.png">

↓↓ ズームイン ↓↓
<img width="439" alt="Image 2019-02-03 at 9.17.29 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/ff3181f6-7b54-e223-372e-a9883abc101f.png">

ということで、ホスト名を変更することに
今回は `DD_DYNO_HOST` という環境変数をいじることにする
これを `true` にすると、Dyno名がホスト名になるので、ホスト名が一意に決まって正しく課金されることになる

```bash
heroku config:set DD_DYNO_HOST=true --app <HEROKU_APP_NAME>
```

**Host Map**
<img width="1280" alt="Image 2019-02-03 at 9.37.03 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/b3235bcb-9ce0-ee9b-f325-2bfa54883311.png">

↓↓ ズームイン ↓↓
<img width="440" alt="Image 2019-02-03 at 9.59.36 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/674ca13a-6c60-ce16-b3ea-26446a57ae7a.png">

モザイクかかっててわかりづらいかもだけど、ホスト名は `<Heroku_APP_NAME>.<HEROKU_DYNO_NAME>` になってます

システムメトリクスもちゃんととれてる
楽勝ですね

<img width="1262" alt="Image 2019-02-03 at 10.02.03 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/7459b1c4-33b3-d203-bf70-863e2ef37f2d.png">

## APM

### APMでアプリケーションのパフォーマンスを可視化
APMは **Application Performance Management** の略で、アプリケーションのスループットやパフォーマンス、エラーを関数やメソッド単位でまでトラッキングできるしくみ
APMもDatadogで可視化できるですね

今回はNode.jsなので、Datadogのドキュメントにしたがってコードインスツルメンテーションしてみた
（参考） https://docs.datadoghq.com/tracing/languages/nodejs/

`package.js` に `dd-trace` を追記

```json:package.js
{
  "name": "slack-invite-automation",
  "version": "0.3.4",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "^1.18.0",
    "cookie-parser": "^1.4.0",
    "dd-trace": "^0.7.3",
    "debug": "^3.1.0",
    "dotenv": "^5.0.1",
    "express": "^4.13.0",
    "i18n": "^0.8.3",
    "morgan": "^1.6.0",
    "pug": "^2.0.0-rc.4",
    "request": "^2.62.0",
    "serve-favicon": "^2.3.0",
    "sanitize": "^2.1.0"
  }
}
```

↑ `"dependencies"` の3番目ね

続いて、モニタリング対象のjsにインスツルメント

```javascript:routes/index.js
const tracer = require('dd-trace').init();
const express = require('express');
const router = express.Router();
const request = require('request');

const config = require('../config');
const { badge } = require('../lib/badge');

const sanitize = require('sanitize');

router.get('/', function(req, res) {
  res.setLocale(config.locale);
  res.render('index', { community: config.community,
                        tokenRequired: !!config.inviteToken,
                        recaptchaSiteKey: config.recaptchaSiteKey });
});

...
```

1行目に↓を追加しただけ

```javascript
onst tracer = require('dd-trace').init();
```

あとはHerokuにデプロイ

```bash
# Add codes
git add .

# Commit
git commit -m "add dd-trace instrumentation"

# Push to Heroku
git push heroku master
```

しばらく待つと、APMデータが入ったっぽい

<img width="1144" alt="Image 2019-02-03 at 10.16.42 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/b6ad29a5-133e-122e-89ae-7f23cf985485.png">

あと、Datadogでは `env` タグごとにトレースを見ることができるらしいが、Herokuの場合デフォルトでは何もセットされていないので、下記CLIで環境変数としてセットしてやる必要がある

```bash
heroku config:set DD_TAGS="env:heroku" --app <HEROKU_APP_NAME>
```

### トレースを見る

Datadogでは一つ一つのリクエストを **トレース** データとして保存してすぐに可視化してくれるらしい
ただ、リクエスト数が多い場合はサンプリングされるそうだ

<img width="919" alt="Image 2019-02-03 at 10.18.35 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/a412ec67-a9a6-a29e-cdd1-ea41e4ef9ef5.png">

### APMとシステムメトリクスの相関

`host` をキーにしてシステムメトリクスとの相関も見られるみたい

<img width="1002" alt="Image 2019-02-03 at 10.45.17 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/1e3a56ed-e59f-1e7b-4a69-d776de19fbf0.png">

## ログ

### ログも見てみよう

[Heroku Log Drains](https://devcenter.heroku.com/articles/log-drains) でHTTP経由でログをDatadogに送れるらしい
ただ、これはまだベータ（2019年2月現在）だとかゴニョゴニョ...
https://docs.datadoghq.com/agent/basic_agent_usage/heroku/?tab=ussite#heroku-log-collection

```
heroku drains:add https://http-intake.logs.datadoghq.com/v1/input/<DD_API_KEY>?ddsource=heroku&service=<SERVICE>&host=<HOST> -a <HEROKU_APP_NAME>
```

上記のエンドポイントでHTTP POSTされるログをDatadogにインデックスされるらしい
各クエリーストリングについて以下解説

- `ddsource`: Datadogの `source` メタタグを付与。 `source:heroku` が付与されたログを自動的にパースしてくれる。
- `service`: Datadogの `source` メタタグを付与。 APMと相関付けるためのタグ。 なので、APMの `service` に合わせよう。
- `host`: Datadogの `source` メタタグを付与。 メトリクスやAPMとの相関付けで利用。 [ホスト名変更](#ホスト名変更) で設定したホスト名を指定しよう。

メトリクスやAPMはDatadog Agent経由で送信されるけど、ログはLog Drains使って直接Datadogのエンドポイントに送られるので、エージェントで指定したホスト名は反映されないんだ
だから、クエリーストリングで直接指定する必要があるんだね

`source:heroku` で検索すると、ログがインデックスされているのがわかりますね

### ログのパース

<img width="1134" alt="Image 2019-02-03 at 10.34.12 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/0d0720ca-0b8b-bae5-4c2f-f75f0bbb9509.png">

自動的にパースされてるから検索・集計しやすくなってるよ

<img width="637" alt="Image 2019-02-03 at 10.36.47 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/3f2e26f0-548d-0f19-dbbe-079a94818da2.png">

### APMとログの相関

`service` や `host` が紐づけられるから、トレースから該当時間のログにドリルダウンするのも簡単

<img width="916" alt="Image 2019-02-03 at 10.42.36 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/f230c71c-d98d-e65d-957f-fa9ffab52160.png">

## これで設定完了

Herokuでアプリケーション作るたびにこれらの設定を手動で追加するのは少々手間なので、Terraformか何かで自動化したいなあ
それは次回以降の課題ということで

# モニタリング

基本的なシステムリシースのダッシュボード、トレース、ログ検索・相関はDatadogのGUIそのままで使えるので、アラートやダッシュボード作りたい
そこまで書くと記事が盛りだくさんすぎてしまうので、それは次回以降にします