{
  "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json",
  "version": "Notebook/1.0",
  "items": [
    {
      "type": 1,
      "content": {
        "json": "## Whisper Security - Incident Enrichment Audit\nThis workbook provides operational visibility into the Whisper Security enrichment playbooks running in Microsoft Sentinel. Track success and failure rates, monitor latency percentiles, review enrichment volume trends, and investigate error patterns to ensure reliable threat intelligence enrichment.\n\n> **Prerequisite:** Populates from the `AzureDiagnostics` table. Enable **Diagnostic Settings** on each Whisper Logic App (send `WorkflowRuntime` to this workspace) so playbook runs are recorded. Panels stay empty until the first diagnostic records arrive."
      },
      "name": "header-markdown"
    },
    {
      "type": 3,
      "content": {
        "version": "KqlItem/1.0",
        "query": "AzureDiagnostics\n| where ResourceProvider == 'MICROSOFT.LOGIC'\n| extend WorkflowName = column_ifexists('resource_workflowName_s', ''), Status = column_ifexists('status_s', '')\n| where WorkflowName has 'Whisper'\n| where Status in ('Succeeded', 'Failed')\n| summarize Succeeded = countif(Status == 'Succeeded'), Failed = countif(Status == 'Failed') by WorkflowName\n| extend Total = Succeeded + Failed\n| extend SuccessRate = round(100.0 * Succeeded / Total, 1)\n| project PlaybookName = WorkflowName, Succeeded, Failed, Total, SuccessRate\n| order by Total desc",
        "size": 0,
        "title": "Enrichment Playbook Success and Failure Rates",
        "queryType": 0,
        "resourceType": "microsoft.operationalinsights/workspaces",
        "visualization": "table",
        "gridSettings": {
          "formatters": [
            {
              "columnMatch": "SuccessRate",
              "formatter": 8,
              "formatOptions": {
                "palette": "redGreen"
              }
            },
            {
              "columnMatch": "Failed",
              "formatter": 8,
              "formatOptions": {
                "palette": "greenRed"
              }
            }
          ]
        }
      },
      "name": "success-failure-rates"
    },
    {
      "type": 3,
      "content": {
        "version": "KqlItem/1.0",
        "query": "AzureDiagnostics\n| where ResourceProvider == 'MICROSOFT.LOGIC'\n| extend WorkflowName = column_ifexists('resource_workflowName_s', ''), Status = column_ifexists('status_s', ''), Duration = column_ifexists('duration_s', '')\n| where WorkflowName has 'Whisper'\n| where Status == 'Succeeded'\n| where isnotempty(Duration)\n| extend DurationMs = toreal(extract(@'(\\d+\\.?\\d*)', 1, Duration))\n| summarize P50 = percentile(DurationMs, 50), P90 = percentile(DurationMs, 90), P95 = percentile(DurationMs, 95), P99 = percentile(DurationMs, 99) by bin(TimeGenerated, 1h)\n| order by TimeGenerated asc",
        "size": 0,
        "title": "Enrichment Latency Percentiles Over Time",
        "queryType": 0,
        "resourceType": "microsoft.operationalinsights/workspaces",
        "visualization": "timechart"
      },
      "name": "latency-percentiles"
    },
    {
      "type": 3,
      "content": {
        "version": "KqlItem/1.0",
        "query": "AzureDiagnostics\n| where ResourceProvider == 'MICROSOFT.LOGIC'\n| extend WorkflowName = column_ifexists('resource_workflowName_s', ''), Status = column_ifexists('status_s', '')\n| where WorkflowName has 'Whisper'\n| where Status in ('Succeeded', 'Failed')\n| summarize EnrichmentCount = count() by bin(TimeGenerated, 1d), Status\n| order by TimeGenerated asc",
        "size": 0,
        "title": "Enrichment Volume Over Time",
        "queryType": 0,
        "resourceType": "microsoft.operationalinsights/workspaces",
        "visualization": "timechart"
      },
      "name": "enrichment-volume"
    },
    {
      "type": 3,
      "content": {
        "version": "KqlItem/1.0",
        "query": "AzureDiagnostics\n| where ResourceProvider == 'MICROSOFT.LOGIC'\n| extend WorkflowName = column_ifexists('resource_workflowName_s', ''), Status = column_ifexists('status_s', '')\n| where WorkflowName has 'Whisper'\n| where Status == 'Failed'\n| extend ErrorCode = coalesce(column_ifexists('error_code_s', ''), column_ifexists('code_s', ''), 'Unknown')\n| extend ErrorMessage = coalesce(column_ifexists('error_message_s', ''), 'No message available')\n| summarize ErrorCount = count() by WorkflowName, ErrorCode, ErrorMessage\n| order by ErrorCount desc",
        "size": 0,
        "title": "Error Breakdown by Playbook and Error Type",
        "queryType": 0,
        "resourceType": "microsoft.operationalinsights/workspaces",
        "visualization": "table",
        "gridSettings": {
          "formatters": [
            {
              "columnMatch": "ErrorCount",
              "formatter": 8,
              "formatOptions": {
                "palette": "greenRed"
              }
            }
          ]
        }
      },
      "name": "error-breakdown"
    }
  ],
  "fallbackResourceIds": [],
  "fromTemplateId": "sentinel-IncidentEnrichmentAuditWorkbook"
}