nuxt-otel-appinsights
v0.0.7
Published
Nuxt module to integrate OpenTelemetry (Azure Monitor) and Azure Application Insights.
Maintainers
Readme
nuxt-otel-appinsights
Nuxt module that wires:
- Server-side OpenTelemetry via Azure Monitor (
@azure/monitor-opentelemetry) - Client-side Azure Application Insights (
@microsoft/applicationinsights-web) - Nitro middleware to create SERVER spans for
/api/*requests
Install
pnpm add nuxt-otel-appinsights
# or
npm i nuxt-otel-appinsightsThis module bundles its runtime dependencies (Azure Monitor OpenTelemetry + Application Insights + OpenTelemetry APIs). You should not need to install those packages separately in consuming apps.
Usage
nuxt.config.ts:
export default defineNuxtConfig({
modules: ['nuxt-otel-appinsights'],
otel: {
// Server-side OpenTelemetry via Azure Monitor (Node/Nitro).
enableAppInsightsServer: true,
// Client-side Application Insights (browser plugin).
enableAppInsightsClient: true,
// Server-side incoming request filter.
// If non-empty, only requests whose path starts with any entry are traced.
// Set to [] to trace all incoming requests.
serverApiRouteFilter: ['/api/'],
// Third-party domains where we should NOT attach correlation headers.
correlationHeaderExcludedDomains: ['*.google-analytics.com', '*.sentry.io', 'api.iconify.design'],
// Third-party domains where we should NOT record browser dependency telemetry
// (fetch/XHR "RemoteDependencyData").
// Patterns supported:
// - 'example.com' (exact)
// - '*.example.com' (subdomains + apex)
dependencyExcludedDomainsClient: ['*.google-analytics.com', '*.launchdarkly.com', 'api.iconify.design'],
// Optional: ignore querystring-only navigations for pageview tracking.
// If only these query params change, we won't send an additional pageView.
// Also strips them from the `uri` sent with pageView telemetry.
pageViewIgnoreQueryParams: ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'gclid', 'fbclid'],
// Client batching interval (ms) for Application Insights. Default: 5_000.
maxBatchInterval: 5_000,
// Enables extra console logging from this module/plugins.
debug: false,
},
runtimeConfig: {
// server-only
otel: {
// Server plugin checks `APPLICATIONINSIGHTS_CONNECTION_STRING` first,
// then falls back to this runtimeConfig value.
appinsightsConnectionString:
process.env.APPLICATIONINSIGHTS_CONNECTION_STRING ||
process.env.NUXT_OTEL_APPINSIGHTS_CONNECTION_STRING ||
'',
},
public: {
// client
otel: {
// Connection string exposed to the browser plugin.
// Avoid putting secrets here; use a client-specific connection string.
appinsightsConnectionString: process.env.NUXT_PUBLIC_OTEL_APPINSIGHTS_CONNECTION_STRING || '',
// The client plugin reads its settings from `runtimeConfig.public.otel`.
// This module copies values from the `otel:` module options into `runtimeConfig.public.otel`.
// If you prefer, you can also set client options directly here instead of under `otel:`.
// dependencyExcludedDomainsClient: ['*.launchdarkly.com'],
// pageViewIgnoreQueryParams: ['utm_source', 'utm_medium', 'gclid'],
// maxBatchInterval: 5_000,
},
},
},
})Module order
This module registers:
- a Nitro plugin (server-side Azure Monitor OpenTelemetry)
- a Nuxt client plugin (Application Insights)
- a Nitro middleware (incoming request SERVER spans)
Nuxt runs module setup in the order listed in modules, and plugin/middleware registration order follows from that.
Recommendation: put nuxt-otel-appinsights early (ideally first) in your modules array so tracing initializes as early as possible and any plugins/middleware you add later are more likely to run under an active trace/span.
Env vars
- Server:
APPLICATIONINSIGHTS_CONNECTION_STRING(preferred) orNUXT_OTEL_APPINSIGHTS_CONNECTION_STRING - Client:
NUXT_PUBLIC_OTEL_APPINSIGHTS_CONNECTION_STRING
Enriching server spans (custom attributes + events)
This module installs a Nitro event handler middleware that creates a SERVER span for incoming requests.
There are two supported ways for a consuming app to enrich those spans:
1) Provide attributes via event.context.otelSpanAttributes (recommended)
In any server handler/middleware, set event.context.otelSpanAttributes to a plain object of primitive values.
The module middleware will attach these to the SERVER span.
Example: add authenticated-user attributes from your auth layer:
export default defineEventHandler((event) => {
// Example only: adapt to your auth/session setup.
const authenticatedUserId = event.context.auth?.user?.id
const dealId = event.context.auth?.dealId
// Only primitive values are copied to span attributes.
event.context.otelSpanAttributes = {
...(event.context.otelSpanAttributes || {}),
'enduser.id': authenticatedUserId,
'deal.id': dealId,
}
})2) Add events/attributes directly on the active SERVER span
For advanced scenarios, the middleware also exposes the span instance as event.context.serverSpan.
You can safely treat this as best-effort (it may be missing if tracing is disabled).
export default defineEventHandler((event) => {
const span = (event.context as any).serverSpan
if (span) {
span.setAttribute('app.feature', 'checkout')
span.addEvent('checkout validation started')
}
return { ok: true }
})In Application Insights, these show up on the request trace as custom dimensions/attributes and span events.
Setting the current user on the client
The client plugin injects a helper you can call from your app:
useNuxtApp().$setAppInsightsUserContext({ authenticatedUserId })
This sets the authenticated user context (maps to ai.user.authUserId).
Example: set on login, clear on logout
const { $setAppInsightsUserContext } = useNuxtApp()
// after login
$setAppInsightsUserContext({ authenticatedUserId: user.id })
// on logout
$setAppInsightsUserContext(null)Example: keep it in sync with reactive auth state
export default defineNuxtPlugin(() => {
const { $setAppInsightsUserContext } = useNuxtApp()
const auth = useAuth() // your composable
watch(
() => auth.user?.id,
(id) => $setAppInsightsUserContext(id ? { authenticatedUserId: id } : null),
{ immediate: true },
)
})Notes
- Do not put secrets in public runtime config.
- The module is intentionally auth-agnostic; host apps can inject identity into spans via
event.context.otelSpanAttributes.
Development
pnpm install
pnpm devReleasing
Maintainers: see RELEASING.md.
