🔍

Next.jsのログをApplication Insightsに送る

に公開

Next.jsのログをApplication Insightsのtraceに送るのでハマったので手順をメモ

コードはここに置いてある

https://github.com/hirokisakabe/azure-application-insights-nextjs-sample

前提

  • App Service から Application Insights へ
  • App ServiceはDockerイメージ利用
  • Next.js
  • ロガーはwinston

手順

Azureのリソースを作成する

次のような感じでリソースを定義して、terraform applyする。

https://github.com/hirokisakabe/azure-application-insights-nextjs-sample/blob/main/infra/main.tf

注意点として、App Serviceの環境変数にはAPPLICATIONINSIGHTS_CONNECTION_STRINGを設定しておく。

main.tf
  app_settings = {
    APPLICATIONINSIGHTS_CONNECTION_STRING = azurerm_application_insights.this.connection_string
  }

Next.jsのコードを書く

必要なライブラリを追加する

npm install @azure/monitor-opentelemetry @opentelemetry/winston-transport winston

instrumentation.tsでAzure Monitorの初期設定をする

instrumentation.ts
import { useAzureMonitor } from "@azure/monitor-opentelemetry";

export function register() {
  console.log("Registering Azure Monitor instrumentation...");

  // eslint-disable-next-line react-hooks/rules-of-hooks
  useAzureMonitor();

  console.log("Azure Monitor instrumentation registered successfully.");
}

どこでも良いが、今回はpage.tsxでログを出すことにする

page.tsx
import winston from "winston";
import { OpenTelemetryTransportV3 } from "@opentelemetry/winston-transport";

export const dynamic = "force-dynamic";

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console(),
    new OpenTelemetryTransportV3({}),
  ],
});

export default function Home() {
  logger.info("ほげほげ");

  ...

イメージをpushする

特別変なことはしていないが、流れをメモ

az login
az acr login --name registryappinextjs

docker build -t registryappinextjs.azurecr.io/app --platform=linux/amd64 .

docker push registryappinextjs.azurecr.io/app

動作確認

イメージを更新するために、App Serviceを再起動して...

App Serviceにアクセスする

念の為、App Serviceのログストリームにログが表示されていることを確認して...

Application Insightsにtraceが表示されているはず。反映まで少しラグがあるので注意

ハマったところ

Next.jsのmiddlewareを使っている場合

middleware.tsが配置されていると、Edge Runtimeでの処理が走る(instrumentation.tsにも波及する)

useAzureMonitorの処理はNode.js Runtimeでしか動作しないので、Edge Runtimeではエラーとなる。

https://nextjs.org/docs/app/guides/instrumentation#importing-runtime-specific-code

に記載の通り、NEXT_RUNTIMEによる分岐を挟む必要が出てくる。

instrumentation.ts
export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    await import("./instrumentation-node");
  }
}
instrumentation-node.ts
import { useAzureMonitor } from "@azure/monitor-opentelemetry";

console.log("Registering Azure Monitor instrumentation...");

// eslint-disable-next-line react-hooks/rules-of-hooks
useAzureMonitor();

console.log("Azure Monitor instrumentation registered successfully.");

instrumentationOptionsでwinstonをenableにしてもtraceは出力されない

.NET、Java、Node.js、Python アプリケーション用の Azure Monitor OpenTelemetry を追加および変更するに記載されているinstrumentationOptionsを利用して次のように設定してもtraceは出力されない。

instrumentation.ts
import { useAzureMonitor } from "@azure/monitor-opentelemetry";

export function register() {
  console.log("Registering Azure Monitor instrumentation...");

  // eslint-disable-next-line react-hooks/rules-of-hooks
  useAzureMonitor({
    instrumentationOptions: {
      winston: {
        enabled: true,
      }
    }
  });

  console.log("Azure Monitor instrumentation registered successfully.");
}

参考

https://nextjs.org/docs/app/guides/instrumentation

https://learn.microsoft.com/ja-jp/azure/azure-monitor/app/opentelemetry-enable?tabs=nodejs

https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/winston-transport

Discussion