Skip to content

Add Log Analytics hybrid support for Activity Log and Resource Health - #9

Merged
marcelloformica merged 7 commits into
mainfrom
loganalytics
Mar 25, 2026
Merged

marcelloformica merged 7 commits into
mainfrom
loganalytics

Conversation

@marcelloformica

Copy link
Copy Markdown
Contributor

Summary

Adds -Workspace / --workspace parameter to both PowerShell and C# versions, enabling bulk KQL queries against a Log Analytics workspace instead of per-resource REST API calls for Activity Log lifecycle events and Resource Health transitions.

Key changes

PowerShell (get-availability.ps1)

  • New -Workspace parameter: accepts a Log Analytics workspace GUID
  • Bulk KQL query against AzureActivity table fetches both Activity Log lifecycle events and Resource Health transitions in a single call (vs thousands of per-resource REST calls)
  • Incident-based health event consolidation: replicates REST API's curated behaviour — lifecycle phases (Activated/Updated/InProgress/Resolved) are consolidated into clean state transitions with retroactive cause correction
  • Hybrid Resource Health merge: LA transitions cover periods beyond the REST API's ~30-day retention; REST transitions are authoritative for the last ~30 days
  • Comprehensive comments added throughout (~26 locations)
  • Fixed batch retry bug: removed HTTP 401 from retryable status codes (401 is auth failure, not transient)

C# (Native AOT)

  • New --workspace\ / -w\ CLI parameter with GUID validation
  • **New \LogAnalyticsService.cs**: KQL query execution, column-indexed response parsing, incident-based post-processing with retroactive cause correction
  • **Updated \ResourceHealthService.cs**: hybrid merge logic, \GetHealthCoverageStart(useLogAnalytics)\ overload, \GetRestHealthCutoff(), public \HealthTransition\ type
  • **Updated \ActivityLogService.cs**: \BuildLifecycleIntervalsFromEvents()\ for LA events, extracted shared \BuildIntervalsFromEvents()\
  • **Updated \Program.cs**: workspace CLI parsing, LA data fetching pipeline, health coverage display
  • Fixed batch retry bug (same as PS — removed 401 from retry condition)
  • Added missing comments across Program.cs, BatchMetricsService.cs, SummaryWriter.cs

README

  • Added --workspace\ to C# parameter table (was PS-only, now both)
  • Added C# workspace usage example
  • Updated observation window paragraph to reference both versions

Testing

Comparative test with 3 subscriptions (215 resources) using -Workspace:

  • PowerShell: 01:03 — C# AOT: 00:43 (31% faster)
  • All per-resource classifications, fault counts, excused minutes, and availability percentages match identically
  • Only differences: 5-minute observation window offset (month-to-date) and occasional 0.00001% rounding at 5th decimal

Commits (7)

  1. \43ea98f\ — Add Log Analytics as alternative data source (PS)
  2. \13bb9f5\ — Update README for Log Analytics support
  3. \86751b0\ — Fix null HttpClient crash in workspace mode
  4. \121d890\ — Fix LA health transitions: incident-based timeline
  5. \�d5de51\ — Add comprehensive comments and fix batch retry logic (PS)
  6. \c516cc7\ — Add Log Analytics hybrid support to C# version
  7. \�2b9e2c\ — C# final pass: fix 401 retry bug, add comments, align README

…ource Health

- Add -Workspace parameter (LA workspace GUID) with validation
- Add Get-LogAnalyticsData function: single KQL query fetches both Activity Log
  lifecycle events and Resource Health transitions from AzureActivity table
- Refactor Invoke-SuspectGapInvestigation with dual paths: pre-fetched LA data
  when available, REST API fallback when -Workspace not specified
- Update Get-HealthCoverageStart to bypass 30-day clamp in LA mode
- Update .DESCRIPTION and function comments to document both modes
- No changes to compiled types (MetricProcessor, GapProcessor)
- Add -Workspace row to PowerShell parameters table
- Add note that C# --workspace support is planned
- Add PowerShell example with -Workspace
- Document LA info line and 30-day warning suppression in Output section
- Update Suspect gap investigation: dual data source paths (REST vs LA)
- Update observation window note for LA retention override
…events

