Cloudflare Pages FunctionsのログをGoogle Driveにリアルタイムに保存しログを永続化してみた

## はじめに

[Cloudflare Pages Functions](https://developers.cloudflare.com/pages/functions/)を利用すると、SSRを行うフレームワークを利用してWebアプリケーションを簡単に構築できる。例えば、SvelteKitでは[Cloudflare Pages](https://kit.svelte.jp/docs/adapter-cloudflare)に書かれているように、すぐにWebアプリケーションを開発・デプロイすることができる。

しかし、以下の記事等を見る限り、Pages Functionsのログは永続化して保存することがCloudflare側に備わっているデフォルトの機能ではできない。

- [Products > Pages > Functions > Debugging and logging](https://developers.cloudflare.com/pages/functions/debugging-and-logging/#limits)
- [CloudFlare Pages(Functions)のログを永続保管したい](https://zenn.dev/tacoms/articles/12f192e2d8b40d)
- [Cloudflare PagesのPages Functionsでログを取る](https://zenn.dev/totto2727/scraps/8c3cc2a35515b4)

また、Logpushというサービスがあるようだが、これはエンタープライズプランのみであり、個人開発やプロプラン等で利用している場合には選択肢に入らないだろう。

- [Products > Logs > Logpush](https://developers.cloudflare.com/logs/about/)

なんとかしてリアルタイムにログを残して、それを永続化できないか？と思い、今回、`wrangler pages deployment tail`コマンドとGoogle Driveへの保存を組みわせて行うことで、ログの永続化をやってみた。

## どのようにやるか？

そんなに複雑ではなく以下のようにして実現する。

1. Google Driveをローカルのディレクトリにマウントする
1. Wranglerの[​​deployment tail](https://developers.cloudflare.com/workers/wrangler/commands/#deployment-tail)でリアルタイムにログを収集し、ファイルに書き出す
1. ファイルを定期的にGoogle Driveをマウントしたディレクトリにコピーする

以下では、順を追ってやっていく。

### 1. Google Driveをローカルのディレクトリにマウントする

OSによるが、私は古いPCにxubuntuを入れ直したPCで今回のことをやるので、[`google-drive-ocamlfuse`](https://github.com/astrada/google-drive-ocamlfuse)を利用する（WindowsのPCならデスクトップアプリのインストーラーがあるのでそれでいい）。

インストール手順はGitHubのREADMEに書いてある通りで以下のようになる。

```console
sudo add-apt-repository ppa:alessandro-strada/ppa
sudo apt-get update
sudo apt-get install google-drive-ocamlfuse
```

続いて、`google-drive-ocamlfuse`はGoogle Drive APIを利用するので、おなじみのOAuth2.0のための設定をする。

1. Google Drive APIの有効化
1. OAuthクライアントの作成（アプリの種類はデスクトップアプリ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/f3ebb177-3d0e-b858-1131-236a5937bd6b.png)
1. 作成したクライアントのclient_idとclient_secretをメモしておく

この手順を終えたら、以下のようにして`google-drive-ocamlfuse`にクライアントの情報を設定する。

```console
google-drive-ocamlfuse -id xxxxxxxxxx.apps.googleusercontent.com -secret XXX-YYY-ZZZ
```

あとは、Google Driveをマウントさせたいローカルディレクトリを作成して、

```conole
$ google-drive-ocamlfuse ~/gdrive
```

というようにマウントを行えばいい。

- 参考
  - [Ubuntu 22.04 / 23.04 で Google Driveを使用するには？](https://note.com/hajime_ueda/n/nfd93099bbc0a) 

### 2. Wranglerの​​deployment tailでリアルタイムにログを収集し、ファイルに書き出す

これは特に何か特別なことは何もなく、以下のようにコマンドを実行するだけ。

```console
$ npx wrangler pages deployment tail DEPLOYMENT_ID --project-name PROJECT_NAME | tee ~/logs/pages-functions.log
```

### 3. ファイルを定期的にGoogle Driveをマウントしたディレクトリにコピーする

これはシェルを書くことになるが、何も難しいことはなく以下のようなスクリプトを書いて実行すればいい。

```bash:~/sync-logs.sh
#!/bin/bash

while true; do
  rotate_log_files
  cp $HOME/logs/pages-functions.log ~/gdrive/logs/pages-functions.log
  sync
  sleep 5
done
```
```console
$ ~/sync-logs.sh
```

## まとめると…

ここまで1つずつ順を追って見てきたが、2, 3の手順は1つのシェルにまとめてしまえるので、最終的には以下のシェルを実行すればいい（日付ごとにログファイルを分けるとか色々機能を追加しているが）。

```sh:~/tail_and_sync_logs.sh
#!/bin/bash

# デプロイメントIDを引数から取得し、存在しない場合はエラーを表示して終了
if [ -z "$1" ]; then
  echo "Error: Deployment ID is required."
  echo "Usage: Deployment ID is required."
  exit 1
fi
DEPLOYMENT_ID=$1

echo "Deployment ID: $DEPLOYMENT_ID"

# Googleドライブのディレクトリを設定
GDRIVE_DIR="$HOME/gdrive/japan-meat-map"

# Googleドライブのディレクトリが存在することを確認し、存在しない場合は作成
echo "Checking if Google Drive directory exists..."
mkdir -p "$GDRIVE_DIR"
echo "Google Drive directory: $GDRIVE_DIR"

# ローカルファイルのパスを設定
LOCAL_LOG_FILE="/tmp/japan-meat-map.log"
echo "Local log file: $LOCAL_LOG_FILE"

# 初期のGoogleドライブのファイルパスを設定
GDRIVE_LOG_FILE="$GDRIVE_DIR/japan-meat-map.log"
echo "Google Drive log file: $GDRIVE_LOG_FILE"

# npxコマンドの出力をローカルファイルにリアルタイムで書き出す
echo "Starting npx wrangler..."
npx wrangler pages deployment tail "$DEPLOYMENT_ID" --project-name japan-meat-map | tee -a "$LOCAL_LOG_FILE" &
echo "npx wrangler started. Logging to $LOCAL_LOG_FILE"

# ログファイルの同期を5秒ごとに行うバックグラウンドプロセス
while true; do
  if [ -f "$LOCAL_LOG_FILE" ]; then
    cp "$LOCAL_LOG_FILE" "$GDRIVE_LOG_FILE"
    sync
    echo "Log file synced to Google Drive at $(date)"
  else
    echo "Local log file not found at $(date)"
  fi
  sleep 5
done
```
```console
$ ~/tail_and_sync_logs.sh DEPLOY_ID
```

上記のシェルを実行し続ければリアルタイムにGoogle Driveログを残すことができる。

## まとめとして

今回はCloudflare Pages Functionsのログを永続化し、かつリアルタイムにログを確認できる仕組みを構築してみた。

思ったよりも簡単にできたな感じた一方、以下のような課題もあるので、それを解消する方法がないかは今後も探っていきたいと思った（Cloudflareの制限事項はどうしようもないが）。

- https://developers.cloudflare.com/pages/functions/debugging-and-logging/#limits に書かれている制限があり、特に**リクエスト/秒が過去5分間に100を超えた場合、ログは表示されません(Logs will not display if the Function’s requests per second are over 100 for the last five minutes.)** とあるので、アクセスが多いとログが取れない
- シェルを動かすPCなど（AWSのEC2とかでも可）が必要で、そのPCが落ちるとログは取れない
- （正確に仕様がわかっていないが）`deployment id`がデプロイごとに変わる場合、その更新が必要になる

:::note info
Google Drive APIは無料で利用可能（2024年７月時点で）。変更される場合もあるので最新の情報をチェックしてください。
https://developers.google.com/drive/api/guides/limits#pricing
:::