Azure / static-web-apps

Azure Static Web Apps. For bugs and feature requests, please create an issue in this repo. For community discussions, latest updates, kindly refer to the Discussions Tab. To know what's new in Static Web Apps, visit https://aka.ms/swa/ThisMonth
https://aka.ms/swa
MIT License
330 stars 56 forks source link

Preloading Application Insights for SSR Next.js #1269

Open mateubo opened 1 year ago

mateubo commented 1 year ago

I'm having a hard time initializing Application Insights for server-side of Next.js deployed in standalone mode. that is being deployed using AzureStaticWebApp task from a DevOps pipeline.

Following this guide does not help to achieve that: https://learn.microsoft.com/en-us/azure/static-web-apps/deploy-nextjs-hybrid#enable-logging-for-nextjs I tried with a custom startup script as described in the tutorial Example preload script for Application Insights + Next.js but learned that it does not get executed.

I also tried instrumentation hooks introduced recently in Next.js but they do not get called too.

Being desperate, I modified the build script to inject custom code into the generated .next/standalone/server.js but it seems this is not used.

Does anyone know how to load applicationinsights nodejs lib?

rbourdon commented 1 year ago

I was able to preload it using Next.js's instrumentation.

For example

load-appinsights.js

const appInsights = require("applicationinsights");
appInsights
  .setup(process.env.APPINSIGHTS_CONNECTION_STRING)
  .setAutoCollectConsole(true)
  .setAutoCollectDependencies(true)
  .setAutoCollectExceptions(true)
  .setAutoCollectHeartbeat(true)
  .setAutoCollectPerformance(true, true)
  .setAutoCollectRequests(true)
  .setAutoDependencyCorrelation(true)
  .setDistributedTracingMode(appInsights.DistributedTracingModes.AI_AND_W3C)
  .setSendLiveMetrics(true)
  .setUseDiskRetryCaching(true);
appInsights.start();

instrumentation.ts

export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    await import("src/utils/load-appinsights.js");
  }
}

next.config.js

//...rest of your config
experimental: {
    instrumentationHook: true,
}
mburumaxwell commented 7 months ago

Found a possibly easier way using @vercel/otel

pnpm install @vercel/otel @opentelemetry/api@1.7.0 @azure/monitor-opentelemetry-exporter@next --save-exact

Then your instrumentation.ts

import { AzureMonitorTraceExporter } from '@azure/monitor-opentelemetry-exporter';
import { registerOTel } from '@vercel/otel';

export async function register() {
  registerOTel({
    serviceName: 'your-project-name',
    traceExporter: new AzureMonitorTraceExporter({
      connectionString: 'InstrumentationKey=<...>;IngestionEndpoint=https://...;LiveEndpoint=https://...',
      // you can read from ENV if you prefer to
      // connectionString: process.env.APP_INSIGHTS_CONNECTION_STRING,
    }),
  });
}

https://maxwellweru.com/blog/2024/03/nextjs-opentelemetry-with-azure-monitor

xInfinitYz commented 2 months ago

Found a possibly easier way using @vercel/otel

pnpm install @vercel/otel @opentelemetry/api@1.7.0 @azure/monitor-opentelemetry-exporter@next --save-exact

Then your instrumentation.ts

import { AzureMonitorTraceExporter } from '@azure/monitor-opentelemetry-exporter';
import { registerOTel } from '@vercel/otel';

export async function register() {
  registerOTel({
    serviceName: 'your-project-name',
    traceExporter: new AzureMonitorTraceExporter({
      connectionString: 'InstrumentationKey=<...>;IngestionEndpoint=https://...;LiveEndpoint=https://...',
      // you can read from ENV if you prefer to
      // connectionString: process.env.APP_INSIGHTS_CONNECTION_STRING,
    }),
  });
}

https://maxwellweru.com/blog/2024/03/nextjs-opentelemetry-with-azure-monitor

I did set it up based on your article with June 2024 Update, nevertheless I'm not seeing anything on the application insights part even after 30 min wait.

src/instrumentation.ts

import type { SpanExporter } from '@opentelemetry/sdk-trace-base';
import { registerOTel } from '@vercel/otel';

