# Metrics Analysis

> Analyze security operations metrics including MTTD, MTTR, incident volume trends, false positive rates, and analyst workload distribution

- Skill: `happy-technologies-llc/metrics-analysis` (Agent Skill)
- Install (CLI): `npx skillmds@latest add happy-technologies-llc/metrics-analysis`
- Raw SKILL.md: https://api.skillmd.com/api/skills/happy-technologies-llc/metrics-analysis/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: Happy-Technologies-LLC (https://skillmd.com/u/happy-technologies-llc)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/happy-technologies-llc/metrics-analysis

---


# Security Operations Metrics Analysis

## Overview

This skill provides a structured approach to analyzing key security operations metrics in ServiceNow. It enables SOC managers and analysts to measure detection and response effectiveness, identify trends, and optimize resource allocation.

Key capabilities:
- Calculate Mean Time to Detect (MTTD) and Mean Time to Respond (MTTR) across incident populations
- Track incident volume trends by category, priority, and time period
- Measure false positive rates and their impact on analyst productivity
- Analyze analyst workload distribution and identify bottlenecks
- Benchmark current performance against historical baselines and industry targets
- Generate metrics dashboards and reports for management review

**When to use:** During periodic SOC performance reviews (weekly, monthly, quarterly), management reporting, capacity planning, or when optimizing detection and response processes.

## Prerequisites

- **Roles:** `sn_si.manager`, `sn_si.admin`, `report_admin`
- **Access:** Read access to `sn_si_incident`, `sn_si_task`, `sn_ti_observable`, `sys_audit` tables; access to Aggregate API
- **Plugins:** Security Incident Response (sn_si), Performance Analytics (optional but recommended)
- **Data:** Sufficient incident history (minimum 30 days recommended for trend analysis)

## Procedure

### Step 1: Calculate Incident Volume by Period

Query incident counts by time period to establish volume trends.

**Using MCP:**
```
Tool: SN-Query-Table
Parameters:
  table_name: sn_si_incident
  query: opened_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)
  fields: sys_id,number,category,subcategory,priority,state,opened_at,resolved_at,closed_at,close_code,assignment_group
  limit: 1000
```

**Using REST (Aggregate API for counts):**
```
GET /api/now/stats/sn_si_incident?sysparm_query=opened_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)&sysparm_count=true&sysparm_group_by=category

GET /api/now/stats/sn_si_incident?sysparm_query=opened_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)&sysparm_count=true&sysparm_group_by=priority
```

### Step 2: Calculate Mean Time to Detect (MTTD)

MTTD measures the elapsed time between when a threat first appears and when it is detected. Use observable `first_seen` timestamps compared to incident `opened_at`.

**Using MCP:**
```
Tool: SN-Execute-Background-Script
Parameters:
  script: |
    var gr = new GlideRecord('sn_si_incident');
    gr.addQuery('opened_at', '>=', gs.daysAgo(30));
    gr.addQuery('state', 'IN', '6,7'); // resolved or closed
    gr.query();
    var totalDetectTime = 0;
    var count = 0;
    while (gr.next()) {
      var obs = new GlideRecord('sn_ti_observable');
      obs.addQuery('security_incident', gr.sys_id);
      obs.orderBy('first_seen');
      obs.setLimit(1);
      obs.query();
      if (obs.next() && obs.first_seen) {
        var firstSeen = new GlideDateTime(obs.first_seen);
        var opened = new GlideDateTime(gr.opened_at);
        var diff = GlideDateTime.subtract(firstSeen, opened);
        totalDetectTime += diff.getNumericValue();
        count++;
      }
    }
    var avgMs = count > 0 ? totalDetectTime / count : 0;
    var avgHours = (avgMs / 3600000).toFixed(2);
    gs.info('MTTD: ' + avgHours + ' hours (based on ' + count + ' incidents)');
```

**Using REST (manual calculation):**
```
GET /api/now/table/sn_si_incident?sysparm_query=opened_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)^stateIN6,7&sysparm_fields=sys_id,number,opened_at,resolved_at&sysparm_limit=500

# For each incident, query earliest observable:
GET /api/now/table/sn_ti_observable?sysparm_query=security_incident=[SYS_ID]^ORDERBYfirst_seen&sysparm_fields=first_seen&sysparm_limit=1
```

### Step 3: Calculate Mean Time to Respond (MTTR)

MTTR measures elapsed time from incident creation to resolution.

