nano SIEM
Case Management

Audit Events & SOC Metrics

Audit Events & SOC Metrics

Every case action in nano is automatically logged as a searchable audit event with source_type=audit and source=case. This enables building SOC metrics dashboards to track key performance indicators like MTTD (Mean Time to Detect), MTTR (Mean Time to Respond), analyst workload, and disposition trends.

Overview

Case audit events are stored in the same log storage (ClickHouse) as your security data, making them queryable using the standard nano search interface. This approach allows you to:

  • Build dashboards using native nano dashboard capabilities
  • Correlate SOC metrics with security events
  • Create alerts on operational anomalies (e.g., case backlog growing)
  • Export metrics to external systems via API

Audit Event Schema

Source Type

All case audit events have:

source_type = "audit"
source = "case"

Event Actions

ActionDescriptionWhen Emitted
createdCase was createdNew case created (manual or auto-grouped)
alert_addedAlert added to caseAlert grouped into case
alert_removedAlert removed from caseAlert manually removed
status_changedStatus changedStatus transition (not resolve/close/reopen)
assignedCase assignedAnalyst assigned to case
unassignedCase unassignedAssignment removed
resolvedCase resolvedStatus changed to "resolved"
closedCase closedStatus changed to "closed"
reopenedCase reopenedClosed/resolved case reopened
comment_addedComment addedAnalyst adds comment to case wall
ai_analysisAI analysis generatedAI summary or triage generated
severity_changedSeverity changedCase severity modified
mergedCases mergedCase merged with another
entity_addedEntity addedNew entity extracted/added

Event Fields

FieldTypeDescription
case_idUUIDUnique case identifier
case_numberIntegerHuman-readable case number (CASE-1234)
case_titleStringCase title
actionStringAction type (see table above)
actor_idUUIDUser who performed the action
actor_nameStringUsername of actor
severityStringCase severity at time of event
statusStringCase status at time of event
previous_statusStringPrevious status (for status changes)
dispositionStringDisposition (for resolved/closed)
assigned_toUUIDAssigned analyst ID
assigned_to_nameStringAssigned analyst name
alert_countIntegerNumber of alerts in case
entity_countIntegerNumber of entities in case
grouping_typeStringHow case was grouped (host/user/ip/rule/manual)

Timing Metrics

These fields enable SOC performance dashboards:

FieldTypeDescription
time_since_creation_secondsIntegerSeconds since case was created
time_to_assign_secondsIntegerSeconds from creation to first assignment
time_to_resolve_secondsIntegerSeconds from creation to resolution (MTTR)
time_to_detect_secondsIntegerSeconds from first alert to case creation (MTTD)
time_in_status_secondsIntegerSeconds case spent in previous status

Additional Context

FieldTypeDescription
alert_idUUIDRelated alert (for alert_added/removed)
entity_valueStringRelated entity value
entity_typeStringRelated entity type
related_case_idUUIDRelated case (for merges)
notesStringComment content (truncated to 500 chars)

Querying Audit Events

Basic Queries

All Case Creations

source_type=audit source=case action=created

All Resolutions Today

source_type=audit source=case action=resolved
| where timestamp > now() - 24h

High Severity Case Activity

source_type=audit source=case severity=critical OR severity=high

Activity by Specific Analyst

source_type=audit source=case actor_name="jsmith"

SOC Metrics Dashboards

Mean Time to Resolve (MTTR)

The most important SOC metric - how long it takes to close cases:

source_type=audit source=case action=resolved
| stats avg(time_to_resolve_seconds) as avg_mttr_seconds
| eval avg_mttr_hours = avg_mttr_seconds / 3600
| eval avg_mttr_minutes = avg_mttr_seconds / 60

MTTR by Severity

source_type=audit source=case action=resolved
| stats avg(time_to_resolve_seconds) as avg_mttr by severity
| eval avg_mttr_hours = avg_mttr / 3600
| sort severity

MTTR Trend Over Time

source_type=audit source=case action=resolved
| bucket timestamp span=1d
| stats avg(time_to_resolve_seconds) as avg_mttr by timestamp
| eval avg_mttr_hours = avg_mttr / 3600

Mean Time to Detect (MTTD)

How quickly threats are identified:

source_type=audit source=case action=created
| where time_to_detect_seconds > 0
| stats avg(time_to_detect_seconds) as avg_mttd
| eval avg_mttd_minutes = avg_mttd / 60

Mean Time to Assign (MTTA)

How quickly cases are picked up by analysts:

source_type=audit source=case action=assigned
| stats avg(time_to_assign_seconds) as avg_mtta
| eval avg_mtta_minutes = avg_mtta / 60

Analyst Workload

Cases per Analyst

source_type=audit source=case action=assigned
| stats count by assigned_to_name
| sort -count

Resolutions per Analyst

source_type=audit source=case action=resolved
| stats count by actor_name
| sort -count

Active Case Load by Analyst

source_type=audit source=case action=assigned
| stats latest(status) as current_status by case_id, assigned_to_name
| where current_status != "closed" AND current_status != "resolved"
| stats count by assigned_to_name

Disposition Analysis

Disposition Distribution

