Skip to content

Monitoring

Yagra actively monitors network devices and servers over ICMP, SNMP, and HTTP(S) — watching liveness, performance, and thresholds across tens of thousands of nodes. This page describes what gets collected, how a node resolves to a set of checks, and how the polling engine behaves. For what happens once a check goes bad, see Alerting.

Everything Yagra watches is a node, but not every node is a router. A node’s kind follows from how it is configured — it is derived from the monitoring attached to the node, not a label you maintain separately:

Kind What it is Checks it gets
Device A network device or server with an IP address ICMP liveness always, plus SNMP collection when a credential and a collection set resolve
URL An HTTP(S) endpoint monitor One HTTP probe — no ICMP (the target may be unpingable behind a CDN) and no SNMP
DNS A name-resolution monitor One DNS probe — a name has no address of its own
Meraki A device imported from a Cisco Meraki organization Collected through the Meraki Dashboard API at the organization level, so it emits no per-node poll job

When a node matches more than one shape, the more specific kind wins, in the fixed order Meraki → URL → DNS → Device. All four kinds live in the same inventory tree, share the same dashboards, and feed the same alerting pipeline.

The kind is visible where you work. A short URL / DNS / Meraki badge sits after the name in the inventory tree and beside the title on the node’s page; ordinary devices are unmarked, so a badge means “read this one differently”. The node’s page then shows only the tabs its kind can fill — a URL or DNS monitor has no Interfaces, Neighbors, or Flow tab, because it is never SNMP-walked and is never a flow exporter — and its Overview lists only facts that kind can hold, so a DNS monitor shows its resolver rather than four blank rows where a maker and model would be. The API reports the same value: kind on GET /api/v1/nodes and on the MCP node tools.

Every device node gets ICMP liveness monitoring — it is always on and requires no credential. The probe records reachability and round-trip time (icmp_rtt_ms), which is graphable on the node detail and usable in threshold rules (for example, RTT above 100 ms). A device that stops answering transitions to the unreachable state and raises a liveness alert, subject to the hysteresis and dependency-suppression logic described under Alerting.

ICMP uses raw sockets, so the poller container needs the NET_RAW capability — the bundled Compose files grant it to the poller (and only the poller) already.

SNMP is where the depth of device monitoring comes from. Yagra speaks:

  • SNMP v2c — community-based.
  • SNMP v3 (USM) — authentication and privacy.

Both versions collect scalar metrics (CPU, memory, sessions, and so on) and walk tables, including multi-index tables. Per-interface metrics come from interface-table walks using GETBULK, on v2c and v3 nodes alike, so per-interface counters are collected even on devices that only permit v3. A node’s table walks are folded into a single SNMP session per poll, which keeps the cost of a many-port switch to one conversation rather than one per table.

On the node detail, per-interface throughput and status appear as sparklines and time-series charts with a shared range control (1 hour to 7 days, plus custom), with configured-bandwidth reference lines drawn on the interface charts.

Yagra stores interface and error counters raw — it never computes a rate on the poller by subtracting the previous sample. Rates and utilization are derived at query and evaluation time by the time-series store, which detects counter wrap and counter resets automatically. This has two practical consequences:

  • Pollers are stateless: no previous-value bookkeeping, no wrong rate after a poller restart or failover.
  • A counter wrap (32-bit) or a device reboot never produces a phantom traffic spike, because the wrap/reset handling lives in the store’s rate functions, not in a hand-rolled subtraction.

It also means threshold rules apply to gauges, not raw counters — see Thresholds below.

SNMP communities and v3 credentials are stored encrypted at rest and are never logged, returned by the API, or used as metric labels. A node without a bound credential can fall back to a deployment-wide v2c community via YAGRA_SNMP_COMMUNITY — see the configuration reference.

A URL node monitors an HTTP(S) endpoint the way you’d check it by hand, on a schedule:

  • Liveness and status — the probe succeeds when the endpoint answers with the expected HTTP status. The expectation is configurable: any 2xx, an explicit list of codes, or a range.
  • Response timehttp_response_time_ms records how long the endpoint took to answer, so “it is up” and “it is slow” are separate questions. It measures time to the response headers, and records nothing at all when the endpoint did not answer, so a timeout does not appear as a flat slow-response line for the whole outage. No default threshold is seeded: response latency varies too much between environments for one to be right.
  • A keyword in the response body — a monitor can require that the body contains a keyword, or that it does not. This is the case availability monitoring structurally cannot see: an endpoint answering 200 while its body says the service is broken. Matching is plain, case-sensitive substring matching, not a regular expression, and a body larger than the read budget reports “not satisfied” rather than risking a false healthy.
  • Numbers out of a JSON body — up to 8 values per monitor, each recorded under a metric name you choose: a queue depth, a replication lag, a worker count. The path is dot-separated and names exactly one value (data.queue.depth). A value that is not a number records nothing for that poll rather than a zero, because a zero is indistinguishable from the value genuinely being zero.
  • TLS certificate expiry — certificate expiry is tracked for HTTPS targets, so a certificate runs down on a chart instead of expiring as a surprise.
  • TLS verification is on by default. Disabling it is an explicit, per-monitor opt-in.

