Skip to content

Azure Container Apps

In Azure, telemetry from every container ends up in Application Insights by way of the managed OpenTelemetry agent that runs on the Container App Environment. Apps speak plain OTLP/gRPC to the agent's localhost sidecar; the platform forwards. The application code does not talk to App Insights directly — we don't use @azure/monitor-opentelemetry server-side.

The agent injects OTEL_EXPORTER_OTLP_ENDPOINT automatically; apps don't pin the endpoint in Terraform. The agent is configured on the Container App Environment, owned by the platform team outside this repo. See the component map for where the agent sits in the larger topology.

Per-app environment variables

VariableSet byPurpose
OTEL_SERVICE_NAMEAppResource attribute, drives cloud_RoleName in App Insights
OTEL_RESOURCE_ATTRIBUTESApp (service.namespace=feyenoord)Resource attributes, parsed by envDetector
OTEL_TRACES_SAMPLEROnly api-gateway (Traefik, Go OTel SDK)Sampler strategy — see note below
OTEL_TRACES_SAMPLER_ARGApp, per env (tfvars)Root sampling ratio
OTEL_EXPORTER_OTLP_ENDPOINTPlatform agentInjected automatically — do not set in Terraform
OTEL_EXPORTER_OTLP_PROTOCOLApp, when applicablegrpc

OTEL_TRACES_SAMPLER is api-gateway only

Node services using @repo/observability hard-wire ParentBased(TraceIdRatio) in node/sdk.ts and never read OTEL_TRACES_SAMPLER. The Apollo Router reads its sampler from router.yaml. Only Traefik (api-gateway) reads OTEL_TRACES_SAMPLER from its embedded Go OTel SDK. Setting it on the other apps would imply a knob that doesn't exist.

match-gateway deliberately omits OTEL_TRACES_SAMPLER_ARG. The SDK default is 1.0 — full trace coverage required for the live Stats Perform event feed.

Sampling per environment

EnvironmentRatioRationale
TST1.0Catch everything during integration testing
ACC1.0Catch everything during acceptance testing
PRD0.1App Insights cost control; native app's 5% decision propagates regardless

Because every component runs parentbased_traceidratio, traces the native app marks sampled=01 always span the whole chain regardless of the per-service ratio. The ratio only governs server-originated work (cron jobs, queue consumers, internal HTTP without inbound traceparent).

Without parent-based sampling everywhere, each hop would flip its own coin and the chance of a complete distributed trace would collapse multiplicatively (5% × 10% × 10% × 10% ≈ 0.005%). With it, the native app's decision is the only one that matters for client-originated traffic.

Exception capture in App Insights

Even for the 95% of native-originated requests with sampled=00, exceptions still arrive in the exceptions table because recordException() always emits a log record alongside the span event, and log records are not sampled. See the exception pipeline for the code-level flow.

In practice:

  • cloud_RoleName filters work because the shared Resource ships service.name.
  • The exceptions blade shows every error, sampled or not.
  • The requests blade shows the sampled subset; linked exceptions are still discoverable via cloud_RoleName + outerMessage.
  • Pino logs land in the traces table with the same cloud_RoleName.

What the apps DON'T do

  • No @azure/monitor-opentelemetry. The platform agent translates OTel → App Insights. The Azure-specific package would double-instrument and overwrite the resource.
  • No App Insights connection string server-side. The web container app sets NEXT_PUBLIC_APPLICATIONINSIGHTS_CONNECTION_STRING for the browser bundle only.
  • No metrics export. The Container Apps agent doesn't accept OTel metrics today.

Where things live

ConcernLocation
Container App Environment + agentPlatform team — referenced as data.azurerm_container_app_environment.main
Application Insights resourceReferenced as data.azurerm_application_insights.main
Per-app OTel env varsazure/infra/apps/<app>/main.tf
Per-env sampler ratioazure/infra/apps/<app>/tfvars/{tst,acc,prd}.tfvars
Apollo Router OTel configapps/graphql-router/router.yaml
Traefik OTel configapps/api-gateway/traefik/entrypoint.sh
Node / Next.js OTel SDKpackages/infrastructure/observability