App Insights Instrumentation
Implement high-value telemetry with minimal noise and strong trace correlation for production troubleshooting and performance optimization.
Use This Skill When
- The user needs monitoring for apps running in Azure
- The user needs distributed tracing across microservices
- The user needs alerting, dashboards, or root cause analysis visibility
- The user wants to migrate from custom logging to structured telemetry
Context: Observability Maturity
Immature: No monitoring, errors discovered by users
Developing: Logs and metrics collected, no correlation or alerting
Managed: Traces linked across services, alerts firing, dashboards useful → Target
Optimized: Real-time anomaly detection, SLO tracking, automated runbooks
Required Inputs
- Application stack: Node.js, Python, .NET, Java, Go, etc.
- Deployment target: App Service, Container Apps, AKS, Function, VM
- Critical user journeys: Signup → Confirmation, Payment → Order, Search → Results
- SLO targets: Availability (%), latency (ms p99), error budget
- Compliance needs: PII filtering, data residency, retention policy
- Existing telemetry: Custom logging, APM, or greenfield?
Decision Tree
Is this a new application or existing?
├─ New → Start with OpenTelemetry SDK from day one
└─ Existing → Assess current logging, add instrumentation incrementally
Which language?
├─ .NET → Application Insights .NET SDK (auto-instrumentation or manual)
├─ Node.js → OpenTelemetry + @opentelemetry/sdk-node
├─ Python → OpenTelemetry + opentelemetry-sdk
├─ Java → OpenTelemetry agent (zero-code) or manual SDK
└─ Other → OpenTelemetry language-specific SDK
How many services (microservices)?
├─ Single → Simple Application Insights setup, no special tracing
├─ 2-5 services → OpenTelemetry with correlation IDs across calls
└─ 5+ services → Distributed trace propagation (W3C Trace Context)
What's the expected volume?
├─ < 1M events/day → 100% sampling acceptable
├─ 1-10M → 10-25% sampling with head-based decisions
└─ > 10M → 1-5% sampling with tail-based (post-request) sampling decisions
Workflow
Phase 1: Setup Application Insights Workspace
Create Application Insights resource:
az monitor app-insights component create \
--resource-group $RG \
--app-name "ai-${app}-${env}" \
--location eastus
# Get instrumentation key
IKEY=$(az monitor app-insights component show --resource-group $RG --app-name "ai-${app}-${env}" --query "instrumentationKey")
Create Log Analytics workspace (for KQL queries):
az monitor log-analytics workspace create \
--resource-group $RG \
--workspace-name "law-${app}-${env}"
# Link to Application Insights
az monitor app-insights component update --resource-group $RG --app-name "ai-${app}-${env}" \
--workspace "/subscriptions/$SUBID/resourceGroups/$RG/providers/Microsoft.OperationalInsights/workspaces/law-${app}-${env}"
Configure retention policy:
- Default: 30 days free
- Increase if needed (paid): 90 days, 1 year
- Archive to Storage: 7+ years for compliance
Phase 2: Add SDK to Application
Example 1: .NET
# Install NuGet packages
dotnet add package Microsoft.ApplicationInsights.AspNetCore
dotnet add package Microsoft.ApplicationInsights.DependencyCollector
// In Program.cs
builder.Services.AddApplicationInsightsTelemetry();
// Instrumentation key from Key Vault
var ikeySecret = new DefaultAzureCredential();
var kvUri = new Uri($"https://{kvName}.vault.azure.net");
var kvClient = new SecretClient(kvUri, ikeySecret);
var ikeySecret = kvClient.GetSecret("APPINSIGHTS_INSTRUMENTATION_KEY");
Example 2: Node.js with OpenTelemetry
npm install @opentelemetry/api @opentelemetry/sdk-node \
@opentelemetry/auto-instrumentations-node \
@opentelemetry/exporter-trace-otlp-http @opentelemetry/sdk-trace-node
// instrumentation.js (first require in entry point)
const { NodeTracerProvider } = require("@opentelemetry/sdk-node");
const { getNodeAutoInstrumentations } = require("@opentelemetry/auto-instrumentations-node");
const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-http");
const traceExporter = new OTLPTraceExporter({
url: `https://${process.env.APPLICATIONINSIGHTS_ENDPOINT_URL}/v2.1/track`
});
const sdk = new NodeSDK({
traceExporter,
instrumentations: [getNodeAutoInstrumentations()]
});
sdk.start();
Example 3: Python
pip install opentelemetry-api opentelemetry-sdk \
opentelemetry-exporter-azure-monitor \
opentelemetry-instrumentation-flask opentelemetry-instrumentation-requests
from azure.monitor.opentelemetry import configure_azure_monitor
configure_azure_monitor(
connection_string=os.environ.get("APPLICATIONINSIGHTS_CONNECTION_STRING")
)
Phase 3: Add Custom Telemetry
Track custom events (business logic):
// .NET
telemetryClient.TrackEvent("UserSignup", new Dictionary<string, string> {
{ "signup_source", "mobile_app" },
{ "user_tier", "premium" }
});
// Node.js
const tracer = trace.getTracer("app");
const span = tracer.startSpan("UserSignup", {
attributes: { "signup_source": "mobile_app", "user_tier": "premium" }
});
Track custom metrics:
// .NET: Track duration
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
ProcessOrder(order);
stopwatch.Stop();
telemetryClient.GetMetric("ProcessOrderDuration").TrackValue(stopwatch.ElapsedMilliseconds);
Add correlation context:
// Automatic: Activity.Current.Id correlates across services
// Manual: Add request ID to headers
using (var activity = new System.Diagnostics.Activity("ProcessPayment").Start()) {
activity.AddTag("order_id", orderId);
CallDownstreamAPI(); // Downstream receives trace context in headers
}
Phase 4: Configure Sampling
Adaptive sampling (default):
Automatically reduces sample rate when volume spikes
- Default: 25 events/sec threshold
- Above: Reduces to 5% sampling
- Below: Continues 100% sampling
services.Configure<ApplicationInsightsServiceOptions>(options => {
options.SamplingSettings = new SamplingSettings {
MaxTelemetryItemsPerSecond = 20,
EvaluationInterval = TimeSpan.FromMinutes(1),
SampledItemCount = 5
};
});
Fixed sampling (simpler, for testing):
Always sample 10% of requests
Useful for known volume or testing
Tail-based sampling (advanced):
- Sample entire traces based on errors, latency
- Only available in Open Telemetry Collector (not direct AppInsights)
Phase 5: Create Dashboards & Alerts
Business KPI dashboard:
// Failed signups in last hour
customEvents
| where name == "SignupFailed"
| where timestamp > ago(1h)
| summarize count() by tostring(customDimensions.failure_reason)
// Average order processing time
customMetrics
| where name == "ProcessOrderDuration"
| summarize avg(value) by bin(timestamp, 5m)
Performance dashboard:
// Request latency (p50, p95, p99)
requests
| summarize p50=percentile(duration,50), p95=percentile(duration,95), p99=percentile(duration,99) by bin(timestamp, 1m)
// Dependency failures
dependencies
| where success == false
| summarize count() by target, type, resultCode
Alert rules (trigger on SLA breach):
Condition: Error rate > 5% in 5 minutes
→ Severity 2 (warning)
→ Notify: on-call via email, PagerDuty
Condition: Response time p99 > 1000ms in 10 minutes
→ Severity 3 (info)
→ Notify: #alerts Slack channel
Condition: Any database connectivity failures
→ Severity 1 (critical)
→ Immediate escalation to DBA
Phase 6: Correlation & Troubleshooting
Follow request through services:
User → API Gateway (trace-id: abc123)
→ Auth Service (inherits trace-id: abc123)
→ Database (inherits trace-id: abc123)
All logs linked via same trace-id; one query finds entire flow
Root cause analysis query:
let trace_id = "abc123";
union
(requests | where operation_Id == trace_id),
(dependencies | where operation_Id == trace_id),
(exceptions | where operation_Id == trace_id),
(traces | where operation_Id == trace_id),
(customEvents | where tostring(customDimensions.trace_id) == trace_id)
| project timestamp, type, message, target, success
| order by timestamp asc
Output Contract
Instrumentation Plan
- SDK/agent selected and justification
- Sampling strategy (fixed %, adaptive, tail-based)
- Correlation approach (trace context headers)
Implementation Checklist
- Packages/SDKs to install
- Code changes (SDK initialization, custom events)
- Environment variables or Key Vault secrets
Telemetry Schema
- Custom events (name, dimensions, metrics)
- Business KPIs to track
- Naming conventions (snake_case, dimensions)
Dashboard & Alert Baseline
- Business KPI dashboard (queries provided)
- Performance dashboard (queries provided)
- Alert rules (thresholds, severity, channels)
Validation Steps
- Send test event, verify in portal
- Trace sample request end-to-end
- Verify alerts fire on synthetic failures
Guardrails
- Never log secrets, PII, or credentials: Filter sensitive data before sending.
- Use structured logging: JSON/structured dimensions, not free text.
- Avoid high-cardinality dimensions: Don't use user ID or request ID as dimension (too many unique values = high cost).
- Set retention policy: Default 30 days; archive old data to storage for compliance.
- Sample intelligently: 100% at <1M events/day; reduce sampling as volume grows.
- Correlate traces across services: Use W3C Trace Context headers to link requests.
- Monitor the monitor: Ensure Application Insights is receiving data; check quota.
- Use alerts for SLA breaches: Don't rely on dashboards; alerts notify on-call team.
1---2name: appinsights-instrumentation3description: Instrument applications with Azure Application Insights and OpenTelemetry for end-to-end observability. Use this skill when users ask about telemetry, tracing, metrics, logging, or monitoring setup. Covers SDK setup, correlation, sampling, dashboards, and alerts per OpenTelemetry standards.4---56# App Insights Instrumentation78Implement high-value telemetry with minimal noise and strong trace correlation for production troubleshooting and performance optimization.910## Use This Skill When1112- The user needs monitoring for apps running in Azure13- The user needs distributed tracing across microservices14- The user needs alerting, dashboards, or root cause analysis visibility15- The user wants to migrate from custom logging to structured telemetry1617## Context: Observability Maturity1819**Immature**: No monitoring, errors discovered by users 20**Developing**: Logs and metrics collected, no correlation or alerting 21**Managed**: Traces linked across services, alerts firing, dashboards useful → **Target** 22**Optimized**: Real-time anomaly detection, SLO tracking, automated runbooks2324## Required Inputs2526- **Application stack**: Node.js, Python, .NET, Java, Go, etc.27- **Deployment target**: App Service, Container Apps, AKS, Function, VM28- **Critical user journeys**: Signup → Confirmation, Payment → Order, Search → Results29- **SLO targets**: Availability (%), latency (ms p99), error budget30- **Compliance needs**: PII filtering, data residency, retention policy31- **Existing telemetry**: Custom logging, APM, or greenfield?3233## Decision Tree3435```36Is this a new application or existing?37├─ New → Start with OpenTelemetry SDK from day one38└─ Existing → Assess current logging, add instrumentation incrementally3940Which language?41├─ .NET → Application Insights .NET SDK (auto-instrumentation or manual)42├─ Node.js → OpenTelemetry + @opentelemetry/sdk-node43├─ Python → OpenTelemetry + opentelemetry-sdk44├─ Java → OpenTelemetry agent (zero-code) or manual SDK45└─ Other → OpenTelemetry language-specific SDK4647How many services (microservices)?48├─ Single → Simple Application Insights setup, no special tracing49├─ 2-5 services → OpenTelemetry with correlation IDs across calls50└─ 5+ services → Distributed trace propagation (W3C Trace Context)5152What's the expected volume?53├─ < 1M events/day → 100% sampling acceptable54├─ 1-10M → 10-25% sampling with head-based decisions55└─ > 10M → 1-5% sampling with tail-based (post-request) sampling decisions56```5758## Workflow5960### Phase 1: Setup Application Insights Workspace61621. **Create Application Insights resource**:63 ```bash64 az monitor app-insights component create \65 --resource-group $RG \66 --app-name "ai-${app}-${env}" \67 --location eastus68 69 # Get instrumentation key70 IKEY=$(az monitor app-insights component show --resource-group $RG --app-name "ai-${app}-${env}" --query "instrumentationKey")71 ```72732. **Create Log Analytics workspace** (for KQL queries):74 ```bash75 az monitor log-analytics workspace create \76 --resource-group $RG \77 --workspace-name "law-${app}-${env}"78 79 # Link to Application Insights80 az monitor app-insights component update --resource-group $RG --app-name "ai-${app}-${env}" \81 --workspace "/subscriptions/$SUBID/resourceGroups/$RG/providers/Microsoft.OperationalInsights/workspaces/law-${app}-${env}"82 ```83843. **Configure retention policy**:85 - Default: 30 days free86 - Increase if needed (paid): 90 days, 1 year87 - Archive to Storage: 7+ years for compliance8889### Phase 2: Add SDK to Application9091**Example 1: .NET**92```bash93# Install NuGet packages94dotnet add package Microsoft.ApplicationInsights.AspNetCore95dotnet add package Microsoft.ApplicationInsights.DependencyCollector96```9798```csharp99// In Program.cs100builder.Services.AddApplicationInsightsTelemetry();101102// Instrumentation key from Key Vault103var ikeySecret = new DefaultAzureCredential();104var kvUri = new Uri($"https://{kvName}.vault.azure.net");105var kvClient = new SecretClient(kvUri, ikeySecret);106var ikeySecret = kvClient.GetSecret("APPINSIGHTS_INSTRUMENTATION_KEY");107```108109**Example 2: Node.js with OpenTelemetry**110```bash111npm install @opentelemetry/api @opentelemetry/sdk-node \112 @opentelemetry/auto-instrumentations-node \113 @opentelemetry/exporter-trace-otlp-http @opentelemetry/sdk-trace-node114```115116```javascript117// instrumentation.js (first require in entry point)118const { NodeTracerProvider } = require("@opentelemetry/sdk-node");119const { getNodeAutoInstrumentations } = require("@opentelemetry/auto-instrumentations-node");120const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-http");121122const traceExporter = new OTLPTraceExporter({123 url: `https://${process.env.APPLICATIONINSIGHTS_ENDPOINT_URL}/v2.1/track`124});125126const sdk = new NodeSDK({127 traceExporter,128 instrumentations: [getNodeAutoInstrumentations()]129});130sdk.start();131```132133**Example 3: Python**134```bash135pip install opentelemetry-api opentelemetry-sdk \136 opentelemetry-exporter-azure-monitor \137 opentelemetry-instrumentation-flask opentelemetry-instrumentation-requests138```139140```python141from azure.monitor.opentelemetry import configure_azure_monitor142143configure_azure_monitor(144 connection_string=os.environ.get("APPLICATIONINSIGHTS_CONNECTION_STRING")145)146```147148### Phase 3: Add Custom Telemetry1491501. **Track custom events** (business logic):151 ```csharp152 // .NET153 telemetryClient.TrackEvent("UserSignup", new Dictionary<string, string> {154 { "signup_source", "mobile_app" },155 { "user_tier", "premium" }156 });157 ```158159 ```javascript160 // Node.js161 const tracer = trace.getTracer("app");162 const span = tracer.startSpan("UserSignup", {163 attributes: { "signup_source": "mobile_app", "user_tier": "premium" }164 });165 ```1661672. **Track custom metrics**:168 ```csharp169 // .NET: Track duration170 var stopwatch = System.Diagnostics.Stopwatch.StartNew();171 ProcessOrder(order);172 stopwatch.Stop();173 telemetryClient.GetMetric("ProcessOrderDuration").TrackValue(stopwatch.ElapsedMilliseconds);174 ```1751763. **Add correlation context**:177 ```csharp178 // Automatic: Activity.Current.Id correlates across services179 // Manual: Add request ID to headers180 using (var activity = new System.Diagnostics.Activity("ProcessPayment").Start()) {181 activity.AddTag("order_id", orderId);182 CallDownstreamAPI(); // Downstream receives trace context in headers183 }184 ```185186### Phase 4: Configure Sampling1871881. **Adaptive sampling** (default):189 ```190 Automatically reduces sample rate when volume spikes191 - Default: 25 events/sec threshold192 - Above: Reduces to 5% sampling193 - Below: Continues 100% sampling194 ```195196 ```csharp197 services.Configure<ApplicationInsightsServiceOptions>(options => {198 options.SamplingSettings = new SamplingSettings {199 MaxTelemetryItemsPerSecond = 20,200 EvaluationInterval = TimeSpan.FromMinutes(1),201 SampledItemCount = 5202 };203 });204 ```2052062. **Fixed sampling** (simpler, for testing):207 ```208 Always sample 10% of requests209 Useful for known volume or testing210 ```2112123. **Tail-based sampling** (advanced):213 - Sample entire traces based on errors, latency214 - Only available in Open Telemetry Collector (not direct AppInsights)215216### Phase 5: Create Dashboards & Alerts2172181. **Business KPI dashboard**:219 ```kql220 // Failed signups in last hour221 customEvents 222 | where name == "SignupFailed" 223 | where timestamp > ago(1h)224 | summarize count() by tostring(customDimensions.failure_reason)225 226 // Average order processing time227 customMetrics228 | where name == "ProcessOrderDuration"229 | summarize avg(value) by bin(timestamp, 5m)230 ```2312322. **Performance dashboard**:233 ```kql234 // Request latency (p50, p95, p99)235 requests236 | summarize p50=percentile(duration,50), p95=percentile(duration,95), p99=percentile(duration,99) by bin(timestamp, 1m)237 238 // Dependency failures239 dependencies240 | where success == false241 | summarize count() by target, type, resultCode242 ```2432443. **Alert rules** (trigger on SLA breach):245 ```246 Condition: Error rate > 5% in 5 minutes247 → Severity 2 (warning)248 → Notify: on-call via email, PagerDuty249 250 Condition: Response time p99 > 1000ms in 10 minutes251 → Severity 3 (info)252 → Notify: #alerts Slack channel253 254 Condition: Any database connectivity failures255 → Severity 1 (critical)256 → Immediate escalation to DBA257 ```258259### Phase 6: Correlation & Troubleshooting2602611. **Follow request through services**:262 ```263 User → API Gateway (trace-id: abc123)264 → Auth Service (inherits trace-id: abc123)265 → Database (inherits trace-id: abc123)266 267 All logs linked via same trace-id; one query finds entire flow268 ```2692702. **Root cause analysis query**:271 ```kql272 let trace_id = "abc123";273 union274 (requests | where operation_Id == trace_id),275 (dependencies | where operation_Id == trace_id),276 (exceptions | where operation_Id == trace_id),277 (traces | where operation_Id == trace_id),278 (customEvents | where tostring(customDimensions.trace_id) == trace_id)279 | project timestamp, type, message, target, success280 | order by timestamp asc281 ```282283## Output Contract2842851. **Instrumentation Plan**286 - SDK/agent selected and justification287 - Sampling strategy (fixed %, adaptive, tail-based)288 - Correlation approach (trace context headers)2892902. **Implementation Checklist**291 - Packages/SDKs to install292 - Code changes (SDK initialization, custom events)293 - Environment variables or Key Vault secrets2942953. **Telemetry Schema**296 - Custom events (name, dimensions, metrics)297 - Business KPIs to track298 - Naming conventions (snake_case, dimensions)2993004. **Dashboard & Alert Baseline**301 - Business KPI dashboard (queries provided)302 - Performance dashboard (queries provided)303 - Alert rules (thresholds, severity, channels)3043055. **Validation Steps**306 - Send test event, verify in portal307 - Trace sample request end-to-end308 - Verify alerts fire on synthetic failures309310## Guardrails311312- **Never log secrets, PII, or credentials**: Filter sensitive data before sending.313- **Use structured logging**: JSON/structured dimensions, not free text.314- **Avoid high-cardinality dimensions**: Don't use user ID or request ID as dimension (too many unique values = high cost).315- **Set retention policy**: Default 30 days; archive old data to storage for compliance.316- **Sample intelligently**: 100% at <1M events/day; reduce sampling as volume grows.317- **Correlate traces across services**: Use W3C Trace Context headers to link requests.318- **Monitor the monitor**: Ensure Application Insights is receiving data; check quota.319- **Use alerts for SLA breaches**: Don't rely on dashboards; alerts notify on-call team.