なつねこメモ

主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ 書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。

Next.js on Vercel で Mackerel へ OpenTelemetry のトレースを送信したい

Mackerel とは別のチームで働いているわたしです。 今回は最近 Mackerel が OpenTelemetry のトレーシングにも対応した様子なので、 Next.js on Vercel でもやってみよう!というメモ書き記事です。

mackerel.io

ということで、まずは OpenTelemetry 関連のパッケージを導入します。 今回は Vercel 組み込みの OpenTelemetry 関連機能では無く Mackerel を使用するので、 Next.js 公式サイトにある Manual OpenTelemetry Configuration の方でやっていきます。 Vercel 組み込みの関連機能や NewRelic / DataDog などの OTEL Integration を使う場合は @vercel/otel を使うとほぼコードの記述無く終わるので、そちらがオススメ。

nextjs.org

まずは以下のパッケージを導入します:

$ npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-proto

ドキュメントとは違い、最後は @opentelemetry/exporter-trace-otlp-proto パッケージを導入しているところがポイントです。 -http だとまだ対応していないよ、と返ってくる。

次に、 instrumentation.ts を作成し、以下のようにします。 今回はエッジロケーションで実行しているコードは特にないので飛ばしていますが、実行しているコードがある場合は NEXT_RUNTIME で追加で分岐して読み込んでおくとよいと思います。

export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    await import("./instrumentation.node");
  }
}

次に instrumentation.node.ts は以下のようにします。 必要最低限これでうごいた。公式で紹介されている設定例に合わせているけど、これで良いかは余り分かっていない......。

import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
import { Resource } from "@opentelemetry/resources";
import { NodeSDK } from "@opentelemetry/sdk-node";
import { BatchSpanProcessor, TraceIdRatioBasedSampler } from "@opentelemetry/sdk-trace-base";
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";

const traceExporter = new OTLPTraceExporter({
  url: "https://otlp-vaxila.mackerelio.com/v1/traces", // /v1/traces が必要
  headers: {
    Accept: "*/*",
    "Mackerel-Api-Key": process.env.MACKEREL_API_KEY!,
  },
});

const sdk = new NodeSDK({
  serviceName: "サービス名",
  resource: new Resource({
    [ATTR_SERVICE_NAME]: "サービス名",
  }),
  sampler: new TraceIdRatioBasedSampler(0.1), // 全部送ると騒がしいので 10%
  traceExporter,
  spanProcessors: [
    new BatchSpanProcessor(traceExporter, {
      maxExportBatchSize: 5000,
    }),
  ],
});

sdk.start();

この状態で next dev なり next start なりすると、アクセスしたときなどにトレース情報が送られる。こんな感じ:

ということで、メモでした。やり方は1日でガチャガチャやったものだからアレかもしれない。 もっと詳しい人いたらブログ書いてくれ!ではでは!