Real-time alerts for Cisco IOS/IOS-XE switches. This example focuses on STP BPDU Guard violations, but the same pattern applies to any log source.
This is a reference implementation. The mechanisms shown here (query filtering, field extraction, throttling, templating) work the same way for any log type: Linux syslogs, application logs, firewall events, etc.
Cisco Switch (syslog)
↓
VictoriaLogs
↓
Valerter (streams & alerts)
↓
Mattermost / Email
A BPDU Guard violation stored in VictoriaLogs:
{
"_time": "2026-01-15T16:10:00.000Z",
"_msg": "2290: CORE-SW-01: Jan 15 16:10:00.000: %SPANTREE-2-BLOCK_BPDUGUARD: Received BPDU on port Gi1/0/24 with BPDU Guard enabled. Disabling port.",
"hostname": "192.168.1.1",
"site": "DATACENTER",
"severity": "2",
"level": "critical",
"group": "SW"
}
Each step below is a reusable building block. Adapt them to your own logs.
query: 'group:"SW" "SPANTREE-2-BLOCK_BPDUGUARD"'
The query uses LogsQL syntax to filter logs in real-time:
group:"SW" — matches only logs with this field value"SPANTREE-2-BLOCK_BPDUGUARD" — full-text search in _msgAdapt it: Change the filter to match your logs. Examples:
app:"nginx" "502 Bad Gateway" — nginx errorslevel:"error" service:"payment" — payment service errors_msg:~"failed.*authentication" — regex match on messageparser:
json:
fields: ["hostname", "site", "severity", "_msg", "level"]
regex: '^\d+: (?P<switch_name>[A-Z0-9-]+):'
Two extraction methods work together:
| Method | Purpose | Result |
|---|---|---|
| JSON | Extract top-level fields from the log | hostname, site, severity become variables |
| Regex | Extract data embedded in _msg |
Named group (?P<switch_name>...) creates switch_name variable |
Adapt it:
(?P<name>pattern)_msgthrottle:
key: ""
count: 3
window: 5m
Throttling groups alerts and limits notifications:
| Setting | Effect |
|---|---|
key |
Groups alerts by this value (template syntax) |
count |
Maximum alerts per group per window |
window |
Time window before counter resets |
With the config above: max 3 alerts per switch per 5 minutes.
Adapt it:
key: "" — throttle per hostkey: "" — throttle per error typekey: "-" — throttle per host+service combokey entirely — global throttle across all matching logsnotify:
template: "SPANTREE-2-BLOCK_BPDUGUARD"
destinations:
- mattermost-infra
- email-infra
Each rule must specify:
template — which template to use for formattingdestinations — list of notifiers to send to (defined in notifiers section)Templates use Jinja2 syntax with all extracted variables:
templates:
SPANTREE-2-BLOCK_BPDUGUARD:
title: "🚨 BPDU Guard | ()"
body: |
**Switch:** `` | **IP:** `` | **Site:** `Jekyll::Drops::SiteDrop`
```
```
body_html: |
<!-- HTML version for email -->
Available variables:
_msg — original log messagerule_name — name of the triggered rulelog_timestamp_formatted — human-readable timestampMattermost:
Email:
Just change the query to monitor different events:
| Alert Type | Query |
|---|---|
| Hardware warnings | group:"SW" "PLATFORM-4-ELEMENT_WARNING" |
| SFP threshold | group:"SW" "SFF8472-3-THRESHOLD_VIOLATION" |
| VLAN mismatch | group:"SW" "CDP-4-NATIVE_VLAN_MISMATCH" |
| Stack link change | group:"SW" "STACKMGR-4-STACK_LINK_CHANGE" |
| Switch restart | group:"SW" "SYS-5-RESTART" |
| All critical (0-2) | group:"SW" severity:~"[0-2]" |
See config.yaml for the complete working configuration.