CloudStorageにファイルがアップロードされたらメール通知したい

# はじめに
タイトルどおりの事がやりたくて奮闘した記事です。
GCPのサービスだけで簡単に出来るかと思ったらそうでもありませんでした。


**楽々メール通知の仕組みの図（妄想）** 
![GCS通知1.png](https://qiita-image-store.s3.amazonaws.com/0/169814/f2162327-709b-68b9-c535-5b1873ffc158.png)


# 実現方法
結論から言うと、Cloud FunctionsのCloud Storageトリガーを利用しました。

## メール通知の仕組み実現版の図
![GCS通知(採用).png](https://qiita-image-store.s3.amazonaws.com/0/169814/04cffe6b-fa3b-96c8-5fd7-0e43c3d56eb2.png)


## こんなメールが届く
![image.png](https://qiita-image-store.s3.amazonaws.com/0/169814/8b189f9a-061f-a07a-4263-bdcfa4dcc536.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/169814/d0f7de75-42b9-2e8f-d699-1ecaaf1e9c47.png)


## 詳細
ファイルが「ファイナライズ/作成」されるとコードが実行されます。コードは下記の通り。


<details><summary>メール送信用コード</summary><div>

```gcs_notification_mail.py
def gcs_notification_mail(event, context):
    import smtplib
    from email.mime.text import MIMEText

    # 変数宣言(メッセージの組み立て用)
    file = event
    filename = file["name"]
    filesize_mb = round(int(file["size"]) / 1024 / 1024, 1)  # MBに変換
    jp = "iso-2022-jp"

    # メッセージの組み立て
    msg = MIMEText(
        str(filename)
        + str("のアップロードが完了しました。\nファイルサイズは約")
        + str(filesize_mb)
        + str("MBです。"),
        "plain",
        jp,
    )

    # 変数宣言(メール送信処理用)
    fromaddr = "送信元メールアドレス"
    toaddr = "送信先メールアドレス"
    smtpserver = "smtp.gmail.com"
    loginid = "GmailのログインID"
    loginpass = "Gmailのログインパスワード"

    # メール送信処理
    msg["Subject"] = "GCSアップロード通知"
    msg["From"] = fromaddr
    msg["To"] = toaddr

    try:
        server = smtplib.SMTP_SSL(smtpserver)
        server.login(loginid, loginpass)
        server.send_message(msg)
        server.quit()
        print(f"Processing file: {file['name']}.")
    except Exception:
        print("Error: unable to send email")

```
</div></details>
トリガーとなったファイルの必要な情報（ファイル名とファイルサイズ）を取り出し、メッセージを組み立て、GmailのSMTPサーバを使ってメール送信します。

コードはコチラのページを参考にしました。
1. [Python3.3でメール送信](http://w.builwing.info/2013/09/21/python3-3%E3%81%A7%E3%83%A1%E3%83%BC%E3%83%AB%E9%80%81%E4%BF%A1/)
2. [Python3のメール送信](https://teratail.com/questions/118921)
3. [Python3で日本語のメールを送信](https://qiita.com/ColdFreak/items/1294258400f3ef149c3b)

以降の記事は全てボツ案です。


# ボツ案１～Stackdriver loggingに出力される通知をトリガーにメール～
**ボツ案その１**
![GCS通知2.png](https://qiita-image-store.s3.amazonaws.com/0/169814/e0b9131f-7280-2f87-373f-1ae0d391780b.png)


一番お手軽に思いついた方法。
が、そもそもStackdriver loggingにはファイル作成される時のログは通知されていませんでした。

# ボツ案２～Stackdriver monitoringのGCS BucketのObject countメトリック増をトリガーにメール～

Stackdriver monitoringのAlerting PolicyのConditionsの設定を見ると、なんと良さそうなメトリックがあるではありませんか！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/169814/bbb2a202-8dd7-3e3e-a751-b0c4ed4cefb7.png)

こんな図の感じでいけそうである。

**シンプルに通知を実現できそうな構成の図**
![GCS通知3.png](https://qiita-image-store.s3.amazonaws.com/0/169814/d689732f-7f57-3839-810c-d81a4ebf329d.png)

だがしかし、このobject countはリアルタイムではなく1日1回しか測定されないようである。

https://cloud.google.com/monitoring/api/metrics_gcp#gcp-storage

以下抜粋
`Total number of objects per bucket, grouped by storage class. Values are measured once per day. Sampled every 300 seconds. After sampling, data is not visible for up to 600 seconds. `
`バケットあたりのオブジェクトの総数。ストレージクラス別にグループ化されています。値は1日に1回測定されます。 300秒ごとにサンプリングされます。サンプリング後、データは最大600秒間表示されません。`

実際に試してみたらアップロードしてから数時間後にメールが飛びました。

# ボツ案3～Cloud FunctionsのGCSファイル作成トリガーでstackdriver loggingにログ出力させてあとはボツ案1の方法～
Stackdriver loggingで監視するのはGCS Bucketリソースではなく、Cloud Functionsリソースが良いということでボツ案1とのコラボレーション。

**Cloud Functionsにログを出力させる図**
![GCS通知4.png](https://qiita-image-store.s3.amazonaws.com/0/169814/e4aa62e1-0c9c-d3f8-79ec-9bde5cbefb16.png)

結果的にこれは上手く動いたが通知のメールがアラートとなってしまうのがイマイチだった。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/169814/274e8e20-6e13-e6c9-2faa-93e763a065c8.png)


# 終わりに
AWSのS3ならもっと簡単に同じような仕組みを構築できるのかなとは思った