Skip to content

Observability Stack

Complete monitoring and observability with data residency compliance for logs, metrics, and traces.


Observability is critical for operating sovereign cloud environments, but telemetry data often contains sensitive information. This module covers designing observability stacks that maintain data residency while providing comprehensive monitoring capabilities.

After completing this section, you will be able to:

  • ✅ Design regional observability architectures
  • ✅ Configure Log Analytics with data residency
  • ✅ Implement distributed tracing with sovereignty controls
  • ✅ Set up alerting and dashboards

Observability Stack

Observability Stack Figure 1: Complete observability stack with regional data collection and storage

ComponentPurposeData Residency
Application InsightsAPM, tracesRegional workspace
Log AnalyticsCentral loggingRegional retention
Microsoft SentinelSecurity monitoringRegional
DatabricksLog analysisRegional compute
Blob StorageLong-term archiveRegional GRS

Terminal window
# Create regional Log Analytics workspace
New-AzOperationalInsightsWorkspace `
-ResourceGroupName "monitoring-rg" `
-Name "eu-logs-workspace" `
-Location "westeurope" `
-Sku "PerGB2018" `
-RetentionInDays 90
# Configure diagnostic settings for resources
Set-AzDiagnosticSetting `
-ResourceId "/subscriptions/{sub}/resourceGroups/app-rg/providers/Microsoft.Web/sites/myapp" `
-WorkspaceId "/subscriptions/{sub}/resourceGroups/monitoring-rg/providers/Microsoft.OperationalInsights/workspaces/eu-logs-workspace" `
-Enabled $true `
-Category @("AppServiceHTTPLogs", "AppServiceConsoleLogs", "AppServiceAuditLogs")
# Log Analytics workspace configuration
logAnalytics:
name: "eu-logs-workspace"
location: "westeurope"
dataResidency:
region: "EU"
dataExportBlocked: true
crossRegionQueryBlocked: true
retention:
interactive: 90 # days
archive: 730 # 2 years for compliance
accessControl:
rbac: true
tableLevel: true
resourceCentric: true
ingestion:
dailyCap: 100 # GB
warningThreshold: 80

// Configure Application Insights with regional workspace
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry(options =>
{
options.ConnectionString = Configuration["ApplicationInsights:ConnectionString"];
options.EnableAdaptiveSampling = true;
});
// Add telemetry processor for PII filtering
services.AddApplicationInsightsTelemetryProcessor<SovereignTelemetryProcessor>();
}
// PII filtering processor
public class SovereignTelemetryProcessor : ITelemetryProcessor
{
public void Process(ITelemetry item)
{
if (item is RequestTelemetry request)
{
// Mask PII in URLs
request.Url = MaskPiiInUrl(request.Url);
request.Name = MaskPiiInUrl(request.Name);
}
if (item is TraceTelemetry trace)
{
// Filter sensitive log messages
trace.Message = FilterSensitiveData(trace.Message);
}
_next.Process(item);
}
}
# OpenTelemetry configuration
openTelemetry:
serviceName: "sovereign-app"
exporter:
type: "AzureMonitor"
connectionString: "${APPLICATIONINSIGHTS_CONNECTION_STRING}"
sampling:
type: "parentBased"
rate: 0.1 # 10% sampling
spanProcessors:
- type: "batch"
maxQueueSize: 2048
maxExportBatchSize: 512
resourceAttributes:
service.region: "westeurope"
deployment.environment: "production"
data.classification: "internal"

// Custom metrics query for sovereignty compliance
AzureMetrics
| where TimeGenerated > ago(1h)
| where ResourceProvider == "MICROSOFT.WEB"
| summarize
AvgResponseTime = avg(Average),
P95ResponseTime = percentile(Average, 95),
RequestCount = sum(Count)
by ResourceId, MetricName, bin(TimeGenerated, 5m)
| where MetricName in ("HttpResponseTime", "Requests", "Http5xx")
// Emit custom sovereignty metrics
public class SovereigntyMetrics
{
private readonly TelemetryClient _telemetry;
public void TrackCrossRegionRequest(string sourceRegion, string targetRegion, bool blocked)
{
_telemetry.TrackMetric(new MetricTelemetry
{
Name = "CrossRegionRequest",
Sum = 1,
Properties =
{
["SourceRegion"] = sourceRegion,
["TargetRegion"] = targetRegion,
["Blocked"] = blocked.ToString()
}
});
if (blocked)
{
_telemetry.TrackEvent("SovereigntyViolationBlocked", new Dictionary<string, string>
{
["SourceRegion"] = sourceRegion,
["TargetRegion"] = targetRegion
});
}
}
}

Terminal window
# Create alert for cross-region data access attempts
New-AzScheduledQueryRule `
-ResourceGroupName "monitoring-rg" `
-Location "westeurope" `
-Name "CrossRegionAccessAlert" `
-Description "Alert on cross-region data access attempts" `
-Scope "/subscriptions/{sub}/resourceGroups/monitoring-rg/providers/Microsoft.OperationalInsights/workspaces/eu-logs-workspace" `
-WindowSize (New-TimeSpan -Minutes 5) `
-Frequency (New-TimeSpan -Minutes 5) `
-Severity 1 `
-CriteriaAllOf @(
New-AzScheduledQueryRuleDimensionedAlert `
-Query 'AzureActivity | where OperationNameValue contains "write" | where CallerIpAddress !startswith "10." | where _ResourceId !contains "westeurope" and _ResourceId !contains "northeurope"' `
-TimeAggregation "Count" `
-Operator "GreaterThan" `
-Threshold 0
) `
-ActionGroupId "/subscriptions/{sub}/resourceGroups/monitoring-rg/providers/microsoft.insights/actionGroups/security-team"
CategorySeverityResponse SLA
Sovereignty Violation0 (Critical)15 minutes
Security Incident1 (Error)1 hour
Performance Degradation2 (Warning)4 hours
Operational3 (Info)24 hours

Terminal window
# Configure data export to regional storage
New-AzOperationalInsightsDataExport `
-ResourceGroupName "monitoring-rg" `
-WorkspaceName "eu-logs-workspace" `
-DataExportName "compliance-archive" `
-DestinationResourceId "/subscriptions/{sub}/resourceGroups/storage-rg/providers/Microsoft.Storage/storageAccounts/eulogarchive" `
-TableName @("SecurityEvent", "AzureActivity", "SigninLogs") `
-Enable $true
Data TypeInteractiveArchiveTotal
Security Logs90 days7 years7 years
Audit Logs90 days5 years5 years
Application Logs30 days1 year1 year
Metrics93 daysN/A93 days

// Dashboard query: Sovereignty health overview
let dataResidencyViolations = AzureActivity
| where TimeGenerated > ago(24h)
| where Properties contains "cross-region"
| count;
let securityIncidents = SecurityIncident
| where TimeGenerated > ago(24h)
| where Status != "Closed"
| count;
let complianceScore = AzurePolicyComplianceState
| where TimeGenerated > ago(1h)
| summarize Compliant = countif(ComplianceState == "Compliant"), Total = count()
| extend Score = round(100.0 * Compliant / Total, 1);
union
(dataResidencyViolations | extend Metric = "DataResidencyViolations"),
(securityIncidents | extend Metric = "OpenSecurityIncidents"),
(complianceScore | extend Metric = "ComplianceScore", Count = Score)

  • Deploy regional Log Analytics workspace
  • Configure Application Insights
  • Set up distributed tracing
  • Implement PII filtering
  • Configure alerting rules
  • Set up data export to storage
  • Create sovereignty dashboards
  • Configure retention policies
  • Enable Sentinel integration


Reference: Azure Monitor — Microsoft Learn