Skip to content

04 - Logging and Monitoring (Premium)

Enable observability for a Premium Function App using Application Insights, Log Analytics queries, and Kudu/SCM diagnostics.

Prerequisites

  • You completed 03 - Configuration.
  • You exported $RG, $APP_NAME, $PLAN_NAME, $STORAGE_NAME, $LOCATION.
  • Your Function App is deployed and returning 200 from /api/health.

What You'll Build

  • Application Insights and Log Analytics integration for a Premium Function App.
  • Live log streaming and KQL query checks for requests, traces, and exceptions.
  • A repeatable diagnostics workflow using SCM/Kudu endpoints.

Infrastructure Context

Plan: Premium (EP1) | Network: VNet + Private Endpoints | Always warm: ✅

Premium deploys with VNet integration (delegated subnet), a private endpoint for inbound access, private DNS zone, and pre-warmed instances. Storage uses connection string or identity-based authentication.

flowchart TD
    INET[Internet] -->|HTTPS| FA[Function App\nPremium EP1\nLinux Python 3.11]

    subgraph VNET["VNet 10.0.0.0/16"]
        subgraph INT_SUB["Integration Subnet 10.0.1.0/24\nDelegation: Microsoft.Web/serverFarms"]
            FA
        end
        subgraph PE_SUB["Private Endpoint Subnet 10.0.2.0/24"]
            PE_BLOB[PE: blob]
            PE_QUEUE[PE: queue]
            PE_TABLE[PE: table]
            PE_FILE[PE: file]
        end
    end

    PE_BLOB --> ST["Storage Account\nallowPublicAccess: false\nallowSharedKeyAccess: true"]
    PE_QUEUE --> ST
    PE_TABLE --> ST
    PE_FILE --> ST

    subgraph DNS[Private DNS Zones]
        DNS_BLOB[privatelink.blob.core.windows.net]
        DNS_QUEUE[privatelink.queue.core.windows.net]
        DNS_TABLE[privatelink.table.core.windows.net]
        DNS_FILE[privatelink.file.core.windows.net]
    end

    PE_BLOB -.-> DNS_BLOB
    PE_QUEUE -.-> DNS_QUEUE
    PE_TABLE -.-> DNS_TABLE
    PE_FILE -.-> DNS_FILE

    FA -.->|System-Assigned MI| ENTRA[Microsoft Entra ID]
    FA --> AI[Application Insights]

    subgraph STORAGE[Content Backend]
        SHARE[Azure Files\ncontent share]
    end
    ST --- SHARE

    WARM["🔥 Pre-warmed instances\nMin: 1, Max: 20-100"] -.- FA

    style FA fill:#ff8c00,color:#fff
    style VNET fill:#E8F5E9,stroke:#4CAF50
    style ST fill:#FFF3E0
    style DNS fill:#E3F2FD
    style WARM fill:#FFF3E0,stroke:#FF9800
flowchart TD
    A[Function App Premium] --> B[Application Insights]
    B --> C[Request and trace telemetry]
    C --> D[KQL verification queries]
    A --> E[SCM or Kudu diagnostics]

