はじめに
自分の担当しているアプリケーションにおいて、ログ基盤をどのように実装したかを記事にまとめようと思います。
ログ基盤とは、アクセスログやエラーログなどが該当します。
ログ基盤の構図
下記の構図のように設定しております。
今回は、下記における Client と Nuxt Server 側の話となります。
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
- 識別 ID となります
- crypto を使用した UUID でもいいですし、AWS の trace ID を使用して、識別 ID を付与します
-
time
- 時間
- CloudWatch 側で記録されるものでもありますが、システム時刻を載せるためにも記録しています
-
path
- アクセスしたパス情報
-
query
- パスに付与されているクエリ情報
-
userID
- ユーザー ID
- ログインしていなければ Null
-
renderingMode
- SSR なのか CSR なのかを記録しています
-
status
- エラー HTTP Status Code
-
message
- エラーメッセージ内容
-
stackTrace
- エラースタックトレース情報
-
ID
アクセスログ
アクセスログは、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を優に超えるトラフィック数になるため、ものすごいログの量ですが、それでもお問い合わせの際のヒントになったりしています。
ログ基盤の構築として、こんなのもあるよ〜の共有でした。
他の方の力になれば幸いです。
Views: 0