**Using MCP:**
```
Tool: SN-Execute-Background-Script
Parameters:
  script: |
    var gr = new GlideRecord('sn_si_incident');
    gr.addQuery('opened_at', '>=', gs.daysAgo(30));
    gr.addQuery('resolved_at', '!=', '');
    gr.query();
    var totalResponseTime = 0;
    var count = 0;
    while (gr.next()) {
      var opened = new GlideDateTime(gr.opened_at);
      var resolved = new GlideDateTime(gr.resolved_at);
      var diff = GlideDateTime.subtract(opened, resolved);
      totalResponseTime += diff.getNumericValue();
      count++;
    }
    var avgMs = count > 0 ? totalResponseTime / count : 0;
    var avgHours = (avgMs / 3600000).toFixed(2);
    gs.info('MTTR: ' + avgHours + ' hours (based on ' + count + ' incidents)');
```

**Using REST (Aggregate API):**
```
GET /api/now/stats/sn_si_incident?sysparm_query=opened_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)^resolved_atISNOTEMPTY&sysparm_avg_fields=business_duration&sysparm_count=true
```

### Step 4: Measure False Positive Rate

Calculate the percentage of incidents closed as false positives or non-incidents.

**Using MCP:**
```
Tool: SN-Query-Table
Parameters:
  table_name: sn_si_incident
  query: closed_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)^close_code=false_positive
  fields: sys_id,number,category,subcategory,assignment_group,closed_at
  limit: 500
```

```
Tool: SN-Query-Table
Parameters:
  table_name: sn_si_incident
  query: closed_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)
  fields: sys_id
  limit: 1
```

**Using REST:**
```
# Total closed incidents
GET /api/now/stats/sn_si_incident?sysparm_query=closed_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)&sysparm_count=true

# False positives
GET /api/now/stats/sn_si_incident?sysparm_query=closed_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)^close_code=false_positive&sysparm_count=true
```

### Step 5: Analyze Analyst Workload Distribution

Measure incident distribution across analysts and assignment groups.

**Using MCP:**
```
Tool: SN-Query-Table
Parameters:
  table_name: sn_si_incident
  query: opened_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)^assigned_toISNOTEMPTY
  fields: assigned_to,assignment_group,priority,state
  limit: 1000
```

**Using REST (Aggregate API):**
```
GET /api/now/stats/sn_si_incident?sysparm_query=opened_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)^assigned_toISNOTEMPTY&sysparm_count=true&sysparm_group_by=assigned_to

GET /api/now/stats/sn_si_incident?sysparm_query=opened_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)&sysparm_count=true&sysparm_group_by=assignment_group
```

### Step 6: Track Incident Category Trends

Identify shifts in attack types over time by comparing category distributions.

**Using MCP:**
```
Tool: SN-Query-Table
Parameters:
  table_name: sn_si_incident
  query: opened_atONLast 90 days@javascript:gs.daysAgoStart(90)@javascript:gs.daysAgoEnd(0)
  fields: sys_id,category,subcategory,priority,opened_at
  limit: 2000
```

**Using REST:**
```
# Current month
GET /api/now/stats/sn_si_incident?sysparm_query=opened_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)&sysparm_count=true&sysparm_group_by=category

# Previous month
GET /api/now/stats/sn_si_incident?sysparm_query=opened_atBETWEENjavascript:gs.daysAgoStart(60)@javascript:gs.daysAgoEnd(30)&sysparm_count=true&sysparm_group_by=category
```

### Step 7: Measure Task Completion Efficiency

Analyze how quickly security incident tasks are completed.

**Using MCP:**
```
Tool: SN-Query-Table
Parameters:
  table_name: sn_si_task
  query: closed_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)
  fields: sys_id,number,short_description,state,priority,assigned_to,opened_at,closed_at,work_duration
  limit: 500
```

**Using REST:**
```
GET /api/now/stats/sn_si_task?sysparm_query=closed_atONLast 30 days@javascript:gs.daysAgoStart(30)@javascript:gs.daysAgoEnd(0)&sysparm_avg_fields=work_duration&sysparm_count=true&sysparm_group_by=priority
```

### Step 8: Compile Metrics Report

Generate a comprehensive metrics summary.

