気になるあの上司は何時まで仕事をしているの？調査しよう。 Part II: データ保存編 (AWS Lambda/CloudWatch)

## 注意

この記事は Slack の在籍状況を DB 等に保存し、そこから勤務時間帯を分析するという企画です。
Slack では 1 つのアカウントで複数のワークスペースを管理することができるため、オンライン状態でも趣味のコミュニティにいた、なんてこともあります。
決して **「Slack がオンライン = 仕事している」ということではない** ので、あくまで参考程度にお願いします。

## 目次

- [Part I: データ取得編 (Slack API)](https://qiita.com/noritakaIzumi/items/15baea8bcda572232d37)
- **Part II: データ保存編 (AWS Lambda/CloudWatch)** <- 今回はここ！
- [Part III: データ分析編 (AWS CloudWatch/スプレッドシート)](https://qiita.com/noritakaIzumi/items/5629e6f4e36d718726da)

## 概要

今回は API を定期実行して結果を保存する仕組みを構築するセクションとなります。

今回は AWS のサービスを使用します。

Lambda で API を実行する関数を作り、それを CloudWatch で定期実行してログを出力、後に CloudWatch Logs Insights で解析を行う方針とします。

## 前提条件

- AWS アカウントを持っている
- Python をインストールしている

## 手順

### Lambda 関数を作成する

Lambda -> Create function -> Author from scratch と選択し、関数名は `slack-users-getPresence` 、ランタイムは `Python 3.8` を選択します。

### パッケージを作成・アップロードする

今回は Python で簡単にリクエストを作成できる [requests ライブラリ](https://docs.python-requests.org/en/master/) を Lambda にアップロードしてからコードを書きます。

ローカルにて好きなディレクトリを作成し、その中に移動しておいてください。

ディレクトリの中に requests ライブラリをインストールします。

```sh
pip install requests --target .
```

`lambda_function.py` を作成し、以下のコードを書いておきます。

```py:lambda_function.py
import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```

これらのパッケージを zip で圧縮します。コマンドで実行する方は以下を実行します。

**作成したディレクトリを zip にするのではなく、ディレクトリの中身だけを zip にしてください！**

```sh
zip -r ../package.zip .
```

zip ができたら、 Lambda 側で作成した関数を開き、 Code タブから Upload from -> .zip file と進みます。

そして先ほどの zip をアップロードしてください。

### 関数を記述する

lambda_function.py の中身を以下のように編集します。

```py:lambda_function.py
import requests
import json

def lambda_handler(event, context):
    # request
    url = 'https://slack.com/api/users.getPresence'
    headers = {'Authorization': 'Bearer xoxb-1234-56789abcdefghijklmnop'}
    payload = {'user': event['member_id']}
    r = requests.get(url, headers=headers, params=payload)
    r_json = r.json()

    # time
    tz = timezone(timedelta(hours=+9))
    dt = datetime.now(tz)

    output = {
        'time': dt.strftime('%Y-%m-%d %H:%M'),
        'presence': r_json['presence'],
    }

    # to CloudWatch
    print(json.dumps(output))

    return {
        'statusCode': 200,
        'body': json.dumps(output),
    }
```

`xoxb-*` の部分をトークンに置き換えてください。

本来、トークンなどの情報は Secrets Manager 等で管理し、アクセスするのが安全かと思いますが、今回はコストを抑えて気軽に試していただくため、あえてベタ書きとしています。

### Lambda の動作テストをする

関数を作成したら Deploy をクリックし、 Test タブに移動します。

テストイベントを作成する画面が出てきますので、以下のようにイベントを作成します。

`W1234567890` は前回 Slack のプロフィールからコピーしたユーザ ID に置き換えてください。

```json
{
  "member_id": "W1234567890"
}
```

Test ボタンをクリックしてテストしてみましょう。以下のような結果が表示されれば成功です！

アクティブ状態

```json
{
  "statusCode": 200,
  "body": "{\"time\": \"2021-07-28 04:11\", \"presence\": \"active\"}"
}
```

離席状態

```json
{
  "statusCode": 200,
  "body": "{\"time\": \"2021-07-28 04:12\", \"presence\": \"away\"}"
}
```

Log output にも同様の結果が出力されていることを確認しておいてください。

### CloudWatch に定期実行イベントを登録する

CloudWatch へ移動し、左側のメニューから Events -> Rules と進み Create rule をクリックします。

設定項目は以下のように設定します。

- Event Source
  - Schedule
  - Fixed rate of `1` Minutes

- Targets
  - Lambda function
  - Function*: `slack-users-getPresence`
  - Configure version/alias: `Default`
  - Configure input: `{"member_id": "W1234567890"}`

Configure details をクリックして次へ進み、以下のように設定します。

- Name: `slack-presence-manager`
- Description: `How long does that boss work? Let's investigate.`
- State: `Enabled`

Create rule をクリックします。

作成が完了すると以下のようにリストに `slack-presence-manager` が追加されています。

![cloudwatch_rules_list.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486784/1ab5cdc2-4f7e-a58c-0e63-0ab34955e8ad.png)

### 定期実行イベントが動作していることを確認する

念のため 5 分ほど放置して、 CloudWatch の Log groups にログが出力されていることを確認しましょう。

Logs -> Log groups と進み、 `/aws/lambda/slack-users-getPresence` を選択します。

Log streams タブが選択されていることを確認し、 Search all をクリックすると、ログを見ることができます。

以下のように 1 分ごとに JSON 形式のログが出力されていれば成功です！

![log_events.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486784/3e17c833-181a-4988-5934-fce5208d891d.png)

## 次回予告

今回はここまでです。

次回は CloudWatch に蓄積されたログを集計し、いよいよ気になるあの上司が何時まで仕事をしているのか、視覚的に分析します。

[Part III: データ分析編 (AWS CloudWatch/スプレッドシート)](https://qiita.com/noritakaIzumi/items/5629e6f4e36d718726da)

### 勤務時間帯を分析する

本日のメインイベントです。

CloudWatch の Log insights でログを整形して CSV に変換した後、スプレッドシートに取り込んで日付を縦軸、時間帯を横軸にしたヒートマップのようなものを作ってみましょう。

※この作業をするにあたり、 CloudWatch の定期実行イベントを数日動作させてログを蓄積させておくと有効な結果が得やすいかと思います。