Observability and Instrumentation
This document describes the observability setup for the Dialogporten Frontend application, covering both the Backend-for-Frontend (BFF) and Frontend instrumentation.
Overview
Section titled âOverviewâThe application uses a hybrid approach to observability:
- BFF: OpenTelemetry (OTEL) with OTLP exporter to Azure Container Apps OTEL Collector
- Frontend: Application Insights SDK directly
Both components are configured to work together, providing end-to-end tracing correlation through trace IDs.
Backend-for-Frontend (BFF) Instrumentation
Section titled âBackend-for-Frontend (BFF) InstrumentationâTechnology Stack
Section titled âTechnology Stackâ- OpenTelemetry SDK: Core instrumentation framework
- OTLP Exporter: Sends telemetry data to Azure Container Apps OTEL Collector
- Pino OpenTelemetry Transport: Automatic log instrumentation
- Custom Instrumentations: Additional OTEL instrumentations for specific libraries
Configuration
Section titled âConfigurationâThe BFF uses OpenTelemetry with the OTLP exporter configured in packages/bff/src/instrumentation.ts:
import { NodeSDK } from '@opentelemetry/sdk-node';import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';Key Features:
Section titled âKey Features:â- OTLP Integration: Exports to Azure Container Apps OTEL Collector which forwards to Application Insights
- Resource Attribution: Custom service name and instance ID
- Multi-Library Support: HTTP, GraphQL, Redis, PostgreSQL, and Fastify instrumentation
- Trace ID Propagation: Adds
X-Trace-Idheader to all responses - Automatic Log Instrumentation: All logs and exceptions are sent through OpenTelemetry
Enabled Instrumentations:
Section titled âEnabled Instrumentations:â- HTTP Instrumentation: Tracks incoming/outgoing HTTP requests
- GraphQL Instrumentation: Monitors GraphQL operations with span merging
- IORedis Instrumentation: Tracks Redis operations
- Fastify OTEL Instrumentation: Framework-specific instrumentation
- PostgreSQL Instrumentation: Database query tracking
Filtering and Optimization:
Section titled âFiltering and Optimization:â- Health Check Filtering: Excludes
/api/livenessand/api/readinessendpoints - OPTIONS Request Filtering: Ignores CORS preflight requests
- GraphQL Optimization: Ignores trivial resolver spans and merges related spans
Logging Integration
Section titled âLogging IntegrationâThe BFF uses Pino logger with OpenTelemetry transport for automatic log instrumentation:
Production Mode (with OTEL endpoint):
Section titled âProduction Mode (with OTEL endpoint):â- All logs (trace, debug, info, warn, error, fatal) are sent through OpenTelemetry
- Logs are automatically correlated with traces using trace context
- No console output - all logs go through OTLP exporter
Local Development Mode (without OTEL endpoint):
Section titled âLocal Development Mode (without OTEL endpoint):â- Logs are output to console with pretty formatting or json formatting
- No telemetry is sent to remote collectors
The logger automatically detects the presence of OTEL_EXPORTER_OTLP_ENDPOINT environment variable to determine which mode to use.
Trace ID Propagation
Section titled âTrace ID PropagationâThe BFF automatically adds trace IDs to response headers:
// In fastifyHeaders.tsconst currentSpan = trace.getActiveSpan();if (currentSpan?.spanContext().traceId) { const traceId = currentSpan.spanContext().traceId; reply.header('X-Trace-Id', traceId);}This enables correlation with frontend telemetry.
Frontend Instrumentation
Section titled âFrontend InstrumentationâTechnology Stack
Section titled âTechnology Stackâ- Application Insights Web SDK: Direct integration with Azure Application Insights
- React Plugin: React-specific instrumentation
- Manual Dependency Tracking: Custom fetch/XHR tracking
Configuration
Section titled âConfigurationâThe frontend uses Application Insights SDK directly, configured in packages/frontend/src/analytics/analytics.ts:
import { ApplicationInsights } from '@microsoft/applicationinsights-web';import { ReactPlugin } from '@microsoft/applicationinsights-react-js';Key Features:
Section titled âKey Features:â- React Integration: Automatic component lifecycle tracking
- Route Tracking: Manual page view tracking via the
usePageTrackinghook (enableAutoRouteTracking: false), limited to an allowlist of routes - Error Handling: Manual
trackExceptioncalls with noise filtering (enableUnhandledPromiseRejectionTracking: false) - CORS Correlation: Cross-origin request correlation
- Manual Dependency Tracking: Custom fetch tracking with backend correlation
Configuration Highlights:
Section titled âConfiguration Highlights:â- Disabled Automatic Tracking:
disableAjaxTracking: true, disableFetchTracking: true - Enhanced Correlation:
enableCorsCorrelation: true - Debug Mode: Not enabled. Do not set
enableDebugâ it makes_throwInternalthrow beforeclearSent, which wedges failed telemetry in sessionStorage until it trips the 48h limit - Sampling:
samplingPercentage: 100â no client-side sampling
Consent
Section titled âConsentâanalytics.ts does not load Application Insights at import time. useAnalyticsConsent (called from App) decides whether it may run and calls setAnalyticsEnabled.
Application Insights only runs when global.enableCookieBanner is on and the user has accepted statistics cookies in the cookie banner. With the flag off there is no way to give consent, so it stays off. Rejecting, or withdrawing consent through the footerâs cookie link, unloads the SDK if it is running and removes its ai_user and ai_session cookies and the ai_session localStorage entry.
Trace Correlation
Section titled âTrace CorrelationâThe frontend correlates with backend traces through the trackFetchDependency function:
const trackFetchDependency = async ( name: string, fetchPromise: Promise<Response>, startTime: number = Date.now(),): Promise<Response> => { // ... await the promise, record status and duration ...
// Extract backend trace ID from response backendTraceId = response.headers.get('X-Trace-Id') || backendTraceId;
// Track dependency with correlation Analytics.trackDependency({ id: backendTraceId, target: targetUrl, name, duration, success, responseCode: responseStatus, properties: { 'backend.traceId': backendTraceId, 'correlation.source': 'backend-response', 'request.type': name.includes('GraphQL') ? 'graphql' : 'http', }, type: 'HTTP', });};Note: dependency telemetry is currently discarded before it leaves the browser. All
deployed environments set applicationInsightsDisableDependencyTracking to 'true', and the
telemetry initializer drops every RemoteDependencyData envelope when that flag is on. The
correlation described above works, but the resulting telemetry does not reach Application
Insights until that parameter is flipped in .azure/applications/frontend/*.bicepparam.
Error Filtering
Section titled âError FilteringâThe frontend implements intelligent error filtering to reduce noise:
- Browser Extension Errors: Filters out errors from browser extensions
- Cross-Origin Errors: Excludes generic âScript errorâ messages
- Stack Trace Analysis: Examines parsed stack traces for extension URLs
End-to-End Correlation Flow
Section titled âEnd-to-End Correlation FlowâsequenceDiagram
participant Frontend
participant BFF
participant Backend API
participant Application Insights
Frontend->>BFF: GraphQL Request
Note over BFF: OTEL creates span with trace ID
BFF->>Backend API: Downstream request
Backend API->>BFF: Response
BFF->>Frontend: Response + X-Trace-Id header
Note over Frontend: Extract trace ID from header
Frontend->>Application Insights: Dependency telemetry with backend trace ID
BFF->>Application Insights: Span telemetry via OTLP â OTEL Collector â App Insights
Note over Application Insights: Correlated telemetry with matching trace IDs
Environment Configuration
Section titled âEnvironment ConfigurationâBFF Environment Variables
Section titled âBFF Environment Variablesâ# OpenTelemetry OTLP endpoint (automatically set by Azure Container Apps)OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
# Trace sampling ratio, 0-1 (optional, defaults to 1 = sample everything)OTEL_TRACES_SAMPLER_ARG="1"
# OpenTelemetry protocol (parsed but NOT honoured - see note below)OTEL_EXPORTER_OTLP_PROTOCOL="grpc" # Options: http/protobuf, http/json, grpcNote: OTEL_EXPORTER_OTLP_PROTOCOL is validated and logged at startup, but the exporters
in instrumentation.ts are hardcoded to the gRPC variants, so changing it has no effect.
Note: When OTEL_EXPORTER_OTLP_ENDPOINT is not set, the BFF runs in local development mode with console output for logs and traces.
Frontend Configuration
Section titled âFrontend ConfigurationâThe frontend receives its instrumentation key through a global variable. For details on how to add new environment variables, see the Environment Variables documentation.
Monitoring and Debugging
Section titled âMonitoring and DebuggingâKey Metrics to Monitor
Section titled âKey Metrics to Monitorâ- Request Duration: End-to-end request timing
- Error Rates: Application and dependency errors
- Dependency Failures: Backend API failures
- GraphQL Operations: Query/mutation performance
- Database Performance: PostgreSQL query timing
- Redis Performance: Cache operation timing
Debugging Tips
Section titled âDebugging Tipsâ- Trace ID Correlation: Use
X-Trace-Idheader to correlate frontend and backend logs - Debug Mode: Enable debug mode in development for detailed telemetry logs
- Sampling: Adjust sampling percentage for development vs. production