Vercelでは、出力したログを各プロジェクトのFunctions画面でリアルタイム表示させることができるが、保存まではされない。

ログを永続的に保持しておくためには、外部のロギングサービスと連携する必要がある。

今回は、テスト用に作成したNext.jsアプリケーションにおいて直近のアクセスを記録させてみた。

ロギングサービスの選定

現在、Vercelと連携が可能なロギングサービスは次の7つが提供されている。

  • GraphJSON
  • Axiom
  • Logtail
  • Logalert
  • Sematext Logs
  • Logflare
  • Datadog

https://vercel.com/integrations

前述の通り、テスト用のアプリケーションに対してアクセスを記録したいだけなので、低コストで運用できるもので選定した。

Sematextは、Basicプラン(無料)にも関わらず、ログを1日あたり500MBまでかつ最長7日間まで保持することができるので、こちらを選択した。

sematext

事前にSematextのアカウントを作成しておく。
https://apps.sematext.com/ui/registration

データセンタは、北米かヨーロッパが選択可能なので、居住区に合わせた地域を選択すると良い。(今回は北米を選択した。)

img_3.png

また、GoogleアカウントやGitHubの登録情報を利用しての登録も可能。

導入

Sematext-logsの追加(Vercel側)

VercelのSematext-logsページの「Add integration」ボタンを押下。

ポップアップが表示されるので、画面の手順に従い操作していく。

img_1.png

対象のログアプリを選択する

対象のVercelプロジェクトとログを集計するアプリを選択する。

各種項目を選択して「Create Log Drains」ボタンを押下で、初期導入は完了となる。

img_4.png

また、Sematext側にVercelのログアプリが作成されていない場合は作成しておく。

img_5.png

使い方

ログアプリの一覧から、予め作成したアプリを選択する。
https://apps.sematext.com/ui/logs

最初に表示されるサマリページには、各種統計情報が表示される。
img_9.png

Exploreページでは、保存したログメッセージや記録日時などの情報を閲覧することができる。

Vercelにデプロイするアプリケーションの実装

サーバーサイド(Node.js)側で出力したログに対して、Sematextはログの収集ができるので、アプリケーションは以下のような実装とした。

getServerSideProps内で接続元のIPアドレス、ホスト名、UserAgentをログとして吐き出す。

index.tsxexport const getServerSideProps: GetServerSideProps = async(context) => {
    const { req } = context;

    const ipAddress = req.headers["x-forwarded-for"]
        ? String(req.headers["x-forwarded-for"]).split(',')[0]
        : req.connection.remoteAddress
            ? req.connection.remoteAddress
            : "";
            
    const userAgent = req.headers["user-agent"];


    const getHostName = (ipAddress: string): Promise<string> => {
        return new Promise(function(resolve, reject) {
            dns.lookupService(ipAddress, 22, function (err, hostname, service) {
                if (err) {
                    return reject(err);
                }
                resolve(hostname);
            });
        });
    };
    const hostName = await getHostName(ipAddress);

    console.log(`IP Address: ${ipAddress}, Host Name: ${hostName}, User Agent: ${userAgent}`);

    return {
        props: {}
    }
}