Azure Container Apps

ACA Discovery & Log Streaming

Auto-discover your Container Apps and stream logs in real time. No code changes, no agents to install. Deploy ZenoLog as a Container App and get instant visibility into your entire environment.

How It Works

Three steps to visibility across your ACA environment.

1

Discover

ZenoLog polls the ARM API to find all Container Apps in your environment, their active revisions, and running replicas.

2

Activate

Select which apps to stream from the Web UI, TUI, or API. Choose specific containers or stream all of them.

3

Stream

Container stdout/stderr flows into ZenoLog's ring buffers with Azure resource attributes, searchable alongside your OTLP logs.

Managed Identity Auth

Authenticate with system or user-assigned Managed Identity. No secrets to rotate. Falls back to DefaultAzureCredential for local dev with az login.

Poll-Based Discovery

Polls the ARM API every 30 seconds (configurable). Detects new apps, removed apps, and replica changes automatically.

Side by Side with K8s

Run ACA and K8s discovery simultaneously. Multi-provider architecture with unified search, tail, and source management.

Self-Exclusion

ZenoLog automatically excludes itself from discovery when running as a Container App. No log feedback loops.

Configuration

All settings via environment variables with the ZENOLOG_ACA_ prefix.

Variable Default Description
ZENOLOG_ACA_ENABLEDfalseEnable ACA discovery (true, auto, or false)
ZENOLOG_ACA_SUBSCRIPTION_IDrequiredAzure subscription ID containing the ACA environment
ZENOLOG_ACA_RESOURCE_GROUPrequiredResource group containing the ACA environment
ZENOLOG_ACA_ENVIRONMENTrequiredName of the ACA Managed Environment
ZENOLOG_ACA_CLIENT_IDoptionalUser-assigned Managed Identity client ID (if omitted, uses system MI or DefaultAzureCredential)
ZENOLOG_ACA_POLL_INTERVAL30sHow often to poll ARM API for app changes
ZENOLOG_ACA_MAX_STREAMS100Maximum concurrent log stream goroutines
ZENOLOG_ACA_EXCLUDE_APPSnoneComma-separated app names to exclude from discovery

Azure Permissions

ZenoLog needs access to discover and stream logs from your Container Apps. Assign the built-in ContainerApp Contributor role, or create a custom role for least-privilege.

Required Permissions

Microsoft.App/containerApps/read
Microsoft.App/containerApps/revisions/read
Microsoft.App/containerApps/revisions/replicas/list/action
Microsoft.App/containerApps/getAuthtoken/action
Microsoft.App/managedEnvironments/read

The getAuthtoken action is required for real-time log streaming. ZenoLog never modifies your Container Apps.

Custom Role Definition

{
  "Name": "ZenoLog ACA Discovery",
  "Description": "Discovery and log streaming for ZenoLog",
  "Actions": [
    "Microsoft.App/containerApps/read",
    "Microsoft.App/containerApps/revisions/read",
    "Microsoft.App/containerApps/revisions/replicas/list/action",
    "Microsoft.App/containerApps/getAuthtoken/action",
    "Microsoft.App/managedEnvironments/read"
  ],
  "AssignableScopes": [
    "/subscriptions/{subscription-id}/resourceGroups/{rg-name}"
  ]
}

Authentication Methods

System-Assigned Managed Identity

Enable system MI on the ZenoLog Container App and assign the ContainerApp Contributor role. No configuration needed beyond the three required env vars.

Alternative
User-Assigned Managed Identity

Create a user-assigned MI, assign it to the ZenoLog app, and set ZENOLOG_ACA_CLIENT_ID to its client ID. Useful when sharing identities across apps.

Local Dev
Azure CLI / Service Principal

For local development, run az login or set AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, and AZURE_TENANT_ID. Handled automatically by DefaultAzureCredential.

Deploy to Azure Container Apps

Two commands to get ZenoLog running in your ACA environment.

az containerapp create \
  --name zenolog \
  --resource-group my-rg \
  --environment my-env \
  --image jimmytoenners/zenolog:0.3.4 \
  --min-replicas 1 --max-replicas 1 \
  --ingress external --target-port 8081 \
  --system-assigned \
  --env-vars \
    ZENOLOG_ACA_ENABLED=true \
    ZENOLOG_ACA_SUBSCRIPTION_ID=<subscription-id> \
    ZENOLOG_ACA_RESOURCE_GROUP=my-rg \
    ZENOLOG_ACA_ENVIRONMENT=my-env

# Assign ContainerApp Contributor role to the system MI
az role assignment create \
  --assignee $(az containerapp show -n zenolog -g my-rg \
    --query identity.principalId -o tsv) \
  --role "ContainerApp Contributor" \
  --scope /subscriptions/<subscription-id>/resourceGroups/my-rg