The probe is hardened against SSRF: it resolves and connects only through a filtered resolver, on the initial target and on every redirect hop, refusing loopback, link-local, and cloud-metadata destinations (including DNS-rebinding tricks). Private and internal ranges stay allowed — an NMS legitimately monitors them.

A URL monitor’s configuration is fully editable after creation. The node’s URL health card has an overflow (⋮) menu with Edit and Remove monitoring; the editor covers every field, including the expected status. Removing the monitoring leaves the node in the inventory with its recorded history intact — it simply stops probing. Changing a monitor requires the same permission as any other monitoring change (Admin).

A DNS node monitors a name the way a URL node monitors an endpoint. Bind a node to the built-in DNS name resolution profile and Yagra records:

  • whether the name resolves, and how long resolution takes;
  • the dig-like recursive CNAME chain the name resolves through.

The chain history appends only when the chain actually changes — TTL countdown and round-robin reordering don’t count as a change — so the history reads as a change log, not noise. Numeric summaries are graphable and alertable: dns_up, dns_resolve_ms, dns_chain_length, and dns_answer_count. A default dns_up threshold is seeded, so a new DNS monitor alerts out of the box.

When resolution fails, the reason is shown as a readable sentence (for example, “No such name (NXDOMAIN)”) in both English and Japanese, rather than an internal error token.

Like URL monitors, a DNS monitor is editable and removable after creation from the node’s DNS health card — resolver, record type, and the rest — with removal preserving the node and its history.

Yagra monitors Cisco Meraki estates over the read-only Dashboard API. Add an organization under Settings ▸ Integrations ▸ Cisco Meraki with a read-only API key; an import wizard enumerates the organization’s networks and devices and lets you choose what to monitor.

  • Imported devices become ordinary nodes — auto-placed under an Organization → Network group tree, carrying a Meraki badge in the inventory.
  • Collection happens per organization: one paged, org-wide API call covers many devices, so a large estate never trips the organization’s API rate limit.
  • Collected metrics include device availability, WAN uplink loss / latency / status, client count, and traffic usage, surfaced on a Cisco Meraki card on the node detail.
  • Per-organization controls let you pause and resume collection, tune per-tier polling cadence and the request-rate budget, and edit which networks are in scope. A global kill switch halts all Meraki collection instantly.

The integration is read-only by design: it issues HTTP GET only, every request is restricted to allow-listed Meraki API hosts, and the API key is encrypted at rest and never returned or logged.

In a distributed deployment, Meraki cloud-poll jobs are routed to the poller pool named by YAGRA_MERAKI_POOL (default default) — useful when only some sites have internet egress. See Distributed polling.

What SNMP data a device yields is decided declaratively, not per node:

  • Device profiles form a role × network-OS taxonomy (a core switch is not a firewall is not a Linux host).
  • Each profile carries editable collection templates, which draw on a curated, searchable MIB/OID catalog.
  • A node bound to a profile resolves — through its templates and its credential — to a concrete collection set: the scalars and tables actually polled on that device.

Built-in profiles and templates cover common vendors out of the box — Cisco, Huawei (including USG firewall sessions and memory), Meraki MX/MS, and A10 — plus the standard host and interface MIBs. All of it is editable and searchable, so extending coverage to a new device family means adding catalog entries and a template, not writing code.

Everything a node collects is visible, not just what the UI anticipated. A node’s Collection tab lists every metric that has arrived for it and charts any of them, which matters most for the coverage you added yourself — a vendor table column collects successfully but no screen was written to know its name. Each entry states whether it is configured and flowing, configured with nothing arriving yet, or arriving with no collection item behind it. That last case is normal rather than a fault: reachability, the URL and DNS monitors, the neighbour count, and values extracted from a monitored JSON body all come from checks rather than from a collection set. A counter can be charted as a per-second rate — its stored value is an odometer reading, and charting that draws a rising line that looks like traffic and is not.

You don’t have to add nodes one at a time:

  • Discovery sweeps IP ranges and address lists, using credentials chosen from the stored credential picker.
  • A Credential Finder tries stored credentials by reference against a discovered device to find one that answers — rate-limited per device, with the attempted values never logged.
  • Classification rules match on sysObjectID / sysDescr and apply the matching device profile automatically, so a discovered device lands with the right collection set attached.
  • Results land in an import grid, so you review and choose what enters the inventory rather than having a sweep add nodes behind your back.

Classification rules are data, not code — they live next to profiles and are editable in the same place.

