Skip to content

Error Logging

Daniel Truong edited this page Sep 8, 2026 · 3 revisions

Error Logging

How-to guide. Read errors from an EPIC product, or connect a new one to Application Insights.

Where errors go

Every product reports to one Application Insights component per environment:

  • eagle-insights-test — resource group c4b0a8-test-rg, subscription c4b0a8-test
  • eagle-insights-prod — resource group rg-eagle-public-prod, subscription c4b0a8-prod

Both are backed by a Log Analytics workspace, region canadacentral, 30-day retention, daily ingestion cap 0.15 GB (test) / 0.25 GB (prod). The workspace is eagle-logs-test in test and eagle-logs-prod in prod, both defined in the eagle-edge repo, azure/modules/observability.bicep.

eagle-public, eagle-admin, eagle-demi-frontend and eagle-demi-admin all report here, on both environments. eagle-api reports here too, on test and prod, via OpenTelemetry (secret eagle-api-appinsights); it is not connected on dev. Products are told apart by the AppRoleName column.

eagle-demi (the API) and eagle-notify report to their own components, demi-insights-<env> and notify-insights-<env>, not this one.

Read errors for a product

  1. Open the environment's Log Analytics workspace (eagle-logs-test or eagle-logs-prod, see above) in the Azure portal, or run queries with:
    az monitor log-analytics query -w <workspace customer id> --analytics-query "<kql>"
  2. Filter every query by AppRoleName to isolate one product (eagle-public, eagle-admin, eagle-demi-frontend, eagle-demi-admin).

Errors in the last 24 hours, by product

AppExceptions
| where TimeGenerated > ago(24h)
| summarize count() by AppRoleName, ProblemId
| order by count_ desc

One operation end to end

union AppRequests, AppDependencies, AppExceptions, AppTraces
| where OperationId == "<id>"
| order by TimeGenerated asc

Failed browser calls, by URL

AppDependencies
| where Success == false
| summarize count() by AppRoleName, Target, ResultCode
| order by count_ desc

Ingestion by table, for cost

Usage
| where TimeGenerated > ago(7d) and IsBillable
| summarize GB=sum(Quantity)/1024 by DataType
| order by GB desc

Exceptions by type

AppExceptions
| where TimeGenerated > ago(7d)
| summarize count() by AppRoleName, ExceptionType
| order by count_ desc

What the browser sends

eagle-public, eagle-admin, eagle-demi-frontend and eagle-demi-admin send: uncaught exceptions, unhandled promise rejections, failed fetch/XHR requests (URL and status code), and render crashes. Query strings are stripped before send. Successful requests and route page views are not sent.

Connect a Node service or Azure Function

  1. Read the connection string (it is not a secret):
    az monitor app-insights component show -g <rg> -a eagle-insights-<env> --query connectionString -o tsv
  2. Set two app settings on the service: APPLICATIONINSIGHTS_CONNECTION_STRING and OTEL_SERVICE_NAME=<product>.
  3. In the Node code, call @azure/monitor-opentelemetry's useAzureMonitor before any other require. See eagle-demi's api/index.js for the pattern.

Connect eagle-public or eagle-admin

The connection string lives in eagle-api's Config document, not in an app setting, and eagle-api reads it at startup.

  1. Read the connection string as above.
  2. Shell into the environment's MongoDB pod:
    oc -n 6cdc9e-<env> rsh deploy/eagle-api-mongodb
  3. Connect with mongosh, using the MONGODB_USER / MONGODB_PASSWORD values from secret eagle-api-mongodb:
    mongosh -u <MONGODB_USER> -p <MONGODB_PASSWORD> --authenticationDatabase admin epic
  4. Set the value on the Config document:
    db.epic.updateOne(
      { _schemaName: 'Config' },
      { $set: { APPINSIGHTS_CONNECTION_STRING: '<value>' } }
    )
  5. Restart eagle-api to pick up the change:
    oc -n 6cdc9e-<env> rollout restart deploy/eagle-api
  6. Verify the frontends can read it:
    curl -s https://<env host>/api/config | jq .APPINSIGHTS_CONNECTION_STRING

An empty string turns browser telemetry off. See Configuration Management for how /api/config serves this key.

Connect the DEMI frontend or DEMI admin

Set APPINSIGHTS_CONNECTION_STRING in the app's env.js.

Cost

Ingestion costs 3.83 CAD/GB in canadacentral (measured 2026-09-02). The workspace daily cap stops ingestion for the rest of the UTC day once reached.

Clone this wiki locally