Steps

  1. Create a Log Analytics workspace and Application Insights component.

    az monitor log-analytics workspace create \
      --workspace-name "log-$APP_NAME" \
      --resource-group "$RG" \
      --location "$LOCATION"
    
    az monitor app-insights component create \
      --app "appi-$APP_NAME" \
      --resource-group "$RG" \
      --location "$LOCATION" \
      --workspace "/subscriptions/<subscription-id>/resourceGroups/$RG/providers/Microsoft.OperationalInsights/workspaces/log-$APP_NAME" \
      --application-type "web"
    
    CLI element Explanation
    Command(s) az monitor log-analytics workspace create, az monitor app-insights component create
    Key flags --workspace-name, --resource-group, --location, --app, --workspace, --application-type
    Variables $APP_NAME, $RG, $LOCATION
    Expected result Azure CLI returns provisioning details; confirm the resource name and successful provisioning state before continuing.
  2. Attach Application Insights connection string to the Function App.

    APPINSIGHTS_CONNECTION_STRING=$(az monitor app-insights component show \
      --app "appi-$APP_NAME" \
      --resource-group "$RG" \
      --query "connectionString" \
      --output tsv)
    
    az functionapp config appsettings set \
      --name "$APP_NAME" \
      --resource-group "$RG" \
      --settings "APPLICATIONINSIGHTS_CONNECTION_STRING=$APPINSIGHTS_CONNECTION_STRING"
    
    CLI element Explanation
    Command(s) az monitor app-insights component show, az functionapp config appsettings set
    Key flags --app, --resource-group, --query, --output, --name, --settings
    Variables $APP_NAME, $RG, $APPINSIGHTS_CONNECTION_STRING
    Expected result Azure CLI applies the configuration change; confirm the returned JSON or follow-up query shows the expected value.

    Restart after attaching Application Insights

    After setting APPLICATIONINSIGHTS_CONNECTION_STRING, restart the Function App to pick up the new telemetry configuration:

    az functionapp restart --name "$APP_NAME" --resource-group "$RG"
    
    CLI element Explanation
    Command(s) az functionapp restart
    Key flags --name, --resource-group
    Variables $APP_NAME, $RG
    Expected result Azure CLI completes successfully and returns JSON, table, or no output depending on the command; verify the next documented check before continuing.

    Telemetry may take 2–5 minutes to appear in Application Insights after the restart.

  3. Stream live logs from the app.

    az webapp log tail \
      --name "$APP_NAME" \
      --resource-group "$RG"
    
    CLI element Explanation
    Command(s) az webapp log tail
    Key flags --name, --resource-group
    Variables $APP_NAME, $RG
    Expected result Azure CLI completes successfully and returns JSON, table, or no output depending on the command; verify the next documented check before continuing.
  4. Query recent request telemetry.

    az monitor app-insights query \
      --app "appi-$APP_NAME" \
      --resource-group "$RG" \
      --analytics-query "requests | where timestamp > ago(15m) | project timestamp, name, resultCode, duration | order by timestamp desc | take 20" \
      --output table
    
    CLI element Explanation
    Command(s) az monitor app-insights query
    Key flags --app, --resource-group, --analytics-query, --output
    Variables $APP_NAME, $RG
    Expected result Azure CLI returns the requested resource data; verify names, IDs, status fields, or metric values match the scenario.

    Empty query results

    If --output table returns no rows, the data may not have been ingested yet. Wait 2–5 minutes after the restart and retry. Use --output json instead of --output table to see raw results including empty arrays.

  5. Query exceptions and traces.

    az monitor app-insights query \
      --app "appi-$APP_NAME" \
      --resource-group "$RG" \
      --analytics-query "exceptions | where timestamp > ago(24h) | project timestamp, type, outerMessage | order by timestamp desc | take 20" \
      --output table
    
    az monitor app-insights query \
      --app "appi-$APP_NAME" \
      --resource-group "$RG" \
      --analytics-query "traces | where timestamp > ago(15m) | project timestamp, severityLevel, message | order by timestamp desc | take 20" \
      --output table
    
    CLI element Explanation
    Command(s) az monitor app-insights query
    Key flags --app, --resource-group, --analytics-query, --output
    Variables $APP_NAME, $RG
    Expected result Azure CLI returns the requested resource data; verify names, IDs, status fields, or metric values match the scenario.
  6. Use Kudu/SCM for runtime diagnostics (Premium supports SCM).

    az functionapp deployment list-publishing-profiles \
      --name "$APP_NAME" \
      --resource-group "$RG" \
      --output table
    
    CLI element Explanation
    Command(s) az functionapp deployment list-publishing-profiles
    Key flags --name, --resource-group, --output
    Variables $APP_NAME, $RG
    Expected result Azure CLI returns provisioning details; confirm the resource name and successful provisioning state before continuing.

    Then open https://$APP_NAME.scm.azurewebsites.net and inspect: - LogFiles/Application/Functions/Function/* - Debug console for filesystem checks - deployed artifacts (file share-based content)

  7. Confirm Premium monitoring expectations.

    • Pre-warmed instances reduce trigger and HTTP cold-start latency.
    • Because at least one instance always runs, baseline telemetry remains active.
    • Scaling events occur at plan level across functions in the same app plan.

Verification

Live Log Stream --- Connected
2026-01-01T00:01:02.345 [Information] Executing 'Functions.health' (Reason='This function was programmatically called via the host APIs.', Id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
2026-01-01T00:01:02.512 [Information] Executed 'Functions.health' (Succeeded, Id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, Duration=167ms)
Timestamp                  Name    ResultCode    Duration
-------------------------  ------  ----------    --------
2026-01-01T00:01:02.512Z   health  200           00:00:00.167

Next Steps

Next: 05 - Infrastructure as Code

See Also

Sources