export async function register() {
  let traceExporter: SpanExporter | undefined;

  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { AzureMonitorTraceExporter } = await import(
      '@azure/monitor-opentelemetry-exporter'
    );
    traceExporter = new AzureMonitorTraceExporter({
      connectionString: process.env.APP_INSIGHTS_CONNECTION_STRING,
    });
  }

  registerOTel({ serviceName: 'AgencyPortal', traceExporter });
}

InstrumentationHook registered correctly

imagen

imagen

imagen

Any ideas ?

mburumaxwell commented 2 months ago

Found a possibly easier way using @vercel/otel pnpm install @vercel/otel @opentelemetry/api@1.7.0 @azure/monitor-opentelemetry-exporter@next --save-exact Then your instrumentation.ts

import { AzureMonitorTraceExporter } from '@azure/monitor-opentelemetry-exporter';
import { registerOTel } from '@vercel/otel';

export async function register() {
  registerOTel({
    serviceName: 'your-project-name',
    traceExporter: new AzureMonitorTraceExporter({
      connectionString: 'InstrumentationKey=<...>;IngestionEndpoint=https://...;LiveEndpoint=https://...',
      // you can read from ENV if you prefer to
      // connectionString: process.env.APP_INSIGHTS_CONNECTION_STRING,
    }),
  });
}

https://maxwellweru.com/blog/2024/03/nextjs-opentelemetry-with-azure-monitor

I did set it up based on your article with June 2024 Update, nevertheless I'm not seeing anything on the application insights part even after 30 min wait.

src/instrumentation.ts

import type { SpanExporter } from '@opentelemetry/sdk-trace-base';
import { registerOTel } from '@vercel/otel';

export async function register() {
  let traceExporter: SpanExporter | undefined;

  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { AzureMonitorTraceExporter } = await import(
      '@azure/monitor-opentelemetry-exporter'
    );
    traceExporter = new AzureMonitorTraceExporter({
      connectionString: process.env.APP_INSIGHTS_CONNECTION_STRING,
    });
  }

  registerOTel({ serviceName: 'AgencyPortal', traceExporter });
}

InstrumentationHook registered correctly

imagen

imagen

imagen

Any ideas ?

I have this very setup and it has been working since up to as late as a few seconds ago. When debugging locally it takes about 1-3 minutes to show up on application insights.

Screenshot 2024-08-23 at 6 34 00 PM

To see what is happening with OTEL, you can set OTEL_LOG_LEVEL=debug in your .env file, restart the app, open a page a couple of times (generates traces), then you will see logs like:

  ▲ Next.js 14.2.5 (turbo)
  - Local:        http://localhost:3000
  - Environments: .env
  - Experiments (use with caution):
    · instrumentationHook

 ✓ Starting...
@opentelemetry/api: Registered a global for diag v1.9.0.
@vercel/otel: Configure propagator: tracecontext
@vercel/otel: Configure propagator: baggage
@vercel/otel: Configure sampler:  parentbased_always_on
@opentelemetry/api: Registered a global for trace v1.9.0.
@opentelemetry/api: Registered a global for context v1.9.0.
@opentelemetry/api: Registered a global for propagation v1.9.0.
@vercel/otel: Configure instrumentations: fetch undefined
@vercel/otel: started <serviceName> nodejs
Fo found resource. r {
  _attributes: {},
  asyncAttributesPending: false,
  _syncAttributes: {},
  _asyncAttributesPromise: undefined
}
Exporting 1 envelope(s)
 ✓ Ready in 1484ms
Exporting 1 span(s). Converting to envelopes...
Exporting 2 envelope(s)
 ○ Compiling / ...
 ✓ Compiled / in 3s
 GET / 200 in 3291ms
 ✓ Compiled /favicon.ico in 173ms
 GET /icon.png?icon.499d3844.png 200 in 298ms
 GET /favicon.ico?favicon.196e4467.ico 200 in 310ms
Exporting 16 span(s). Converting to envelopes...
Exporting 17 envelope(s)
Searching for filesystem persisted files
Searching for filesystem persisted files

Otherwise, there should be a meaningful error message