Introduction
As platforms evolve toward microservice‑based architectures, observability becomes more complex than ever. In Azure Kubernetes Service (AKS), teams often rely on Istio to manage service‑to‑service communication and Azure Application Insights for application‑level telemetry.
While both are powerful, they operate at different layers and without deliberate configuration, correlating a single request across the service mesh and the application layer is not straightforward.
This blog walks through a practical, production‑ready solution to enable Istio (Envoy) access logging in AKS and correlate those logs with Application Insights telemetry, allowing engineers to trace a request end‑to‑end for faster troubleshooting and deeper visibility.
Platform Observability Context
The environment consists of:
- AKS with managed Istio enabled
- Envoy sidecars injected into application pods
- Azure Application Insights SDK running inside workloads
- Log Analytics as the centralized log store
Istio is responsible for traffic management, while Application Insights captures application‑level telemetry. The goal was to align these layers using a common trace context, without introducing additional tracing systems or custom agents.
Enabling Istio Access Logging at the Mesh Level
The first step is to ensure that Envoy access logs are emitted consistently across the service mesh. Istio provides the Telemetry API, which allows access logging to be enabled centrally without modifying individual workloads.
Apply a Telemetry resource in the Istio system namespace to enable Envoy access logging:
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: mesh-access-logs
namespace: aks-istio-system
spec:
accessLogging:
- providers:
- name: envoy
This configuration ensures that:
- All Envoy sidecars emit access logs
- Logging behavior is uniform across the mesh
- The setup remains compatible with AKS managed Istio
Standardizing Envoy Logs Using EnvoyFilter
Access logs must be structured to be useful at scale. In AKS managed Istio, direct Envoy configuration is restricted, so EnvoyFilter is used to customize logging behavior.
EnvoyFilters are configured to:
- Emit logs in structured JSON format
- Write logs to /dev/stdout
- Include trace and request correlation headers
To achieve full visibility, separate EnvoyFilters are applied for inbound and outbound sidecar traffic.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: json-access-logs
namespace: aks-istio-system
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
patch:
operation: MERGE
value:
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
access_log:
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: /dev/stdout
log_format:
json_format:
timestamp: "%START_TIME%"
method: "%REQ(:METHOD)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
response_code: "%RESPONSE_CODE%"
response_flags: "%RESPONSE_FLAGS%"
duration_ms: "%DURATION%"
downstream_remote_address: "%DOWNSTREAM_REMOTE_ADDRESS%"
x_request_id: "%REQ(X-REQUEST-ID)%"
traceparent: "%REQ(TRACEPARENT)%"
tracestate: "%REQ(TRACESTATE)%"
x_b3_traceid: "%REQ(X-B3-TRACEID)%"
This configuration ensures inbound traffic logs contain both request metadata and correlation identifiers.
Configuring Outbound Envoy Access Logs
Outbound logging is required to observe downstream calls made by a service. Apply a second EnvoyFilter for outbound traffic:
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: json-access-logs-outbound
namespace: aks-istio-system
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_OUTBOUND
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
patch:
operation: MERGE
value:
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
access_log:
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: /dev/stdout
log_format:
json_format:
timestamp: "%START_TIME%"
method: "%REQ(:METHOD)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
response_code: "%RESPONSE_CODE%"
response_flags: "%RESPONSE_FLAGS%"
duration_ms: "%DURATION%"
downstream_remote_address: "%DOWNSTREAM_REMOTE_ADDRESS%"
x_request_id: "%REQ(X-REQUEST-ID)%"
traceparent: "%REQ(TRACEPARENT)%"
tracestate: "%REQ(TRACESTATE)%"
x_b3_traceid: "%REQ(X-B3-TRACEID)%"
Inbound and outbound logs now follow the same schema, enabling consistent querying and analysis.
Automating the Configuration with PowerShell
To standardize and repeat the setup across environments, wrap the configuration in a PowerShell script. The script should:
- Validate the Istio system namespace
- Apply the Telemetry resource
- Apply inbound and outbound EnvoyFilters
$MeshRootNamespace = "aks-istio-system"
$TelemetryName = "mesh-access-logs"
$EnvoyFilterName = "json-access-logs"
kubectl get ns $MeshRootNamespace --ignore-not-found
$telemetryYaml | kubectl apply -f -
$envoyFilterYaml | kubectl apply -f -
$envoyFilterOutboundYaml | kubectl apply -f -
Log Ingestion into Azure Monitor
Because Envoy access logs are written to standard output:
- AKS automatically collects them
- Logs are ingested into Log Analytics
- Data appears in the ContainerLogV2 table
No additional agents or custom log pipelines are required.
Aligning with Application Insights Telemetry
Application Insights uses W3C Trace Context, where the operation_Id represents the trace identifier. Since Envoy access logs capture the traceparent header, both systems expose the same trace ID.
This alignment allows service mesh logs and application telemetry to be correlated without changing application code.
Correlating Requests Using KQL
To analyze request flow:
- Parse JSON access logs from ContainerLogV2
- Extract the trace ID from traceparent
- Join with Application Insights request telemetry
To validate end‑to‑end tracing, use Log Analytics to query Istio access logs collected in the ContainerLogV2 table. Since Envoy access logs include the traceparent header, the trace‑id embedded in it directly maps to the Application Insights operation_Id. By filtering istio-proxy logs on this trace‑id, it becomes possible to view the full Envoy request record for a specific application request and trace it across the service mesh and application layers.
KQL (filter Istio access logs using an Application Insights operation_Id)
let operationId = "<OperationID>"; // Replace with your actual operation_Id
ContainerLogV2
| where TimeGenerated >= ago(24h)
| where ContainerName == "istio-proxy"
| where LogSource == "stdout"
| where LogMessage startswith "{"
| extend AccessLog = parse_json(LogMessage)
| extend ExtractedOperationId = extract(@"00-([a-f0-9]{32})-", 1, tostring(AccessLog.traceparent))
| where ExtractedOperationId == operationId
| project
TimeGenerated,
PodName,
Method = tostring(AccessLog.method),
Path = tostring(AccessLog.path),
ResponseCode = toint(AccessLog.response_code),
RequestId = tostring(AccessLog.x_request_id),
TraceParent = tostring(AccessLog.traceparent),
TraceState = tostring(AccessLog.tracestate),
Authority = tostring(AccessLog.authority),
RawLogMessage = LogMessage
| order by TimeGenerated asc
Closing Thoughts
End‑to‑end request tracing in AKS is achieved by aligning service mesh logging and application telemetry around shared standards. By enabling structured Istio access logs and correlating them with Application Insights, platforms gain clear visibility into request flow across networking and application layers using Azure‑native tools.
This process scales well in managed Istio environments and provides meaningful observability without adding platform complexity.