与 AZD 集成 Application Insights ⏱️ 预计时间:40-50 分钟 | 成本影响:约 $5-15/月 | ⭐ 复杂度:中级 学习路径: ← 上一节:预检检查 - 部署前验证 当前位置:Application Insights 集成(监控、遥测、调试) → 下一节:部署指南 - 部署到 Azure 课程主页 你将学到什么 完成本课程后,你将能够: 自动将 Application Insights 集成到 AZD 项目中 配置微服务的 分布式追踪 实现 自定义遥测(指标、事件、依赖项) 设置 实时指标 进行实时监控 从 AZD 部署中创建 警报和仪表盘 使用 遥测查询 调试生产问题 优化 成本和采样 策略 监控 AI/LLM 应用(令牌、延迟、成本) 为什么 AZD
⏱️ 预计时间:40-50 分钟 | 成本影响:约 $5-15/月 | ⭐ 复杂度:中级
** 学习路径:**
完成本课程后,你将能够:
没有 Application Insights:
❌ No visibility into production behavior ❌ Manual log aggregation across services ❌ Reactive debugging (wait for customer complaints) ❌ No performance metrics ❌ Cannot trace requests across services ❌ Unknown failure rates and bottlenecks
有 Application Insights + AZD:
✅ Automatic telemetry collection ✅ Centralized logs from all services ✅ Proactive issue detection ✅ End-to-end request tracing ✅ Performance metrics and insights ✅ Real-time dashboards ✅ AZD provisions everything automatically
类比:Application Insights 就像应用的“黑匣子”飞行记录器 + 驾驶舱仪表盘。你可以实时看到一切发生的情况,并重现任何事件。
| 遥测类型 | 捕获内容 | 用例 |
|---|---|---|
| 请求 | HTTP 请求、状态码、持续时间 | API 性能监控 |
| 依赖项 | 外部调用(数据库、API、存储) | 识别瓶颈 |
| 异常 | 未处理的错误及堆栈跟踪 | 调试故障 |
| 自定义事件 | 业务事件(注册、购买) | 分析和漏斗 |
| 指标 | 性能计数器、自定义指标 | 容量规划 |
| 跟踪 | 带有严重级别的日志消息 | 调试和审计 |
| 可用性 | 正常运行时间和响应时间测试 | SLA 监控 |
# 验证 Azure Developer CLI azd version # ✅ 预期:azd 版本 1.0.0 或更高 # 验证 Azure CLI az --version # ✅ 预期:azure-cli 2.50.0 或更高
你应该已经完成:
AZD 在你部署时会自动创建并配置 Application Insights。让我们看看它是如何工作的。
monitored-app/ ├── azure.yaml # AZD configuration ├── infra/ │ ├── main.bicep # Main infrastructure │ ├── core/ │ │ └── monitoring.bicep # Application Insights + Log Analytics │ └── app/ │ └── api.bicep # Container App with monitoring └── src/ ├── app.py # Application with telemetry ├── requirements.txt └── Dockerfile
文件:azure.yaml
name: monitored-app metadata: template: monitored-app@1.0.0 services: api: project: ./src language: python host: containerapp # AZD automatically provisions monitoring!
就是这样! AZD 默认会创建 Application Insights。无需额外配置即可实现基本监控。
文件:infra/core/monitoring.bicep
param logAnalyticsName string param applicationInsightsName string param location string = resourceGroup().location param tags object = {} // Log Analytics Workspace (required for Application Insights) resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: logAnalyticsName location: location tags: tags properties: { sku: { name: 'PerGB2018' // Pay-as-you-go pricing } retentionInDays: 30 // Keep logs for 30 days features: { enableLogAccessUsingOnlyResourcePermissions: true } } } // Application Insights resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { name: applicationInsightsName location: location tags: tags kind: 'web' properties: { Application_Type: 'web' WorkspaceResourceId: logAnalytics.id IngestionMode: 'LogAnalytics' publicNetworkAccessForIngestion: 'Enabled' publicNetworkAccessForQuery: 'Enabled' } } // Outputs for Container Apps output logAnalyticsWorkspaceId string = logAnalytics.id output logAnalyticsWorkspaceName string = logAnalytics.name output applicationInsightsConnectionString string = applicationInsights.properties.ConnectionString output applicationInsightsInstrumentationKey string = applicationInsights.properties.InstrumentationKey output applicationInsightsName string = applicationInsights.name
文件:infra/app/api.bicep
param name string param location string param tags object = {} param containerAppsEnvironmentName string param applicationInsightsConnectionString string resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { name: name location: location tags: tags properties: { configuration: { ingress: { external: true targetPort: 8000 } secrets: [ { name: 'appinsights-connection-string' value: applicationInsightsConnectionString } ] } template: { containers: [ { name: 'api' image: 'myregistry.azurecr.io/api:latest' resources: { cpu: json('0.5') memory: '1Gi' } env: [ { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' secretRef: 'appinsights-connection-string' } { name: 'APPLICATIONINSIGHTS_ENABLED' value: 'true' } ] } ] } } } output uri string = 'https://${containerApp.properties.configuration.ingress.fqdn}'
文件:src/app.py
from flask import Flask, request, jsonify from opencensus.ext.azure.log_exporter import AzureLogHandler from opencensus.ext.azure.trace_exporter import AzureExporter from opencensus.ext.flask.flask_middleware import FlaskMiddleware from opencensus.trace.samplers import ProbabilitySampler import logging import os app = Flask(__name__) # 获取应用程序洞察连接字符串 connection_string = os.environ.get('APPLICATIONINSIGHTS_CONNECTION_STRING') if connection_string: # 配置分布式追踪 middleware = FlaskMiddleware( app, exporter=AzureExporter(connection_string=connection_string), sampler=ProbabilitySampler(rate=1.0) # 开发环境100%采样 ) # 配置日志记录 logger = logging.getLogger(__name__) logger.addHandler(AzureLogHandler(connection_string=connection_string)) logger.setLevel(logging.INFO) print("✅ Application Insights enabled") else: logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) print("⚠️ Application Insights not configured") @app.route('/health') def health(): logger.info('Health check endpoint called') return jsonify({'status': 'healthy', 'monitoring': 'enabled'}) @app.route('/api/products') def get_products(): logger.info('Fetching products') # 模拟数据库调用(自动跟踪为依赖项) products = [ {'id': 1, 'name': 'Laptop', 'price': 999.99}, {'id': 2, 'name': 'Mouse', 'price': 29.99}, {'id': 3, 'name': 'Keyboard', 'price': 79.99} ] logger.info(f'Returned {len(products)} products') return jsonify(products) @app.route('/api/error-test') def error_test(): """Test error tracking""" logger.error('Testing error tracking') try: raise ValueError('This is a test exception') except Exception as e: logger.exception('Exception occurred in error-test endpoint') return jsonify({'error': str(e)}), 500 @app.route('/api/slow') def slow_endpoint(): """Test performance tracking""" import time logger.info('Slow endpoint called') time.sleep(3) # 模拟慢操作 logger.warning('Endpoint took 3 seconds to respond') return jsonify({'message': 'Slow operation completed'}) if __name__ == '__main__': app.run(host='0.0.0.0', port=8000)
文件:src/requirements.txt
Flask==3.0.0 opencensus-ext-azure==1.1.13 opencensus-ext-flask==0.8.1 gunicorn==21.2.0
# 初始化 AZD azd init # 部署(自动配置 Application Insights) azd up # 获取应用程序 URL APP_URL=$(azd env get-values | grep API_URL | cut -d '=' -f2 | tr -d '"') # 生成遥测数据 curl $APP_URL/health curl $APP_URL/api/products curl $APP_URL/api/error-test curl $APP_URL/api/slow
✅ 预期输出:
{ "status": "healthy", "monitoring": "enabled" }
# 获取应用程序洞察详细信息 azd env get-values | grep APPLICATIONINSIGHTS # 在 Azure 门户中打开 az monitor app-insights component show \ --app $(azd env get-values | grep APPLICATIONINSIGHTS_NAME | cut -d '=' -f2 | tr -d '"') \ --resource-group $(azd env get-values | grep AZURE_RESOURCE_GROUP | cut -d '=' -f2 | tr -d '"') \ --query "appId" -o tsv
导航到 Azure 门户 → Application Insights → 事务搜索
你应该能看到:
/api/slow 超过 3 秒)/api/error-test 的异常详情让我们为关键业务事件添加自定义遥测。
文件:src/telemetry.py
from opencensus.ext.azure import metrics_exporter from opencensus.stats import aggregation as aggregation_module from opencensus.stats import measure as measure_module from opencensus.stats import stats as stats_module from opencensus.stats import view as view_module from opencensus.tags import tag_map as tag_map_module from opencensus.ext.azure.log_exporter import AzureLogHandler from opencensus.ext.azure.trace_exporter import AzureExporter from opencensus.trace import tracer as tracer_module import logging import os class TelemetryClient: """Custom telemetry client for Application Insights""" def __init__(self, connection_string=None): self.connection_string = connection_string or os.environ.get('APPLICATIONINSIGHTS_CONNECTION_STRING') if not self.connection_string: print("⚠️ Application Insights connection string not found") return # 设置日志记录器 self.logger = logging.getLogger(__name__) self.logger.addHandler(AzureLogHandler(connection_string=self.connection_string)) self.logger.setLevel(logging.INFO) # 设置指标导出器 self.stats = stats_module.stats self.view_manager = self.stats.view_manager self.stats_recorder = self.stats.stats_recorder exporter = metrics_exporter.new_metrics_exporter( connection_string=self.connection_string ) self.view_manager.register_exporter(exporter) # 设置追踪器 self.tracer = tracer_module.Tracer( exporter=AzureExporter(connection_string=self.connection_string) ) print("✅ Custom telemetry client initialized") def track_event(self, event_name: str, properties: dict = None): """Track custom business event""" properties = properties or {} self.logger.info( f"CustomEvent: {event_name}", extra={ 'custom_dimensions': { 'event_name': event_name, **properties } } ) def track_metric(self, metric_name: str, value: float, properties: dict = None): """Track custom metric""" properties = properties or {} self.logger.info( f"CustomMetric: {metric_name} = {value}", extra={ 'custom_dimensions': { 'metric_name': metric_name, 'value': value, **properties } } ) def track_dependency(self, name: str, dependency_type: str, duration: float, success: bool): """Track external dependency call""" with self.tracer.span(name=name) as span: span.add_attribute('dependency.type', dependency_type) span.add_attribute('duration', duration) span.add_attribute('success', success) # 全局遥测客户端 telemetry = TelemetryClient()
文件:src/app.py(增强版)
from flask import Flask, request, jsonify from telemetry import telemetry import time import random app = Flask(__name__) @app.route('/api/purchase', methods=['POST']) def purchase(): """Track purchase event with custom telemetry""" data = request.json product_id = data.get('product_id') quantity = data.get('quantity', 1) price = data.get('price', 0) # 跟踪业务事件 telemetry.track_event('Purchase', { 'product_id': product_id, 'quantity': quantity, 'total_amount': price * quantity, 'user_id': request.headers.get('X-User-Id', 'anonymous') }) # 跟踪收入指标 telemetry.track_metric('Revenue', price * quantity, { 'product_id': product_id, 'currency': 'USD' }) return jsonify({ 'order_id': f'ORD-{random.randint(1000, 9999)}', 'status': 'confirmed', 'total': price * quantity }) @app.route('/api/search') def search(): """Track search queries""" query = request.args.get('q', '') start_time = time.time() # 模拟搜索(将是实际的数据库查询) results = [{'id': 1, 'name': f'Result for {query}'}] duration = (time.time() - start_time) * 1000 # 转换为毫秒 # 跟踪搜索事件 telemetry.track_event('Search', { 'query': query, 'results_count': len(results), 'duration_ms': duration }) # 跟踪搜索性能指标 telemetry.track_metric('SearchDuration', duration, { 'query_length': len(query) }) return jsonify({'results': results, 'count': len(results)}) @app.route('/api/external-call') def external_call(): """Track external API dependency""" import requests start_time = time.time() success = True try: # 模拟外部 API 调用 response = requests.get('https://api.example.com/data', timeout=5) result = response.json() except Exception as e: success = False result = {'error': str(e)} duration = (time.time() - start_time) * 1000 # 跟踪依赖 telemetry.track_dependency( name='ExternalAPI', dependency_type='HTTP', duration=duration, success=success ) return jsonify(result) if __name__ == '__main__': app.run(host='0.0.0.0', port=8000)
# 跟踪购买事件 curl -X POST $APP_URL/api/purchase \ -H "Content-Type: application/json" \ -H "X-User-Id: user123" \ -d '{"product_id": 1, "quantity": 2, "price": 29.99}' # 跟踪搜索事件 curl "$APP_URL/api/search?q=laptop" # 跟踪外部依赖 curl $APP_URL/api/external-call
在 Azure 门户中查看:
导航到 Application Insights → 日志,然后运行:
// View purchase events traces | where customDimensions.event_name == "Purchase" | project timestamp, product_id = tostring(customDimensions.product_id), total_amount = todouble(customDimensions.total_amount), user_id = tostring(customDimensions.user_id) | order by timestamp desc // View revenue metrics traces | where customDimensions.metric_name == "Revenue" | summarize TotalRevenue = sum(todouble(customDimensions.value)) by bin(timestamp, 1h) | render timechart // View search performance traces | where customDimensions.event_name == "Search" | summarize AvgDuration = avg(todouble(customDimensions.duration_ms)), SearchCount = count() by bin(timestamp, 5m) | render timechart
对于微服务,Application Insights 会自动关联跨服务的请求。
文件:infra/main.bicep
targetScope = 'subscription' param environmentName string param location string = 'eastus' var tags = { 'azd-env-name': environmentName } resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: 'rg-${environmentName}' location: location tags: tags } // Monitoring (shared by all services) module monitoring './core/monitoring.bicep' = { name: 'monitoring' scope: rg params: { logAnalyticsName: 'log-${environmentName}' applicationInsightsName: 'appi-${environmentName}' location: location tags: tags } } // API Gateway module apiGateway './app/api-gateway.bicep' = { name: 'api-gateway' scope: rg params: { name: 'ca-gateway-${environmentName}' location: location tags: union(tags, { 'azd-service-name': 'gateway' }) applicationInsightsConnectionString: monitoring.outputs.applicationInsightsConnectionString } } // Product Service module productService './app/product-service.bicep' = { name: 'product-service' scope: rg params: { name: 'ca-products-${environmentName}' location: location tags: union(tags, { 'azd-service-name': 'products' }) applicationInsightsConnectionString: monitoring.outputs.applicationInsightsConnectionString } } // Order Service module orderService './app/order-service.bicep' = { name: 'order-service' scope: rg params: { name: 'ca-orders-${environmentName}' location: location tags: union(tags, { 'azd-service-name': 'orders' }) applicationInsightsConnectionString: monitoring.outputs.applicationInsightsConnectionString } } output APPLICATIONINSIGHTS_CONNECTION_STRING string = monitoring.outputs.applicationInsightsConnectionString output GATEWAY_URL string = apiGateway.outputs.uri
查询端到端追踪:
// Find complete request flow let traceId = "abc123..."; // Get from response header dependencies | union requests | where operation_Id == traceId | project timestamp, type = itemType, name, duration, success, cloud_RoleName | order by timestamp asc
实时指标提供 <1 秒延迟的实时遥测。
访问实时指标:
# 获取应用程序洞察资源 APPI_NAME=$(azd env get-values | grep APPLICATIONINSIGHTS_NAME | cut -d '=' -f2 | tr -d '"') # 获取资源组 RG_NAME=$(azd env get-values | grep AZURE_RESOURCE_GROUP | cut -d '=' -f2 | tr -d '"') echo "Navigate to: Azure Portal → Resource Groups → $RG_NAME → $APPI_NAME → Live Metrics"
实时可见内容:
# 生成负载以查看实时指标 for i in {1..100}; do curl $APP_URL/api/products & curl $APP_URL/api/search?q=test$i & done # 在 Azure 门户中查看实时指标 # 您应该看到请求速率激增
目标:为高错误率和慢响应创建警报。
步骤:
# 获取应用程序洞察资源ID APPI_ID=$(az monitor app-insights component show \ --app $APPI_NAME \ --resource-group $RG_NAME \ --query "id" -o tsv) # 为失败的请求创建指标警报 az monitor metrics alert create \ --name "High-Error-Rate" \ --resource-group $RG_NAME \ --scopes $APPI_ID \ --condition "count requests/failed > 10" \ --window-size 5m \ --evaluation-frequency 1m \ --description "Alert when error rate exceeds 10 per 5 minutes"
az monitor metrics alert create \ --name "Slow-Responses" \ --resource-group $RG_NAME \ --scopes $APPI_ID \ --condition "avg requests/duration > 3000" \ --window-size 5m \ --evaluation-frequency 1m \ --description "Alert when average response time exceeds 3 seconds"
文件:infra/core/alerts.bicep
param applicationInsightsId string param actionGroupId string = '' param location string = resourceGroup().location // High error rate alert resource errorRateAlert 'Microsoft.Insights/metricAlerts@2018-03-01' = { name: 'high-error-rate' location: 'global' properties: { description: 'Alert when error rate exceeds threshold' severity: 2 enabled: true scopes: [ applicationInsightsId ] evaluationFrequency: 'PT1M' windowSize: 'PT5M' criteria: { 'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria' allOf: [ { name: 'Error rate' metricName: 'requests/failed' operator: 'GreaterThan' threshold: 10 timeAggregation: 'Count' } ] } actions: actionGroupId != '' ? [ { actionGroupId: actionGroupId } ] : [] } } // Slow response alert resource slowResponseAlert 'Microsoft.Insights/metricAlerts@2018-03-01' = { name: 'slow-responses' location: 'global' properties: { description: 'Alert when response time is too high' severity: 3 enabled: true scopes: [ applicationInsightsId ] evaluationFrequency: 'PT1M' windowSize: 'PT5M' criteria: { 'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria' allOf: [ { name: 'Response duration' metricName: 'requests/duration' operator: 'GreaterThan' threshold: 3000 timeAggregation: 'Average' } ] } } } output errorAlertId string = errorRateAlert.id output slowResponseAlertId string = slowResponseAlert.id
# 生成错误 for i in {1..20}; do curl $APP_URL/api/error-test done # 生成缓慢响应 for i in {1..10}; do curl $APP_URL/api/slow done # 检查警报状态(等待5-10分钟) az monitor metrics alert list \ --resource-group $RG_NAME \ --query "[].{Name:name, Enabled:enabled, State:properties.enabled}" \ --output table
✅ 成功标准:
时间:20-25 分钟
目标:构建显示关键应用指标的仪表盘。
步骤:
导航到:Azure 门户 → 仪表盘 → 新建仪表盘
文件:infra/core/dashboard.bicep
param dashboardName string param applicationInsightsId string param location string = resourceGroup().location resource dashboard 'Microsoft.Portal/dashboards@2020-09-01-preview' = { name: dashboardName location: location properties: { lenses: [ { order: 0 parts: [ // Request count { position: { x: 0, y: 0, rowSpan: 4, colSpan: 6 } metadata: { type: 'Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart' inputs: [ { name: 'resourceId' value: applicationInsightsId } { name: 'query' value: ''' requests | summarize RequestCount = count() by bin(timestamp, 1h) | render timechart ''' } ] } } // Error rate { position: { x: 6, y: 0, rowSpan: 4, colSpan: 6 } metadata: { type: 'Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart' inputs: [ { name: 'resourceId' value: applicationInsightsId } { name: 'query' value: ''' requests | summarize Total = count(), Failed = countif(success == false) | extend ErrorRate = (Failed * 100.0) / Total | project ErrorRate ''' } ] } } ] } ] } } output dashboardId string = dashboard.id
# 添加到main.bicep module dashboard './core/dashboard.bicep' = { name: 'dashboard' scope: rg params: { dashboardName: 'dashboard-${environmentName}' applicationInsightsId: monitoring.outputs.applicationInsightsId location: location } } # 部署 azd up
✅ 成功标准:
时间:25-30 分钟
目标:跟踪 Azure OpenAI 使用情况(令牌、成本、延迟)。
步骤:
文件:src/ai_telemetry.py
from telemetry import telemetry from openai import AzureOpenAI import time class MonitoredAzureOpenAI: """Azure OpenAI client with automatic telemetry""" def __init__(self, api_key, endpoint, api_version="2024-02-01"): self.client = AzureOpenAI( api_key=api_key, api_version=api_version, azure_endpoint=endpoint ) def chat_completion(self, model: str, messages: list, **kwargs): """Track chat completion with telemetry""" start_time = time.time() try: # 调用 Azure OpenAI response = self.client.chat.completions.create( model=model, messages=messages, **kwargs ) duration = (time.time() - start_time) * 1000 # 毫秒 # 提取使用情况 usage = response.usage prompt_tokens = usage.prompt_tokens completion_tokens = usage.completion_tokens total_tokens = usage.total_tokens # 计算成本(GPT-4 定价) prompt_cost = (prompt_tokens / 1000) * 0.03 # 每 1K 令牌 $0.03 completion_cost = (completion_tokens / 1000) * 0.06 # 每 1K 令牌 $0.06 total_cost = prompt_cost + completion_cost # 跟踪自定义事件 telemetry.track_event('OpenAI_Request', { 'model': model, 'prompt_tokens': prompt_tokens, 'completion_tokens': completion_tokens, 'total_tokens': total_tokens, 'duration_ms': duration, 'cost_usd': total_cost, 'success': True }) # 跟踪指标 telemetry.track_metric('OpenAI_Tokens', total_tokens, { 'model': model, 'type': 'total' }) telemetry.track_metric('OpenAI_Cost', total_cost, { 'model': model, 'currency': 'USD' }) telemetry.track_metric('OpenAI_Duration', duration, { 'model': model }) return response except Exception as e: duration = (time.time() - start_time) * 1000 telemetry.track_event('OpenAI_Request', { 'model': model, 'duration_ms': duration, 'success': False, 'error': str(e) }) raise
from flask import Flask, request, jsonify from ai_telemetry import MonitoredAzureOpenAI import os app = Flask(__name__) # 初始化受监控的OpenAI客户端 openai_client = MonitoredAzureOpenAI( api_key=os.environ['AZURE_OPENAI_API_KEY'], endpoint=os.environ['AZURE_OPENAI_ENDPOINT'] ) @app.route('/api/chat', methods=['POST']) def chat(): data = request.json user_message = data.get('message') # 使用自动监控进行调用 response = openai_client.chat_completion( model='gpt-4', messages=[ {'role': 'user', 'content': user_message} ] ) return jsonify({ 'response': response.choices[0].message.content, 'tokens': response.usage.total_tokens })
// Total AI spend over time traces | where customDimensions.event_name == "OpenAI_Request" | where customDimensions.success == "True" | summarize TotalCost = sum(todouble(customDimensions.cost_usd)) by bin(timestamp, 1h) | render timechart // Token usage by model traces | where customDimensions.event_name == "OpenAI_Request" | summarize TotalTokens = sum(toint(customDimensions.total_tokens)), RequestCount = count() by Model = tostring(customDimensions.model) // Average latency traces | where customDimensions.event_name == "OpenAI_Request" | summarize AvgDuration = avg(todouble(customDimensions.duration_ms)) | project AvgDurationSeconds = AvgDuration / 1000 // Cost per request traces | where customDimensions.event_name == "OpenAI_Request" | extend Cost = todouble(customDimensions.cost_usd) | summarize TotalCost = sum(Cost), RequestCount = count(), AvgCostPerRequest = avg(Cost)
✅ 成功标准:
时间:35-45 分钟
通过采样遥测控制成本:
from opencensus.trace.samplers import ProbabilitySampler # 开发:100%采样 sampler = ProbabilitySampler(rate=1.0) # 生产:10%采样(降低90%的成本) sampler = ProbabilitySampler(rate=0.1) # 自适应采样(自动调整) from opencensus.trace.samplers import AdaptiveSampler sampler = AdaptiveSampler()
在 Bicep 中:
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { name: applicationInsightsName properties: { SamplingPercentage: 10 // 10% sampling } }
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: logAnalyticsName properties: { retentionInDays: 30 // Minimum (cheapest) // Options: 30, 31, 60, 90, 120, 180, 270, 365, 550, 730 } }
| 数据量 | 保留期 | 每月成本 |
|---|---|---|
| 1 GB/月 | 30 天 | ~$2-5 |
| 5 GB/月 | 30 天 | ~$10-15 |
| 10 GB/月 | 90 天 | ~$25-40 |
| 50 GB/月 | 90 天 | ~$100-150 |
免费层:包含 5 GB/月
测试你的理解:
Q1:AZD 如何配置 Application Insights?
infra/core/monitoring.bicep 中的 Bicep 模板自动完成Q2:哪个环境变量启用 Application Insights?
APPLICATIONINSIGHTS_CONNECTION_STRINGQ3:三种主要的遥测类型是什么?
动手验证:
# 检查是否配置了 Application Insights azd env get-values | grep APPLICATIONINSIGHTS # 验证遥测数据是否正常流动 az monitor app-insights metrics show \ --app $APPI_NAME \ --resource-group $RG_NAME \ --metric "requests/count"
测试你的理解:
Q1:如何跟踪自定义业务事件?
custom_dimensions 的日志记录器或 TelemetryClient.track_event()Q2:事件和指标的区别是什么?
Q3:如何跨服务关联遥测?
operation_Id 进行关联动手验证:
// Verify custom events traces | where customDimensions.event_name != "" | summarize count() by tostring(customDimensions.event_name)
测试你的理解:
Q1:什么是采样,为什么要使用它?
Q2:如何设置警报?
Q3:Log Analytics 和 Application Insights 有什么区别?
动手验证:
# 检查采样配置 az monitor app-insights component show \ --app $APPI_NAME \ --resource-group $RG_NAME \ --query "properties.SamplingPercentage"
使用关联 ID
logger.info('Processing order', extra={ 'custom_dimensions': { 'order_id': order_id, 'user_id': user_id } })
为关键指标设置警报
// Error rate, slow responses, availability
使用结构化日志
# ✅ 好的:结构化 logger.info('User signup', extra={'custom_dimensions': {'user_id': 123}}) # ❌ 不好的:非结构化 logger.info(f'User 123 signed up')
监控依赖项
# 自动跟踪数据库调用、HTTP请求等。
在部署期间使用实时指标
不要记录敏感数据
# ❌ 不好 logger.info(f'Login: {username}:{password}') # ✅ 好 logger.info('Login attempt', extra={'custom_dimensions': {'username': username}})
不要在生产环境中使用 100% 采样
# ❌ 昂贵 sampler = ProbabilitySampler(rate=1.0) # ✅ 划算 sampler = ProbabilitySampler(rate=0.1)
不要忽略死信队列
不要忘记设置数据保留限制
诊断:
# 检查是否设置了连接字符串 azd env get-values | grep APPLICATIONINSIGHTS # 检查应用程序日志 azd logs api --tail 50
解决方案:
# 验证容器应用中的连接字符串 az containerapp show \ --name $APP_NAME \ --resource-group $RG_NAME \ --query "properties.template.containers[0].env" \ | grep -i applicationinsights
诊断:
# 检查数据摄取 az monitor app-insights metrics show \ --app $APPI_NAME \ --resource-group $RG_NAME \ --metric "availabilityResults/count"
解决方案:
你已经学会了:
关键要点:
下一步:
免责声明:
本文档使用AI翻译服务Co-op Translator进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于重要信息,建议使用专业人工翻译。我们对因使用此翻译而产生的任何误解或误读不承担责任。