source_type=audit source=case action=resolved OR action=closed
| where disposition != ""
| stats count by disposition

False Positive Rate

source_type=audit source=case action=resolved OR action=closed
| where disposition != ""
| stats
    count(eval(disposition="false_positive")) as false_positives,
    count as total
| eval fp_rate = (false_positives / total) * 100

Dispositions by Detection Rule

source_type=audit source=case action=resolved
| stats count by case_title, disposition
| sort case_title, -count

Cases Created per Day

source_type=audit source=case action=created
| bucket timestamp span=1d
| stats count by timestamp

Cases by Severity Over Time

source_type=audit source=case action=created
| bucket timestamp span=1d
| stats count by timestamp, severity

Cases by Grouping Type

source_type=audit source=case action=created
| stats count by grouping_type

Case Backlog

Open Case Count

source_type=audit source=case
| stats latest(status) as current_status by case_id
| where current_status = "open" OR current_status = "in_progress" OR current_status = "pending"
| stats count

Aging Cases (Open > 24 hours)

source_type=audit source=case action=created
| stats min(timestamp) as created_at by case_id
| join case_id [
    source_type=audit source=case
    | stats latest(status) as current_status by case_id
]
| where current_status != "closed" AND current_status != "resolved"
| eval age_hours = (now() - created_at) / 3600
| where age_hours > 24
| stats count

Alert Correlation

Alerts per Case Distribution

source_type=audit source=case action=resolved
| stats avg(alert_count) as avg_alerts, max(alert_count) as max_alerts

Cases with Most Alerts

source_type=audit source=case
| stats max(alert_count) as alerts by case_number, case_title
| sort -alerts
| head 10

Dashboard Examples

Executive SOC Dashboard

Create a dashboard with these panels:

PanelQueryVisualization
MTTR (Hours)MTTR query aboveSingle value
MTTD (Minutes)MTTD query aboveSingle value
Open CasesBacklog countSingle value
Cases TodayCreated today countSingle value
MTTR TrendMTTR by dayLine chart
Cases by SeverityVolume by severityPie chart
Disposition BreakdownDisposition distributionPie chart
Analyst WorkloadCases per analystBar chart

Analyst Performance Dashboard

PanelQueryVisualization
My Open CasesFilter by current userTable
My Resolutions (Week)Resolved by me, 7 daysSingle value
Avg Resolution TimeMy MTTRSingle value
My Disposition BreakdownMy dispositionsPie chart
Cases Resolved per DayMy resolutions by dayBar chart

Detection Tuning Dashboard

PanelQueryVisualization
False Positive RateFP rate queryGauge
FP by RuleDispositions by ruleTable
Most Active RulesCases by ruleBar chart
Rules Needing TuningHigh FP rulesTable

Alerting on Metrics

Create detection rules on audit events to alert on operational issues:

High Case Backlog Alert

name: SOC Case Backlog Alert
query: |
  source_type=audit source=case
  | stats latest(status) as status by case_id
  | where status = "open"
  | stats count as open_cases
  | where open_cases > 50
schedule: "*/15 * * * *"
severity: medium

Stale Cases Alert

name: Stale Case Alert
query: |
  source_type=audit source=case action=created
  | stats min(timestamp) as created by case_id
  | join case_id [
      source_type=audit source=case | stats latest(status) as status by case_id
  ]
  | where status = "open"
  | eval age_hours = (now() - created) / 3600
  | where age_hours > 48
  | stats count as stale_cases
  | where stale_cases > 0
schedule: "0 */6 * * *"
severity: low

MTTR Degradation Alert

name: MTTR Degradation Alert
query: |
  source_type=audit source=case action=resolved
  | where timestamp > now() - 24h
  | stats avg(time_to_resolve_seconds) as mttr
  | where mttr > 14400  -- 4 hours
schedule: "0 * * * *"
severity: medium

Best Practices

1. Baseline Your Metrics

Before setting alerts, establish baselines:

  • What is your normal MTTR?
  • What is your typical case volume?
  • What is your expected false positive rate?

Single data points can be misleading. Focus on trends:

  • Is MTTR improving over time?
  • Is case volume seasonal?
  • Are certain rules generating more false positives?

3. Segment by Severity

Aggregate metrics hide important details:

  • Critical cases should have lower MTTR than low severity
  • Track metrics per severity level

4. Review Regularly

Schedule regular reviews of SOC metrics:

  • Weekly: Analyst performance, backlog health
  • Monthly: MTTR/MTTD trends, false positive rates
  • Quarterly: Detection tuning opportunities

5. Export for Reporting

Use the API to export metrics for executive reporting:

# Export MTTR data
curl "/api/search" -d '{
  "query": "source_type=audit source=case action=resolved | stats avg(time_to_resolve_seconds) by severity",
  "start": "-30d",
  "end": "now"
}'

API Reference

Query Audit Events

POST /api/search
{
  "query": "source_type=audit source=case action=resolved",
  "start": "-7d",
  "end": "now",
  "limit": 1000
}

Get Case Audit Trail

GET /api/cases/:id/wall

Returns all audit events for a specific case as wall entries.

On this page

On this page