The Network map draws the connectivity Yagra derived from what the devices themselves report — nobody types a link. Each edge carries the evidence behind it, and the map labels and legends them:

  • CDP / LLDP adjacency, matched to a monitored node through the peer’s management address.
  • A shared IP subnet — two nodes with an interface address in the same prefix are adjacent as a matter of fact.
  • OSPF neighbours, BGP peers, and connected routes, which is how the map sees links that share no subnet: a point-to-point /32 (a PPPoE dialer, a tunnel endpoint), an unnumbered OSPF link, or a peering across a segment whose addressing has not been collected.

A link seen more than one way is still one link, carrying all of its evidence. Redundant paths are kept rather than collapsed — a server reached through two routers shows both links.

The walks that feed it run hourly by default and each has its own switch at Settings ▸ System settings ▸ Discovery walks: neighbours (CDP/LLDP), interface addresses, routing adjacency (OSPF/BGP), and the ARP cache. The tables they read are sized by the device’s own peering mesh, not by the network — the routing table is never walked. A router carrying a full table has hundreds of thousands of routes, so Yagra asks about one destination at a time, only of a device that holds a host address of its own, capped at 64 destinations. On a fleet of ordinary devices that issues no route queries at all.

Two deliberate behaviours worth knowing. A down session still draws its link — a BGP session in active is a link with a fault, and that is usually the thing being investigated. And an iBGP session between loopbacks does not become a link: a peer counts as adjacent only when it sits on a network the reporting device terminates, so a route reflector does not acquire a false star to every client it peers with.

Known limits, stated rather than half-answered: BGP4-MIB is IPv4-only, so IPv6 BGP peers are out of scope; OSPF collection is OSPFv2; virtual links are not read; and a segment with more than two members where no member can be identified as routing for the others produces no links rather than a guessed one, and is counted in the map’s summary instead.

The same graph is what dependency suppression can be switched over to.

Turn on the ARP / IPv6 neighbor cache walk and every monitored router reports the hosts it has actually spoken to. Anything not already in the inventory appears under Nodes ▸ Discovery ▸ Seen on the network — the address, its MAC, and which device saw it on which port — with a Monitor button that turns it into a node through the same import path a subnet scan uses. No scan required; it is a by-product of the polling you already do.

Discovered endpoints are deliberately not drawn on the network map: an unmonitored host has no state to show, and a few thousand stateless boxes would bury the nodes that do. Import one and the ordinary derivation picks it up from there.

Thresholds are per-metric rules that turn a measurement into a warning or critical state: a bound, a direction (above / below), and dwell behavior evaluated by the alert engine (see Alerting).

Two rules of the model are worth knowing before you write rules:

  • Thresholds apply to gauge metrics only. A threshold on a counter metric (if_hc_in_octets, error or discard counters — anything the collection catalog declares a counter) would compare a raw monotonic total against the bound: an above rule latches permanently once the counter passes it, and a below rule fires a phantom alert at every reboot’s counter reset. Yagra therefore rejects creating one — POST /api/v1/thresholds on a counter metric answers 400 counter_metric — and reads counter samples as OK, which also drains any alert an older rule had latched, through the normal recovery path. Rate-style alerting on counters is a query-time concern: set thresholds on gauges.
  • Reading the threshold list requires the manage-configuration permission (Admin), not just view access — a threshold set describes when and whom Yagra will page, so it stays closed even on a public dashboard. Anonymous requests answer 401.

For automation, GET /api/v1/thresholds returns an envelope — { "items": [...], "total": <n>, "truncated": <bool> } — capped at 500 rules per request; ?limit= can narrow that, never widen it, and truncated tells you when the cap bit.

Some node kinds seed a sensible default rule on creation (for example, dns_up for DNS monitors), so a fresh monitor alerts without configuration.

The polling engine is built to be predictable at fleet scale:

  • Interval — the default poll interval is 30 seconds, clamped to 10–3600 s. The YAGRA_POLL_INTERVAL_SECS environment variable seeds the value on first boot only; after that the setting stored in the database (editable in the WebUI) is authoritative. Per-device-profile intervals can override the global default.
  • Jitter — polling intervals are jittered so tens of thousands of nodes don’t all fire on the same tick and stampede the network (or the pollers).
  • One probe in flight per device — a slow device never accumulates a pile-up of concurrent probes against itself; the next probe waits for the last. (DNS monitors are the deliberate exception: they share resolver targets by design, so they are governed by the global bound instead of the per-target one.)
  • Global concurrency boundYAGRA_MAX_CONCURRENT_POLLS (default 64) caps a poller’s total concurrent probes, alongside per-device rate limiting and backpressure.

An immediate, out-of-schedule poll of a single node can also be triggered on demand — for example, by an AI or automation client through Yagra’s MCP tool surface — as a configuration-level (Admin) action, without waiting for the next tick.

Pollers are stateless and horizontally scalable; how work is spread across pools and sites — and how a remote poller rides out a network partition — is covered in Distributed polling.

  • Alerting — what happens when a check breaches: hysteresis, flapping detection, dependency suppression, and notification channels.
  • Distributed polling — poller pools, location affinity, and store-and-forward.
  • Configuration reference — the environment variables named on this page, with defaults and clamps.