Tutorial: Monitoring & Observability – Watch Your Tests in Real-Time
Collect metrics, stream events, and monitor security tests across logs, dashboards, and terminal UIs.
What You’ll Learn
- ✅ Enable and stream SSE (Server-Sent Events) for real-time updates
- ✅ Export Prometheus metrics and integrate with Grafana
- ✅ Tail logs and analyze attack events in real-time
- ✅ Use the terminal UI (blessed) to monitor from the command line
- ✅ Create custom dashboards to track security metrics
- ✅ Set up alerts when vulnerabilities are found
- ✅ Analyze metrics for performance and failure patterns
Prerequisites
- Apparatus running — Server at
http://localhost:8090 - curl installed — For API commands
- Terminal access — For CLI monitoring
- Browser — For dashboard viewing
- Optional: Grafana — For advanced dashboarding (we’ll show setup)
- Optional: jq — For JSON parsing in terminal
Time Estimate
~35 minutes (SSE setup → metrics export → dashboard → terminal UI)
What You’ll Build
By the end, you’ll have:
- Real-time event streaming from Apparatus
- Prometheus metrics exported and queryable
- Grafana dashboard showing attack trends
- Terminal UI monitoring without browser
- Custom alerts when security events occur
Section 1: Understanding Monitoring in Apparatus
Three Pillars of Observability
| Pillar | What It Shows | Tool |
|---|---|---|
| Logs | What happened (events) | Terminal, dashboards |
| Metrics | How much (counts, rates, timing) | Prometheus, Grafana |
| Traces | How did it happen (flow) | SSE events |
Apparatus Monitoring Architecture
Metrics Apparatus Tracks
Request Metrics:
- Total requests
- Requests per second (RPS)
- Response time distribution
- Error rate
- Status code breakdown (2xx, 4xx, 5xx)
Security Metrics:
- Vulnerabilities found
- Requests blocked by WAF
- IPs trapped in tarpit
- Rate-limited requests
- Attack attempts by tool
Performance Metrics:
- Event loop lag
- CPU usage
- Memory consumption
- GC pause duration
Section 2: SSE (Server-Sent Events) Streaming
What SSE Does
SSE pushes events from server to client in real-time. Instead of polling (“Is there new data?”), the server automatically sends data when something happens.
Use cases:
- Dashboard updates as attacks happen
- Alerts when vulnerabilities found
- Real-time traffic monitoring
- Live scenario execution
Connect to SSE Stream
Step 1: Start the Stream
curl -N http://localhost:8090/sse
What it does:
-Ndisables buffering (immediate output)- Stream stays open, receiving events indefinitely
- Press
Ctrl+Cto stop
Expected output (starts immediately):
data: {"type":"health","status":"healthy","timestamp":"2026-02-21T20:30:00Z"}
data: {"type":"request","method":"GET","path":"/api/users","status":200,"duration":45}
data: {"type":"defense","action":"blocked","pattern":"xss","ip":"192.168.1.42"}
data: {"type":"finding","vulnerability":"reflected_xss","severity":"high","path":"/search"}
Each line is a JSON event. Events keep coming as actions happen.
Step 2: Filter Events by Type
You probably don’t want ALL events. Filter for specific types:
# Only vulnerability findings
curl -N http://localhost:8090/sse | grep '"type":"finding"'
# Only requests that were blocked
curl -N http://localhost:8090/sse | grep '"action":"blocked"'
# Only security events (defense, findings)
curl -N http://localhost:8090/sse | grep -E '"type":"(finding|defense)"'
Step 3: Parse and Pretty-Print Events
Use jq to parse JSON:
# Pretty-print all events
curl -N http://localhost:8090/sse | sed 's/^data: //' | jq .
# Show only vulnerabilities with severity
curl -N http://localhost:8090/sse | sed 's/^data: //' | jq 'select(.type=="finding") | {severity, vulnerability, path}'
# Count events by type
curl -N http://localhost:8090/sse | sed 's/^data: //' | jq -s 'group_by(.type) | map({type: .[0].type, count: length})'
Exercise: Monitor an Attack Via SSE
Part 1: Start SSE stream in one terminal
curl -N http://localhost:8090/sse | sed 's/^data: //' | jq '.'
Part 2: Launch attack in another terminal
curl -X POST http://localhost:8090/api/redteam/autopilot/start \
-H "Content-Type: application/json" \
-d '{
"target": "http://vuln-web:3000",
"config": {
"interval": 2000,
"maxIterations": 5,
"allowedTools": ["redteam.xss", "redteam.sqli"]
}
}'
Expected: SSE terminal shows real-time attack events as they happen
Checkpoint
- Connected to SSE stream successfully (got data flowing)
- Saw multiple event types (request, finding, defense)
- Filtered events for specific types
- Parsed JSON with jq
- Monitored a real attack via SSE
Section 3: Prometheus Metrics
What Prometheus Does
Prometheus collects metrics and stores them in a time-series database. Then tools like Grafana can query and visualize them.
Step 1: Access Prometheus Metrics Endpoint
curl http://localhost:8090/metrics
Output (text format):
# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",status="200"} 1234
http_requests_total{method="GET",status="403"} 56
http_requests_total{method="POST",status="200"} 89
# HELP http_request_duration_ms HTTP request duration
# TYPE http_request_duration_ms histogram
http_request_duration_ms_bucket{le="10",path="/health"} 50
http_request_duration_ms_bucket{le="50",path="/health"} 120
http_request_duration_ms_bucket{le="100",path="/api/users"} 45
Format explained:
# HELP— Description of the metric# TYPE— Metric type (counter, gauge, histogram)- Lines with values — Actual data points
Step 2: Query Metrics
Sample queries:
# Get request rate (requests per minute)
curl -s http://localhost:8090/metrics | grep 'http_requests_total'
# Get errors only
curl -s http://localhost:8090/metrics | grep 'status="[45][0-9][0-9]"'
# Get average response time
curl -s http://localhost:8090/metrics | grep 'http_request_duration_ms'
Step 3: Set Up Prometheus Collection
Create a prometheus.yml config file:
global:
scrape_interval: 15s # Collect metrics every 15 seconds
scrape_configs:
- job_name: 'apparatus'
static_configs:
- targets: ['localhost:8090']
metrics_path: '/metrics'
Start Prometheus:
# Using Docker
docker run -p 9090:9090 -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus
# Or download binary from https://prometheus.io/download/
./prometheus --config.file=prometheus.yml
Access Prometheus UI:
http://localhost:9090
Step 4: Query Metrics in Prometheus
In the Prometheus UI:
- Go to “Graph” tab
- Enter a query, e.g.:
rate(http_requests_total[5m]) - Click “Execute”
- See request rate over time
Useful queries:
| Query | What It Shows |
|---|---|
http_requests_total |
Total requests since startup |
rate(http_requests_total[5m]) |
Requests per second (5-min average) |
http_request_duration_ms |
Response time histogram |
http_errors_total |
Errors only |
Checkpoint
- Accessed
/metricsendpoint - Saw Prometheus-format metrics
- Parsed metrics with grep
- (Optional) Set up Prometheus and queried metrics
Section 4: Grafana Dashboards
What Grafana Does
Grafana visualizes Prometheus metrics in dashboards with graphs, tables, and alerts.
Setup Grafana
Using Docker:
docker run -d -p 3000:3000 \
-e "GF_SECURITY_ADMIN_PASSWORD=admin" \
grafana/grafana
# Access at http://localhost:3000
# Login: admin / admin
Create a Dashboard
Step 1: Add Prometheus Data Source
- Go to http://localhost:3000
- Settings (gear icon) → Data Sources
- Click “Add data source”
- Select “Prometheus”
- URL:
http://localhost:8090(if Prometheus is on Apparatus) ORhttp://prometheus:9090(if using Docker) - Click “Save & Test”
Step 2: Create a Dashboard
- Click “+” → Dashboard
- Click “Add panel”
- Select “Graph”
- Configure query:
- Data source: Prometheus
- Query:
rate(http_requests_total[5m]) - Legend: ` `
- Title: “Request Rate”
- Click “Apply”
Step 3: Add More Panels
Repeat for each metric:
Panel 2: Error Rate
Query: rate(http_errors_total[5m])
Title: "Error Rate"
Panel 3: Response Time
Query: http_request_duration_ms
Title: "Response Time"
Panel 4: Vulnerabilities Found
Query: security_vulnerabilities_found_total
Title: "Vulnerabilities Discovered"
View Real-Time Dashboard
- Run an autopilot campaign or scenario
- Watch Grafana dashboard update in real-time
- See requests, errors, and vulnerabilities as they happen
Checkpoint
- (Optional) Installed and accessed Grafana
- Created Prometheus data source
- Created at least one panel/graph
- Configured metrics queries
Section 5: Terminal UI Monitoring
The blessed Terminal UI
Apparatus includes a terminal UI built with blessed. Monitor everything from the command line!
Start the Terminal UI
pnpm tui
OR from the Docker container:
docker exec apparatus-server npm run tui
What you see:
Terminal UI Features
18+ Widget Types Available:
- System status (health, uptime, memory)
- Request metrics (RPS, latency, error rate)
- Event feeds (real-time request log)
- Vulnerability counter
- Traffic graphs
- Attack history
- Defense statistics
- Tarpit status
Keyboard Controls
| Key | Action |
|---|---|
q |
Quit |
h |
Help |
1-9 |
Switch tabs/views |
Space |
Pause/resume updates |
c |
Clear selected widget |
r |
Refresh all |
Exercise: Monitor with Terminal UI
Part 1: Start TUI
pnpm tui
Part 2: Launch attack in another terminal
curl -X POST http://localhost:8090/api/redteam/autopilot/start \
-H "Content-Type: application/json" \
-d '{
"target": "http://vuln-web:3000",
"config": {
"interval": 1000,
"maxIterations": 10,
"allowedTools": ["redteam.xss", "redteam.sqli"]
}
}'
Watch the TUI:
- RPS increases (requests per second)
- Events stream in real-time
- Vulnerability counter increments
- Graphs update live
Checkpoint
- Started terminal UI (
pnpm tui) - Saw multiple widgets/panels
- Understood keyboard controls
- Monitored a real attack in TUI
Section 6: Log Aggregation (Advanced)
Sending Logs to External Systems
Send to Splunk
Splunk collects and indexes logs. Configure Apparatus to send logs:
# Configure Splunk HEC (HTTP Event Collector)
curl -X POST http://localhost:8090/_sensor/config/integrations \
-H "Content-Type: application/json" \
-d '{
"splunk_hec_url": "https://splunk.example.com:8088",
"splunk_hec_token": "your-token-here"
}'
Apparatus will now send logs to Splunk. Query them:
index=apparatus vulnerability=found
| stats count by severity
Send to ELK Stack (Elasticsearch + Logstash + Kibana)
Elasticsearch stores logs, Kibana visualizes:
# Docker Compose stack
docker-compose -f docker-compose.elk.yml up
Configure Apparatus to send to Logstash:
curl -X POST http://localhost:8090/_sensor/config/integrations \
-H "Content-Type: application/json" \
-d '{
"logstash_host": "logstash",
"logstash_port": 5000
}'
Section 7: Creating Alerts
Alert When Vulnerabilities Found
Create an alert using Prometheus AlertManager:
groups:
- name: apparatus
rules:
- alert: VulnerabilityFound
expr: security_vulnerabilities_found_total > 0
for: 1m
annotations:
summary: "Vulnerability discovered in security test"
description: " vulnerabilities found"
- alert: HighErrorRate
expr: rate(http_errors_total[5m]) > 0.05
for: 5m
annotations:
summary: "Error rate high (>5%)"
Receive alerts:
- Slack — Post to #security-alerts channel
- Email — Send to [email protected]
- PagerDuty — Create incident for on-call engineer
- Webhook — POST to your API
Section 8: Real-Time Dashboard Queries
Common Monitoring Questions
“How many vulnerabilities were found today?”
curl -s http://localhost:8090/metrics | grep 'security_vulnerabilities' | tail -1
“What’s the error rate in the last 5 minutes?”
# Using Prometheus
promql: rate(http_errors_total[5m]) / rate(http_requests_total[5m])
“Which endpoints are slowest?”
curl -s http://localhost:8090/metrics | grep 'http_request_duration' | sort -k2 -rn | head -10
“How many requests blocked by WAF?”
curl -s http://localhost:8090/metrics | grep 'waf_requests_blocked' | awk '{print $2}' | paste -sd+ | bc
Section 9: Troubleshooting Monitoring
Metrics Endpoint Returns Nothing
Symptom: curl http://localhost:8090/metrics returns empty
Cause: Metrics collection disabled or no requests have been made yet
Solution:
- Send a request to Apparatus to generate metrics
- Check if metrics collection is enabled:
curl http://localhost:8090/_sensor/config/metrics - Enable if disabled
SSE Stream Disconnects
Symptom: SSE stream stops receiving events after a few minutes
Cause: Network timeout or server restart
Solution:
# Reconnect automatically
while true; do
curl -N http://localhost:8090/sse | process_events
sleep 5
done
Grafana Can’t Connect to Prometheus
Symptom: “Unable to connect to Prometheus” error in Grafana
Cause: Wrong URL or Prometheus not running
Solution:
- Verify Prometheus is running:
curl http://localhost:9090/api/v1/query?query=up - Check Grafana data source URL (should be
http://prometheus:9090in Docker) - Restart both services
Summary
You’ve learned how to:
- ✅ Stream real-time events via SSE
- ✅ Export Prometheus metrics
- ✅ Set up Grafana dashboards
- ✅ Monitor from terminal UI
- ✅ Query and analyze metrics
- ✅ Create custom alerts
- ✅ Integrate with Splunk/ELK
Next Steps
- Set up monitoring for your own security tests
- Create custom dashboards for your metrics
- Configure alerts for critical events
- Integrate with your SIEM (Splunk, ELK)
- Build reports from historical metrics
Made with ❤️ for operators and analysts