When -Workspace is specified but a resource has no Activity Log or Resource
Health events in the LA data, resLaData is null. The fallback condition
'elseif (-not )' incorrectly triggered the REST API path, which
tried to use the null HttpClient (not created in workspace mode).

Fix: change both fallback conditions to 'elseif (-not )' so the REST
API path is only attempted when NOT in workspace mode. In workspace mode,
absence of a resource from the LA result correctly means no events.
…dation

AzureActivity ResourceHealth events include multiple lifecycle events
(Activated, Updated, InProgress, Resolved) per health incident. The
previous code treated each event as an independent state transition,
causing:
- Activated events (cause=Unknown) to create phantom faults before the
  real cause was determined via subsequent Updated events.
- Stale Updated events arriving after Resolved to create phantom
  unavailability periods.
- Concurrent InProgress+Activated events to produce conflicting causes.

The REST API retroactively applies the final cause to the entire incident.
This commit replicates that behaviour:
1. Add OperationNameValue to the KQL health data projection.
2. Track health incidents (Activated/InProgress -> Resolved) and collect
   the latest non-Unknown cause within each incident.
3. Only create transitions when the health state actually changes.
4. On Resolved, retroactively apply the final cause to all transitions
   in that incident, matching the REST API's curated timeline.
5. Skip orphan Updated events outside any incident (stale events).

Tested: win22ans0-PROD faults 122->2 (matches REST), tmaceal01azne
720->0,  spocovm01a 949->0.  OVERALL improved from 99.68% to 99.97%.
- Add inline comments to ~25 uncommented code sections covering health
  event parsing, incident post-processing, batch/per-resource metric
  collection, Activity Log investigation, Resource Health interval
  building, suspect classification, result assembly, and pipeline steps
- Fix batch metric retry: remove HTTP 401 from retryable status codes
  (401 is permanent auth failure, only 429 should be retried)
- Update README to accurately describe the hybrid LA+REST approach for
  Resource Health data (KQL for older transitions, REST API authoritative
  for last ~30 days)
- Add LogAnalyticsService.cs: single bulk KQL query fetches Activity Log
  lifecycle events and Resource Health transitions from a workspace.
  Health events undergo incident-based post-processing (Activated/Updated/
  InProgress/Resolved consolidation with retroactive cause correction)
  to match REST API's curated timeline.
- Update ResourceHealthService: add hybrid merge logic (LA transitions
  older than REST ~30-day cutoff + REST transitions for last ~30 days),
  add GetHealthCoverageStart(useLogAnalytics) overload and
  GetRestHealthCutoff(), pass LA data through investigation pipeline.
- Update ActivityLogService: add BuildLifecycleIntervalsFromEvents()
  for processing pre-fetched LA events, extract shared interval-building
  logic into BuildIntervalsFromEvents().
- Update Program.cs: add --workspace/-w CLI parameter with GUID
  validation, integrate LA data fetching before investigation, display
  workspace info line and suppress 30-day health coverage warning in
  hybrid mode.
- BatchMetricsService: remove 401 from retry condition (same bug
  previously fixed in PowerShell — 401 is not retryable)
- Program.cs: expand comments on suspect candidate assembly,
  investigation result integration, and result assembly sections
- BatchMetricsService: add XML doc comments to ProcessVmOrSqlBatch,
  ProcessStorageBatch, and inline comments for grouping/parsing logic
- SummaryWriter: document format string column layout
- README: add --workspace/-w to C# parameter table, add C# workspace
  usage example, remove outdated 'PS-only' note, update observation
  window paragraph to reference both versions
@marcelloformica
marcelloformica merged commit 90b57b4 into main Mar 25, 2026
1 check passed
@marcelloformica
marcelloformica deleted the loganalytics branch March 25, 2026 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant