Closed4

Next.js サーバーの o11y 周りで調べたことのメモ

nissy-devnissy-dev

Metrics

Prom client を runtime metrics の収集に使っている。デフォルトだと Prometheus の推奨のメトリクス + Node.js 固有の event loop などのログなどを収集する。

There are some default metrics recommended by Prometheus itself. To collect these, call collectDefaultMetrics. In addition, some Node.js-specific metrics are included, such as event loop lag, active handles, GC and Node.js version. See lib/metrics for a list of all metrics.

https://github.com/siimon/prom-client

Custom Metrics は Otel のライブラリを使って収集している。リクエストの回数とか。
https://github.com/open-telemetry/opentelemetry-js/tree/main/api

できれば Otel に寄せたいが、runtime metrics に関する issue は open のままになっている。

https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1106

現状の整理としてはこんな感じか

nissy-devnissy-dev

Trace

ローカルで trace を確認する場合は jaeger の all ion one イメージを otel collector と一緒に立ち上げるのが楽だった。

  # coimpose.yaml の定義
  jaeger:
    image: jaegertracing/all-in-one:1.56.0
    ports:
      - '16686:16686' # frontend
      - '4317:4317' # OTLP gRPC receiver
    environment:
      - COLLECTOR_OTLP_ENABLED=true

Next 側で定義している span について

https://nextjs.org/docs/pages/building-your-application/optimizing/open-telemetry#default-spans-in-nextjs

実装の概要としては、opentelemtry js sdk の trace API の wrapper を用意して、それを内部のいろんなところで使っているという感じ。

https://github.com/vercel/next.js/blob/7552a7a0efe176de3dfe4dc1078650fe6ef97a49/packages/next/src/server/lib/trace/tracer.ts

instrumentationHookを true にすると root の instrumentation.ts が読み込まれる。以下のようなシンプルな sdk の初期化処理が書かれているイメージ。

import { NodeSDK } from '@opentelemetry/sdk-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource } from '@opentelemetry/resources'
import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'
 
const sdk = new NodeSDK({
  resource: new Resource({
    [SEMRESATTRS_SERVICE_NAME]: 'next-app',
  }),
  spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()

sdk-trace-node と trace api とかの連携の流れがよくわかってないので、もう少し掘り下げる

nissy-devnissy-dev

logs

pino で構造化しているが、request id を渡せてない気もするので、いい感じにした方がいいかもしれない。Pino の使い方は、以下のブログが参考になる。

https://betterstack.com/community/guides/logging/how-to-install-setup-and-use-pino-to-log-node-js-applications/

request id を渡す方法として一番シンプルなのが http header を使う方法。以下のブログとかも参考になりそう。

https://michaelangelo.io/blog/logging-nextjs

ただ最近だと AsyncLocalStorage を使うのが主流だと思う。

また「いい感じにした方がいいかもしれない」と書いてるのは、Otel の node の自動計装パッケージを使うと、opentelemetry-instrumentation-pino が導入され、pino のログに trace のコンテキストが自動で挿入されるから。 trace のコンテキストがあれば、trace id などを使えば ログを引けそうな感じもある。ここら辺、server actions とかも考慮していい感じに設計したい。

https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-pino

4年ほど前から更新されてないが、pino が提供しているサンプルもある。custom server 構成で、フロントエンドのエラーを /logs のエンドポイントへ送信するようにしている。(pino の trasmit 機能を使っている) /logs のエンドポイントは、next.js が動くサーバーでさばいている。
https://github.com/pinojs/pino-nextjs-example

/logs を定義している箇所

https://github.com/pinojs/pino-nextjs-example/blob/a9939bc9786165eb66edb23ec0b987052d7dcc35/server.js#L27-L57

このスクラップは2024/05/13にクローズされました