はじめに
ログをクラウド上に持ってくるときにWebHookを経由して連携させるSaaSのソリューションがあります。
こんなイメージ
SendGridのアクティビティログはまさにそのパターンで、例えばEvent Webhookを利用することでSendGrid経由でメールを送信する際に発生するイベントを、指定したURLにPOSTすることができます。
このデータの用途は、配信停止アドレスの削除、迷惑メール報告への対応、
エンゲージできなかった受信アドレスの判定、バウンスされたメールアドレスの特定、
メールプログラムの高度な分析などです。ユニーク引数やカテゴリパラメータを使用して、
動的なデータを挿入することができるため、あなたのメールのシャープでクリアなイメージを構築するのに役立ちます。
これをAzure Functionsを利用して実装してみたいと思います。
#AzureFunction(Typescript)でAppendBlobを利用する記事が見当たらなかったので書いてみました。
output binding
Azure FunctionsにはOutput Bindingという機能があり、BlobStorageへ簡単にデータを書き込むことができます。
これを使えば簡単にできるぞと思っていざやってみるとそうはうまくいきませんでした。
常に新しいファイルに書き込んでいくことはできるのですが追記することはできないようです。
Append blobの利用
こういうログのユースケースに最適なBlobStorageがありまして、これが追加Blob(append blob)です。
追加 BLOB はブロックで構成され、追加操作用に最適化されています。
追加 BLOB を変更すると、ブロックは追加ブロック操作を介してのみ BLOB の末尾に 追加 されます。
既存のブロックの更新または削除はサポートされていません。
ブロック BLOB とは異なり、追加 BLOB はブロック ID を公開しません。
追加 BLOB 内の各ブロックは、最大 4 MiB の異なるサイズにすることができ、
追加 BLOB には最大 50,000 ブロックを含めることができます。
したがって、追加 BLOB の最大サイズは 195 GiB (4 MiB X 50,000 ブロック) をわずかに超えています。
一度の書き込み4MBというところは気を付けたほうがよさそうですが、追加処理に最適という部分がポイントです。
いざ、TypeScriptでoutputbindingを使ってAppendBlobを利用しようと思ったのですが、どうやらC#しか対応していない模様です。
ということで、Function内でBlobSDKを使って書き込んでいきたいと思います。
Azure Function
ソースはこちら
import {AzureFunction, Context, HttpRequest} from "@azure/functions"
import {BlobServiceClient, StorageSharedKeyCredential} from "@azure/storage-blob"
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
// log
context.log(req.body)
const account = process.env.STORAGE_ACCOUNT_NAME || "";
const accountKey = process.env.STORAGE_ACCOUNT_KEY || "";
const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);
const blobServiceClient = new BlobServiceClient(
`https://${account}.blob.core.windows.net`,
sharedKeyCredential
);
// コンテナがなければ作る
const containerClient = await blobServiceClient.getContainerClient("sendgrid");
await containerClient.createIfNotExists();
// append blobが無ければ作る
const date = new Date().getDate();
const appendBlobClient = await containerClient.getAppendBlobClient(`activity-${getYYYYMMDD(new Date())}.log`);
await appendBlobClient.createIfNotExists();
// append blobに追記
let activity = JSON.stringify(req.body) + '\n';
await appendBlobClient.getAppendBlobClient().appendBlock(activity, activity.length);
context.res = {
status: 200
};
};
const getYYYYMMDD = (now: Date) => {
let yyyy = now.getFullYear();
let mm = ('00' + (now.getMonth() + 1)).slice(-2);
let dd = ('00' + now.getDate()).slice(-2);
const ymd = String(yyyy) + String(mm) + String(dd);
return ymd;
};
export default httpTrigger;
ローカル実行
-
Storageアカウントを作成
-
Azure Functionを作成
-
Functionの環境変数をローカルへダウンロード
- local.settings.jsonに環境変数が入ることを確認する
func azure functionapp fetch-app-settings <functionname>
5.ローカルで実行
- 正常に起動することを確認します。
func start
6.PostmanなどでJSONを投げ込んで、ストレージアカウントにデータが入ることを確認してください。
deploy
yarn run build
func azure functionapp publish <functionname>
SendGridでの利用
Functionでアプリキーをコピーします
http://function-url/eventwebhook?code=<アプリキー>
をsendgridに設定します。
その他注意点についてはこちらの記事を参照してください。