15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

自分の担当しているアプリケーションにおいて、ログ基盤をどのように実装したかを記事にまとめようと思います。
ログ基盤とは、アクセスログやエラーログなどが該当します。

ログ基盤の構図

下記の構図のように設定しております。
今回は、下記における Client と Nuxt Server 側の話となります。

名称未設定ファイル.drawio.png

CloudWarch と BigQuery によって、Nuxt 側では、logger でログを吐き出すだけのロジックとなったので、皆さんの方でも参考になれば幸いです。

ログの内容

吐き出している内容は下記となります。

  • アクセスログ
    • ID
      • 識別 ID となります
      • crypto を使用した UUID でもいいですし、AWS の trace ID を使用して、識別 ID を付与します
    • time
      • 時間
      • CloudWatch 側で記録されるものでもありますが、システム時刻を載せるためにも記録しています
    • path
      • アクセスしたパス情報
    • query
      • パスに付与されているクエリ情報
    • userID
      • ユーザー ID
      • ログインしていなければ Null
    • renderingMode
      • SSR なのか CSR なのかを記録しています
    • status
      • アクセスした際の HTTP Status Code
  • エラーログ
    • ID
      • 識別 ID となります
      • crypto を使用した UUID でもいいですし、AWS の trace ID を使用して、識別 ID を付与します
    • time
      • 時間
      • CloudWatch 側で記録されるものでもありますが、システム時刻を載せるためにも記録しています
    • path
      • アクセスしたパス情報
    • query
      • パスに付与されているクエリ情報
    • userID
      • ユーザー ID
      • ログインしていなければ Null
    • renderingMode
      • SSR なのか CSR なのかを記録しています
    • status
      • エラー HTTP Status Code
    • message
      • エラーメッセージ内容
    • stackTrace
      • エラースタックトレース情報

アクセスログ

アクセスログは、Nuxt における global middleware で出力します。
サーバ側で吐き出すため、ログに出力するための API を Nuxt Server 側に用意する必要もあります。

middleware/postAccessLog.global.ts
export default defineNuxtRouteMiddleware(async (to) => {
  if (process.env.NODE_ENV === 'production') {
    $fetch.raw('/api/access-logs', {
      method: 'POST',
      body: {
        /* 必要な情報を送信 */
      }
    })
  }
})

エラーログ

エラーログは、Nuxt のエラーハンドラーで検知したものを送信するような仕組みとしました。

plugins/globalErrorHandler.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('vue:error', (error, instance, info) => {
    if (process.env.NODE_ENV === 'production') {
      $fetch.raw('/api/error-logs', {
        method: 'POST',
        body: {
          /* 必要な情報を送信 */
        }
      })
    }
  })

  nuxtApp.hook('app:error', (error) => {
    if (process.env.NODE_ENV === 'production') {
      $fetch.raw('/api/error-logs', {
        method: 'POST',
        body: {
          /* 必要な情報を送信 */
        }
      })
    }
  })
})

実際のログ出力処理

ログ出力では consola を使用した実装を行いました。
というのも、Nuxt の logger は以前から consola を使用しているということもあったので、そちらを使用。
また、useLogger composables でも裏側では consola を使用しているため、そちらを採用しました。

import { consola } from 'consola'

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig()
  consola.level = config.public.logLevel

  consola.log(
    JSON.stringify({
      ...(await readBody(event)),
      /* その他必要な情報を記載 */
    })
  )

  setResponseStatus(event, 204)
})

今回のログ基盤を導入したことによって

どのユーザーがどのタイミングでアクセスし、エラーになったのかが明確になりました。
自分の担当させていただいているアプリケーションは1,000を優に超えるトラフィック数になるため、ものすごいログの量ですが、それでもお問い合わせの際のヒントになったりしています。

ログ基盤の構築として、こんなのもあるよ〜の共有でした。
他の方の力になれば幸いです。

15
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?