```
=== SECURITY OPERATIONS METRICS REPORT ===
Period: 2026-02-19 to 2026-03-19 (30 days)
Generated: 2026-03-19

VOLUME METRICS:
Total Incidents: 156 (prev period: 142, +9.8%)
  - Critical/P1: 4 (2.6%)
  - High/P2: 18 (11.5%)
  - Medium/P3: 67 (42.9%)
  - Low/P4: 67 (42.9%)

By Category:
  - Phishing: 52 (33.3%) ↑ from 28.2%
  - Malware: 28 (17.9%) ↓ from 22.5%
  - Unauthorized Access: 24 (15.4%) → stable
  - Data Loss: 12 (7.7%) → stable
  - Vulnerability Exploit: 18 (11.5%) ↑ from 8.5%
  - Other: 22 (14.1%)

RESPONSE METRICS:
Mean Time to Detect (MTTD): 4.2 hours (target: <2h, prev: 5.1h)
Mean Time to Respond (MTTR): 18.6 hours (target: <24h, prev: 22.3h)
Mean Time to Contain (MTTC): 2.8 hours (target: <4h, prev: 3.5h)

QUALITY METRICS:
False Positive Rate: 23.1% (target: <20%, prev: 25.6%)
Reopened Incidents: 3 (1.9%)
Escalation Rate: 14.1%

WORKLOAD DISTRIBUTION:
| Analyst | Incidents | Avg Resolution | Utilization |
|---------|-----------|----------------|-------------|
| T. Williams | 32 | 14.2h | 85% |
| K. Chen | 28 | 16.8h | 78% |
| A. Johnson | 31 | 19.1h | 82% |
| M. Davis | 25 | 21.5h | 70% |
| L. Park | 22 | 15.3h | 65% |
| Unassigned | 18 | N/A | - |

KEY OBSERVATIONS:
1. MTTD improved 18% but still above 2-hour target
2. Phishing volume increasing - consider enhanced email filtering
3. False positive rate improving but above 20% threshold
4. Workload imbalance: T. Williams carrying 20% of all incidents
5. 18 unassigned incidents need immediate attention

RECOMMENDATIONS:
1. Tune phishing detection rules to reduce false positives
2. Rebalance workload: redistribute from T. Williams to L. Park
3. Investigate MTTD gap: review SIEM alert correlation rules
4. Staff augmentation may be needed if volume trend continues
```

## Tool Usage

| Tool | Purpose |
|------|---------|
| SN-Query-Table | Retrieve incident and task records for metric calculation |
| SN-Execute-Background-Script | Run server-side scripts for complex metric calculations |
| SN-Add-Work-Notes | Document metrics findings on relevant records |

## Best Practices

- **Establish baselines** before setting targets; use 90 days of historical data minimum
- **Segment metrics by priority** since P1 and P4 incidents have vastly different acceptable response times
- **Track trends over time** rather than focusing on single-period snapshots
- **Automate data collection** using scheduled background scripts or Performance Analytics indicators
- **Exclude outliers** when calculating averages; a single month-long incident can skew MTTR significantly
- **Report false positive rates by source** to identify which detection rules need tuning
- **Align metrics with business outcomes** by connecting MTTD/MTTR to business impact duration
- **Review workload distribution monthly** to prevent analyst burnout and ensure equitable assignment

## Troubleshooting

### MTTD Calculation Returns Zero
**Cause:** No observables with `first_seen` timestamps are linked to incidents, or the timestamp predates the incident.
**Solution:** Verify that threat intelligence integrations are populating `first_seen` on observables. If `first_seen` is after `opened_at`, MTTD may be negative; use the incident `opened_at` as the detection time in those cases.

### Aggregate API Returns Unexpected Counts
**Cause:** Encoded queries may not match the expected date ranges, or display values differ from stored values.
**Solution:** Test the query in the ServiceNow UI list filter first. Ensure date formats match the instance timezone.

### Workload Metrics Show All Incidents as Unassigned
**Cause:** The `assigned_to` field may be cleared when incidents are resolved or closed.
**Solution:** Use `sys_audit` to find the last assigned analyst before closure, or query the `assigned_to` field with `sysparm_display_value=true` to get display names.

### Metrics Differ from Performance Analytics
**Cause:** PA indicators may use different data collection schedules, filters, or calculation methods.
**Solution:** Align your query filters with the PA indicator definitions. Check PA data collection job schedules and ensure they have run recently.

## Examples

**Example 1: Monthly SOC Performance Report**
1. Calculate 30-day incident volume: 156 total across all categories
2. Compute MTTD (4.2h), MTTR (18.6h), and MTTC (2.8h)
3. Determine false positive rate: 36 false positives out of 156 total (23.1%)
4. Analyze workload across 5 analysts and identify imbalance
5. Compare all metrics against previous period and targets
6. Generate report with trend arrows and recommendations

**Example 2: Quarterly Executive Dashboard**
1. Pull 90-day incident data segmented by month for trend charts
2. Calculate month-over-month MTTD improvement: 6.3h → 5.1h → 4.2h
3. Identify top 3 categories driving volume increase
4. Benchmark MTTR against industry average (24h for mid-size organizations)
5. Project staffing needs based on volume trend (+9.8%/month)
6. Present findings with recommended budget for additional analyst headcount

## Related Skills

- `secops/correlation-insights` - Measure correlation effectiveness as a detection metric
- `secops/incident-summarization` - Include metrics context in incident summaries
- `secops/post-incident-analysis` - Use PIR data to improve detection metrics
- `secops/shift-handover` - Include shift-level metrics in handover reports
- `reporting/trend-analysis` - General ServiceNow trend analysis techniques

