@cryptotaxi247 / netdata-1 / commits / b509bf311

docs: add SNMP profile format doc (#21201)

Ilya Mashchenko committed Oct 26, 2025 at 18:17 UTC b509bf311fe38de1883898adf61dc7e20b4f5b2f
1 file changed +1557
src/go/plugin/go.d/collector/snmp/profile-format.md new
+1557
@@ -0,0 +1,1557 @@
1 +# Profile Format
2 +
3 +## Overview
4 +
5 +An **SNMP profile** defines _how a specific class of devices is monitored through SNMP_.
6 +
7 +:::info
8 +
9 +SNMP profiles are reusable and declarative — you never need to modify the collector source code to support new devices.
10 +
11 +:::
12 +
13 +It tells the Netdata SNMP collector:
14 +
15 +- which **OIDs** to query
16 +- how to **interpret** the returned values
17 +- how to **transform** them into **metrics**, **dimensions**, **tags**, and **metadata**
18 +
19 +Profiles make it possible to describe _entire device families_ (switches, routers, UPSes, firewalls, printers, etc.) declaratively — so you don’t need to hard-code logic in Go or manually define metrics for each device.
20 +
21 +Each profile is a single YAML file that can be reused, extended, and combined.
22 +
23 +### How Profiles Work
24 +
25 +When Netdata connects to an SNMP device, the collector:
26 +
27 +1. Reads the device’s **sysObjectID** and **sysDescr**.
28 +2. Evaluates all available profiles.
29 +3. Applies every profile whose [selector](#1-selector) matches.
30 +4. Uses the combined configuration to:
31 + - Collect [scalar metrics](#scalar-metrics-single-values) (single values like uptime or temperature).
32 + - Collect [table metrics](#table-metrics-multiple-rows) (multi-row values like per-interface traffic).
33 + - Build [virtual metrics](#virtual-metrics) (derived totals, fallbacks, or aggregates).
34 + - Gather [metadata](#3-metadata) and [tags](#5-metric_tags) for labeling and grouping.
35 +
36 +**Profile Lifecycle**
37 +
38 +```text
39 +┌──────────────────────┐
40 +│ SNMP Device │ → provides sysObjectID/sysDescr
41 +└──────────┬───────────┘
42 + ↓
43 +┌──────────────────────┐
44 +│ selector │ → matches device profile
45 +├──────────────────────┤
46 +│ extends │ → inherits base profiles
47 +├──────────────────────┤
48 +│ metadata │ → device info (vendor, model, etc.)
49 +├──────────────────────┤
50 +│ metrics │ → OIDs to collect
51 +├──────────────────────┤
52 +│ metric_tags │ → dynamic tags for all metrics
53 +├──────────────────────┤
54 +│ static_tags │ → fixed tags for all metrics
55 +├──────────────────────┤
56 +│ virtual_metrics │ → calculated or aggregated metrics
57 +└──────────┬───────────┘
58 + ↓
59 +┌──────────────────────┐
60 +│ Netdata charts & UI │ → visualized in dashboard
61 +└──────────────────────┘
62 +```
63 +
64 +### Example: Complete SNMP Profile
65 +
66 +```yaml
67 +# example-device.yaml
68 +
69 +# selects which devices this profile applies to.
70 +selector:
71 + - sysobjectid:
72 + include: ["1.3.6.1.4.1.9.*"] # Cisco devices
73 + sysdescr:
74 + include: ["IOS"]
75 +
76 +# imports common base metrics
77 +extends:
78 + - _system-base.yaml
79 + - _std-if-mib.yaml
80 +
81 +# defines device-level labels (virtual node)
82 +metadata:
83 + device:
84 + fields:
85 + vendor:
86 + value: "Cisco"
87 + model:
88 + symbol:
89 + OID: 1.3.6.1.2.1.47.1.1.1.1.2.1
90 + name: entPhysicalModelName
91 +
92 +# specifies which OIDs to collect
93 +metrics:
94 + - MIB: IF-MIB
95 + table:
96 + OID: 1.3.6.1.2.1.2.2
97 + name: ifTable
98 + symbols:
99 + - OID: 1.3.6.1.2.1.2.2.1.10
100 + name: ifInOctets
101 + chart_meta:
102 + description: Interface inbound traffic
103 + family: 'Network/Interface/Traffic/In'
104 + unit: "bit/s"
105 + scale_factor: 8
106 + metric_tags:
107 + - tag: interface
108 + symbol:
109 + OID: 1.3.6.1.2.1.31.1.1.1.1
110 + name: ifName
111 +
112 +# add dynamic tags to all metrics
113 +metric_tags:
114 + - tag: fs_sys_version
115 + symbol:
116 + OID: 1.3.6.1.4.1.9.2.1.73.0
117 + name: fsSysVersion
118 +
119 +# add fixed tags to all metrics
120 +static_tags:
121 + - tag: region
122 + value: "us-east-1"
123 + - tag: environment
124 + value: "production"
125 +
126 +# computes combined metrics
127 +virtual_metrics:
128 + - name: ifTotalTraffic
129 + sources:
130 + - { metric: _ifHCInOctets, table: ifXTable, as: in }
131 + - { metric: _ifHCOutOctets, table: ifXTable, as: out }
132 + chart_meta:
133 + description: Total traffic across all interfaces
134 + family: 'Network/Total/Traffic'
135 + unit: "bit/s"
136 +```
137 +
138 +## Profile Structure
139 +
140 +Each SNMP profile is a YAML file that defines **how Netdata collects, interprets, and labels SNMP metrics** from a device.
141 +
142 +Profiles are modular — you can extend others, define metadata, and specify what to collect.
143 +
144 +```yaml
145 +selector: <device matching pattern>
146 +extends: <base profiles to include>
147 +metadata: <device information>
148 +metrics: <what to collect>
149 +metric_tags: <global tags>
150 +static_tags: <static tags>
151 +virtual_metrics: <calculated metrics>
152 +```
153 +
154 +| Section | Purpose |
155 +|-------------------------------------------|-----------------------------------------------------------|
156 +| [**selector**](#1-selector) | Defines which devices the profile applies to. |
157 +| [**extends**](#2-extends) | Inherits and merges other base profiles. |
158 +| [**metadata**](#3-metadata) | Collects device-level information (host labels). |
159 +| [**metrics**](#4-metrics) | Defines which OIDs to collect and how to chart them. |
160 +| [**metric_tags**](#5-metric_tags) | Defines global dynamic tags collected once per device. |
161 +| [**static_tags**](#6-static_tags) | Defines fixed tags applied to all metrics. |
162 +| [**virtual_metrics**](#7-virtual_metrics) | Defines calculated or aggregated metrics based on others. |
163 +
164 +### 1. selector
165 +
166 +You use the selector to:
167 +
168 +- Target specific **device families** (e.g., Cisco, Juniper, HP)
169 +- Match devices supporting specific **MIBs**
170 +- Exclude unwanted devices
171 +
172 +During discovery, Netdata evaluates all profiles; any profile whose selector matches a device is **applied **.
173 +
174 +```yaml
175 +selector:
176 + - sysobjectid:
177 + include: ["1.3.6.1.4.1.9.*"] # regex: Cisco enterprise OID subtree
178 + exclude: ["1.3.6.1.4.1.9.9.666"] # optional excludes
179 + sysdescr:
180 + include: ["IOS"] # substring (case-insensitive)
181 + exclude: ["emulator", "lab"] # optional excludes
182 +```
183 +
184 +**How it works**:
185 +
186 +- Each selector rule is a set of conditions (`sysobjectid`, `sysdescr`, etc.).
187 +- For a rule to match, **all its conditions must pass**.
188 +- A profile is applied if **at least one rule** in the `selector` list matches the device.
189 +- If both `sysobjectid` and `sysdescr` are defined within the same rule, **both must succeed**.
190 +
191 +**Supported conditions**:
192 +
193 +| Key | What It Checks | Match Criteria (Pass) | Fails When... |
194 +|-----------------------|--------------------------------------|--------------------------------------------------|---------------------------------|
195 +| `sysobjectid.include` | Device `sysObjectID` | Matches **at least one** pattern in the list. | No items match. |
196 +| `sysobjectid.exclude` | Device `sysObjectID` | Matches **none** of the listed patterns. | Any item matches. |
197 +| `sysdescr.include` | Device `sysDescr` (case-insensitive) | Contains **at least one** substring in the list. | No listed substrings are found. |
198 +| `sysdescr.exclude` | Device `sysDescr` (case-insensitive) | Contains **none** of the listed substrings. | Any listed substring is found. |
199 +
200 +### 2. extends
201 +
202 +Use `extends` to inherit metrics, tags, and metadata from another profile instead of duplicating common metrics — perfect for vendor-specific variations of a base MIB.
203 +
204 +Most real profiles extend a few shared building blocks and then add device-specific definitions.
205 +
206 +```yaml
207 +extends:
208 + - _system-base.yaml # System basics (uptime, contact, location)
209 + - _std-if-mib.yaml # Network interfaces (IF-MIB)
210 + - _std-ip-mib.yaml # IP statistics
211 +```
212 +
213 +The final profile is the **merged result** of all inherited profiles plus the content in the current file.
214 +
215 +**How inheritance works**:
216 +
217 +1. **Order matters** — profiles are loaded in the order listed.
218 +2. **Metrics are merged** — all metrics from all referenced profiles are included.
219 +3. **Later overrides earlier** — if the same field is defined multiple times, the last one wins.
220 +
221 +**Common base profiles**
222 +
223 +| Profile | Provides | Typical Use |
224 +|---------------------|-------------------------------------------|--------------------|
225 +| `_system-base.yaml` | Basic system info (uptime, name, contact) | All devices |
226 +| `_std-if-mib.yaml` | Interface statistics (IF-MIB) | Network devices |
227 +| `_std-ip-mib.yaml` | IP-level statistics (IP-MIB) | Routers, switches |
228 +| `_std-tcp-mib.yaml` | TCP statistics | Servers, firewalls |
229 +| `_std-udp-mib.yaml` | UDP statistics | Servers, firewalls |
230 +| `_std-ups-mib.yaml` | Power and UPS metrics | UPS devices |
231 +
232 +### 3. metadata
233 +
234 +The `metadata` section defines **device-level information** (not metric tags).
235 +
236 +It is collected **once per device** and populates the device’s **host labels** in Netdata (the “virtual node” labels shown on the device page).
237 +
238 +It always follows the structure `metadata → device → fields`, where each field defines a single label.
239 +
240 +Each field can be:
241 +
242 +- **Static** — `value:` is a fixed string.
243 +- **Dynamic** — `symbol:` reads the value from an SNMP OID.
244 +
245 +```yaml
246 +metadata:
247 + device:
248 + fields:
249 + vendor:
250 + value: "Cisco" # static label
251 + model:
252 + symbol: # dynamic label from SNMP
253 + OID: 1.3.6.1.2.1.47.1.1.1.1.2.1
254 + name: entPhysicalModelName
255 +```
256 +
257 +:::info
258 +
259 +You can define multiple symbols for fallback — the first valid one will be used.
260 +
261 +:::
262 +
263 +**How it works**:
264 +
265 +- `vendor` is set statically to `"Cisco"`.
266 +- `model` is collected from `entPhysicalModelName`.
267 +- These values appear as **device (virtual node) host labels** in the UI. They are **not** per-metric tags.
268 +
269 +:::tip
270 +
271 +See [**Tag Transformation**](#tag-transformation) for supported transformations and syntax examples.
272 +
273 +:::
274 +
275 +### 4. metrics
276 +
277 +The `metrics` section defines **what data to collect** from the device — which OIDs to query, how to interpret them, and how to display them as charts in Netdata.
278 +
279 +**Metrics can be**:
280 +
281 +- **Scalars** — single values that apply to the entire device (for example, uptime).
282 +- **Tables** — repeating rows of related values (for example, interfaces, disks, sensors).
283 +
284 +:::note
285 +
286 +A metric is **either scalar** (single value) or **table-based** (multiple rows).
287 +Never mix both in the same metric entry.
288 +
289 +:::
290 +
291 +The collector automatically uses **SNMP GET** for scalars and **SNMP BULKWALK** for tables.
292 +
293 +```yaml
294 +metrics:
295 + - MIB: HOST-RESOURCES-MIB
296 + symbol:
297 + OID: 1.3.6.1.2.1.1.3.0
298 + name: systemUptime
299 + scale_factor: 0.01 # Value is in hundredths of a second
300 + chart_meta:
301 + description: Time since the system was last rebooted or powered on
302 + family: 'System/Uptime'
303 + unit: "s"
304 +
305 + - MIB: IF-MIB
306 + table:
307 + OID: 1.3.6.1.2.1.31.1.1
308 + name: ifXTable
309 + symbols:
310 + - OID: 1.3.6.1.2.1.31.1.1.1.6
311 + name: ifHCInOctets
312 + chart_meta:
313 + description: Traffic
314 + family: 'Network/Interface/Traffic/In'
315 + unit: "bit/s"
316 + scale_factor: 8 # Octets → bits
317 + metric_tags:
318 + - tag: interface
319 + symbol:
320 + OID: 1.3.6.1.2.1.31.1.1.1.1
321 + name: ifName
322 +```
323 +
324 +**How it works**:
325 +
326 +- Each entry defines a metric or table of metrics to collect via SNMP.
327 +- Scalars use a single `symbol`, while tables define a `table` and one or more `symbols`.
328 +- Metrics can include transformations (`extract_value`, `scale_factor`, etc.) and chart metadata.
329 +- Table metrics can include tags (`metric_tags`) to identify rows by interface, disk, or other attributes.
330 +
331 +:::tip
332 +
333 +See also
334 +
335 +- [Collecting Metrics](#collecting-metrics) — explains SNMP OIDs, scalars, and tables.
336 +- [Scalar Metrics](#scalar-metrics-single-values) — detailed syntax for single-value metrics.
337 +- [Table Metrics](#table-metrics-multiple-rows)— how tables and row indexes work.
338 +- [Adding Tags to Metrics](#adding-tags-to-metrics) — tag types and how to label table rows.
339 +- [Tag Transformations](#tag-transformation) — extract, match, or map tag values.
340 +- [Value Transformations](#value-transformation) — manipulate or scale collected values.
341 +- [Virtual Metrics](#virtual-metrics) — build new metrics from existing ones.
342 +
343 +:::
344 +
345 +### 5. metric_tags
346 +
347 +The `metric_tags` section defines **global dynamic tags** — values collected once from the device and applied to **every metric** in the profile.
348 +
349 +They are evaluated during collection, just like other SNMP symbols, and remain the same for all metrics within that device.
350 +
351 +**Typical uses**:
352 +
353 +- Attach device-wide metadata such as serial number, firmware version, or model.
354 +- Enable grouping and filtering by hardware, OS, or vendor attributes.
355 +- Complement per-metric tags (for example, per-interface or per-sensor tags in tables).
356 +
357 +```yaml
358 +metric_tags:
359 + - tag: fs_sys_serial
360 + symbol:
361 + OID: 1.3.6.1.4.1.12356.106.1.1.1.0
362 + name: fsSysSerial
363 + - tag: fs_sys_version
364 + symbol:
365 + OID: 1.3.6.1.4.1.12356.106.4.1.1.0
366 + name: fsSysVersion
367 +```
368 +
369 +**How it works**:
370 +
371 +- Each tag is collected once per device, not per metric or per table row.
372 +- The resulting tag values are attached to **all metrics** collected by the profile.
373 +- Tags can be transformed (for example, reformatted or mapped) using the same rules as per-metric tags.
374 +
375 +:::tip
376 +
377 +See [**Tag Transformation**](#tag-transformation) for supported transformations and syntax examples.
378 +
379 +:::
380 +
381 +### 6. static_tags
382 +
383 +The `static_tags` section defines **fixed key–value pairs** that are attached to every metric collected by the profile.
384 +
385 +They don’t depend on SNMP data and remain constant for all devices using the profile.
386 +
387 +**Typical uses**:
388 +
389 +- Add environment or deployment identifiers (for example, `environment`, `region`, or `service`).
390 +- Simplify filtering, grouping, and alerting across metrics from multiple devices.
391 +- Provide consistent context (for example, datacenter or team ownership).
392 +
393 +```yaml
394 +static_tags:
395 + - tag: environment
396 + value: production
397 + - tag: region
398 + value: us-east-1
399 + - tag: service
400 + value: network
401 +```
402 +
403 +**How it works**:
404 +
405 +- Each tag is added to **all metrics** collected by the profile.
406 +- Static tags are merged with any dynamic tags defined in `metric_tags`.
407 +- Device-specific or dynamic tags always take precedence if they overlap.
408 +
409 +### 7. virtual_metrics
410 +
411 +The `virtual_metrics` section defines **calculated metrics** built from other metrics already collected by the profile.
412 +
413 +They don’t query SNMP directly — instead, they reuse existing metric values to produce totals, sums, or fallbacks.
414 +
415 +:::tip
416 +
417 +See [**Virtual Metrics**](#virtual-metrics) for the complete reference, configuration options, and advanced examples.
418 +
419 +:::
420 +
421 +**Typical uses**:
422 +
423 +- Combine related counters (for example, `in` + `out` traffic or errors).
424 +- Create fallbacks (prefer 64-bit counters, fall back to 32-bit if missing).
425 +- Aggregate or group metrics per tag (for example, total per interface or per type).
426 +
427 +```yaml
428 + - name: ifTotalTraffic
429 + sources:
430 + - { metric: ifHCInOctets, table: ifXTable, as: in }
431 + - { metric: ifHCOutOctets, table: ifXTable, as: out }
432 + chart_meta:
433 + description: Total traffic across all interfaces
434 + family: 'Network/Total/Traffic'
435 + unit: "bit/s"
436 +```
437 +
438 +**How it works**:
439 +
440 +- Defines a new virtual metric named `ifTotalTraffic`.
441 +- Uses existing metrics (`ifHCInOctets`, `ifHCOutOctets`) as sources.
442 +- The `as` field names the resulting dimensions (`in`, `out`).
443 +- The resulting chart behaves like a regular metric — visible in dashboards, alertable, and included in exports.
444 +
445 +## Collecting Metrics
446 +
447 +This section explains how SNMP data is structured and how it maps to metrics in a Netdata profile.
448 +
449 +### Understanding SNMP Data
450 +
451 +SNMP data is organized as a **hierarchical tree** of numeric identifiers called **OIDs** (**Object Identifiers**).
452 +
453 +Each OID uniquely identifies a value on a device — similar to a file path in a filesystem.
454 +
455 +```text
456 +1.3.6.1.2.1.1.3.0
457 +│ │ │ │ │ │ │ └── Instance (0 = scalar)
458 +│ │ │ │ │ │ └──── Object (3 = sysUpTime)
459 +│ │ │ │ │ └────── Branch: system (MIB-2)
460 +│ │ │ └────────── MIB-2 root
461 +└─ SNMP global prefix
462 +```
463 +
464 +- **MIBs** (Management Information Bases) are named collections of related OIDs.
465 +
466 + Examples: `IF-MIB` (interfaces), `IP-MIB` (IP statistics), `HOST-RESOURCES-MIB` (system info).
467 +- Each OID maps to a **typed value**, such as `Counter64`, `Gauge32`, `Integer`, or `TimeTicks`.
468 +- Some OIDs represent **single values** (scalars), while others represent **tables** of related values (rows).
469 +
470 +### Scalar Metrics (Single Values)
471 +
472 +Scalar metrics represent a **single value for the entire device**.
473 +
474 +Their OIDs always end with `.0`, which denotes the **instance number** for a scalar object.
475 +
476 +```yaml
477 +metrics:
478 + - MIB: HOST-RESOURCES-MIB
479 + symbol:
480 + OID: 1.3.6.1.2.1.1.3.0
481 + name: systemUptime
482 + scale_factor: 0.01 # Value is in hundredths of a second
483 + chart_meta:
484 + description: Time since the system was last rebooted or powered on.
485 + family: 'System/Uptime'
486 + unit: "s"
487 +```
488 +
489 +**What this does**:
490 +
491 +- Collects the `sysUpTime` value once per device.
492 +- The `.0` at the end indicates there is only **one instance** of this value.
493 +- Common scalar metrics: device uptime, total memory, or overall temperature.
494 +
495 +### Table Metrics (Multiple Rows)
496 +
497 +Table metrics represent **lists of related values**, such as one entry per network interface, disk, or CPU.
498 +
499 +Each row in a table is identified by an **index** appended to the base OID — for example:
500 +
501 +```text
502 +ifHCInOctets.1 = 1024
503 +ifHCInOctets.2 = 2048
504 +```
505 +
506 +- `.1`, `.2`, … are `row indexes` that identify the instance (e.g., interface #1, interface #2).
507 +- Each column (symbol) in the table has its own OID pattern but shares the same row indexes.
508 +
509 +> Table metrics **must define at least one tag** (`metric_tags`) to identify each row.
510 +> Without tags, only a single row can be emitted.
511 +
512 +```yaml
513 +metrics:
514 + - MIB: IF-MIB
515 + table:
516 + OID: 1.3.6.1.2.1.31.1.1
517 + name: ifXTable
518 + symbols:
519 + - OID: 1.3.6.1.2.1.31.1.1.1.6
520 + name: ifHCInOctets
521 + chart_meta:
522 + description: Traffic
523 + family: 'Network/Interface/Traffic/In'
524 + unit: "bit/s"
525 + scale_factor: 8 # Octets → bits
526 + metric_tags:
527 + - tag: interface
528 + symbol:
529 + OID: 1.3.6.1.2.1.31.1.1.1.1
530 + name: ifName
531 +```
532 +
533 +**How Table Metrics Expand into Rows**
534 +
535 +```text
536 +SNMP Table: ifTable
537 +───────────────────────────────────────────────
538 +Index | ifName | ifHCInOctets
539 +───────────────────────────────────────────────
540 +1 | eth0 | 1024
541 +2 | eth1 | 2048
542 +───────────────────────────────────────────────
543 +
544 +metric_tags:
545 + - tag: interface
546 + symbol:
547 + OID: 1.3.6.1.2.1.31.1.1.1.1 # ifName
548 +
549 +Resulting metrics:
550 +───────────────────────────────────────────────
551 +ifHCInOctets{interface="eth0"} = 1024
552 +ifHCInOctets{interface="eth1"} = 2048
553 +───────────────────────────────────────────────
554 +```
555 +
556 +**How it works**:
557 +
558 +1. The collector reads both columns (`ifHCInOctets` and `ifName`) from the same table.
559 +2. It aligns rows using their shared SNMP index (`1`, `2`, …).
560 +3. Each metric is emitted with its corresponding tag from the same row.
561 +
562 +**What this does**:
563 +
564 +- Collects traffic (`ifHCInOctets`) from each interface.
565 +- Tags each row with its name (`ifName`) from the same index.
566 +- Produces metrics like:
567 + ```text
568 + ifHCInOctets{interface="eth0"} = 1024
569 + ifHCInOctets{interface="eth1"} = 2048
570 + ```
571 +
572 +### Metric Types
573 +
574 +Each SNMP value has a data type that determines **how Netdata interprets and displays it**.
575 +
576 +The collector automatically detects the appropriate **metric type** (e.g., `gauge` or `rate`), but you can override it manually.
577 +
578 +**Automatic Type Detection**
579 +
580 +| SNMP Type | Default Netdata Type | Typical Use |
581 +|--------------------------|----------------------|--------------------------------------|
582 +| `Counter32`, `Counter64` | `rate` | Network traffic, packet counters |
583 +| `Gauge32`, `Integer` | `gauge` | Temperatures, usage levels, statuses |
584 +| `TimeTicks` | `gauge` | Uptime, time-based values |
585 +
586 +**Overriding the Metric Type**
587 +
588 +You can explicitly set a metric’s type using the `metric_type` field inside a symbol definition.
589 +
590 +```yaml
591 +metrics:
592 + - MIB: IF-MIB
593 + table:
594 + OID: 1.3.6.1.2.1.2.2
595 + name: ifTable
596 + symbols:
597 + - OID: 1.3.6.1.2.1.2.2.1.10
598 + name: ifInOctets
599 + metric_type: gauge # Override default 'rate'
600 +```
601 +
602 +**What this does**:
603 +
604 +- Forces `ifInOctets` to be treated as a **gauge** (instantaneous value) instead of a rate.
605 +- Normally, `Counter` types are automatically converted to per-second rates.
606 +
607 +## Adding Tags to Metrics
608 +
609 +Tags add **context and identity** to SNMP metrics.
610 +
611 +They let you distinguish between instances (for example, which interface, disk, or IP) and allow filtering and grouping in the Netdata UI.
612 +
613 +**The collector**:
614 +
615 +- Attaches tags to each metric as labels.
616 +- Uses tags to differentiate rows when building charts.
617 +- Requires at least one tag for every **table metric** (to identify each row).
618 +- Ignores tags for **scalar metrics**, which represent a single value per device.
619 +
620 +**Key Concepts**:
621 +
622 +| Concept | Description |
623 +|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
624 +| **Table metrics must have tags** | Each table row must be uniquely identified by at least one tag (for example, interface name or index). Without tags, only one row is emitted. |
625 +| **Scalar metrics don’t need tags** | Scalars represent one value for the entire device, not per-instance data. |
626 +| **Static tags** | Fixed values that never change (for example, datacenter, environment). |
627 +| **Dynamic tags** | Extracted from SNMP data — from table columns, related tables, or row indexes. |
628 +| **Global tags** | Defined in the profile’s top-level `metric_tags` section and applied to all metrics. |
629 +
630 +**Tag Types and Available Transformations**:
631 +
632 +| Tag Type | Description | Supported Transformations |
633 +|---------------------|-----------------------------------------------------------------|-------------------------------------------------------------------------------|
634 +| **Static** | Fixed tags with constant values. | None (value is fixed). |
635 +| **Same-Table** | Values from columns in the same table as the metric. | `mapping`, `extract_value`, `match_pattern` + `match_value`, `match` + `tags` |
636 +| **Cross-Table** | Values from another table. | `mapping`, `extract_value`, `match_pattern` + `match_value`, `match` + `tags` |
637 +| **Index-Based** | Values derived from the OID index of each row. | `mapping` (optional) |
638 +| **Index Transform** | Adjusts multi-part indexes so cross-table tags align correctly. | — (structural, not a transformation) |
639 +
640 +**Summary**:
641 +
642 +- Each **table metric** must define at least one **tag source** (`metric_tags`) to distinguish rows.
643 +- Tags can come from **the same table**, **another table**, or the **row index** itself.
644 +- Tag transformations (`mapping`, `extract_value`, `match_pattern`, `match + tags`) can modify or extract parts of raw values.
645 +- **Static tags** apply globally and are not transformed.
646 +- **Index transformations** are a special mechanism used only for aligning multi-part indexes between tables.
647 +
648 +**How the Collector Matches Values and Tags**:
649 +
650 +```text
651 +SNMP Table (ifTable)
652 +───────────────────────────────────────────────
653 +Index | ifDescr | ifInOctets
654 +───────────────────────────────────────────────
655 +1 | eth0 | 1024
656 +2 | eth1 | 2048
657 +───────────────────────────────────────────────
658 +
659 +metric_tags:
660 + - tag: interface
661 + symbol:
662 + OID: 1.3.6.1.2.1.2.2.1.2 # ifDescr
663 +
664 +Resulting metrics:
665 +───────────────────────────────────────────────
666 +ifInOctets{interface="eth0"} = 1024
667 +ifInOctets{interface="eth1"} = 2048
668 +───────────────────────────────────────────────
669 +```
670 +
671 +How it works:
672 +
673 +1. The collector walks the table and collects both columns: `ifInOctets` (value) and `ifDescr` (tag source).
674 +2. It aligns them by their shared SNMP index (`1`, `2`, …).
675 +3. Each metric row is tagged with the corresponding column value from the same index.
676 +
677 +**Cross-Table Example**:
678 +
679 +```text
680 +SNMP Tables: ifTable + ifXTable
681 +───────────────────────────────────────────────
682 +ifTable.ifInOctets.1 = 1024
683 +ifTable.ifInOctets.2 = 2048
684 +
685 +ifXTable.ifName.1 = "eth0"
686 +ifXTable.ifName.2 = "eth1"
687 +───────────────────────────────────────────────
688 +
689 +metric_tags:
690 + - tag: interface
691 + table: ifXTable
692 + symbol:
693 + OID: 1.3.6.1.2.1.31.1.1.1.1 # ifName
694 +
695 +Result:
696 +───────────────────────────────────────────────
697 +ifInOctets{interface="eth0"} = 1024
698 +ifInOctets{interface="eth1"} = 2048
699 +───────────────────────────────────────────────
700 +```
701 +
702 +How it works:
703 +
704 +- The collector collects metrics from `ifTable` but fetches tag values from `ifXTable`.
705 +- It matches rows from both tables using their shared index (`.1`, `.2`, …).
706 +- The `interface` tag is populated from `ifXTable.ifName` for each matching row
707 +
708 +### Static
709 +
710 +Static tags define **fixed key–value pairs** that are attached to metrics without being collected from SNMP.
711 +
712 +They are useful for identifying **environment**, **location**, or other context that applies to all collected data.
713 +
714 +#### Profile-level Static Tags
715 +
716 +Profile-level static tags apply to **all metrics** defined in the profile.
717 +
718 +```yaml
719 +# Global static tags (applied to all metrics)
720 +static_tags:
721 + - tag: datacenter
722 + value: "DC1"
723 + - tag: environment
724 + value: "production"
725 +```
726 +
727 +**What this does**:
728 +
729 +- These tags are injected into every metric reported by the profile.
730 +
731 +**Typical use cases**:
732 +
733 +- Identify the datacenter, region, or cluster where the device belongs.
734 +- Mark metrics from staging or production environments.
735 +- Add organization-wide context that doesn’t depend on SNMP data.
736 +
737 +#### Metric-level Static Tags
738 +
739 +Metric-level static tags apply to **specific metrics only**.
740 +
741 +```yaml
742 +# Metric-specific static tags
743 +metrics:
744 + - MIB: IF-MIB
745 + table:
746 + OID: 1.3.6.1.2.1.2.2
747 + name: ifTable
748 + symbols:
749 + - OID: 1.3.6.1.2.1.2.2.1.10
750 + name: ifInOctets
751 + static_tags:
752 + - tag: "source"
753 + value: "snmp"
754 + - tag: "interface_type"
755 + value: "physical"
756 +```
757 +
758 +**What this does**:
759 +
760 +- Adds the tags `source=snmp` and `interface_type=physical` only to the `ifInOctets` metric.
761 +- Does not affect other metrics in the same profile.
762 +
763 +> Metric-level static tags are technically supported but rarely needed.
764 +> In most cases, prefer profile-level `static_tags` for consistency and simplicity.
765 +
766 +### Same-Table
767 +
768 +Same-table tags extract values from **columns in the same SNMP table** as the metric.
769 +
770 +They are the most common way to label per-row metrics with identifiers like interface names or indexes.
771 +
772 +**The collector**:
773 +
774 +- Retrieves both the metric value and the tag column from the same table row.
775 +- Automatically aligns rows by their shared index.
776 +- Adds the tag to every metric collected from that row.
777 +
778 +```yaml
779 +metrics:
780 + - MIB: IF-MIB
781 + table:
782 + OID: 1.3.6.1.2.1.2.2
783 + name: ifTable
784 + symbols:
785 + - OID: 1.3.6.1.2.1.2.2.1.10
786 + name: ifInOctets
787 + metric_tags:
788 + - tag: interface
789 + symbol:
790 + OID: 1.3.6.1.2.1.2.2.1.2
791 + name: ifDescr
792 +```
793 +
794 +**What this does**:
795 +
796 +- Collects `ifInOctets` (input bytes) for each row in `ifTable`.
797 +- Reads the `ifDescr` column from the same table to label each row.
798 +- Produces metrics like:
799 + ```text
800 + ifInOctets{interface="eth0"} = 1000
801 + ifInOctets{interface="eth1"} = 2000
802 + ```
803 +
804 +### Cross-Table
805 +
806 +Cross-table tags let you **use data from another SNMP table** as a tag source.
807 +
808 +**The collector**:
809 +
810 +- Reads tag values from the specified `table:` instead of the current one.
811 +- Matches rows between tables by their **index**.
812 +- When index structures differ, an optional `index_transform` can modify the current table’s index to align it with the target.
813 +
814 +#### Same Index
815 +
816 +Two tables are said to have the **same index** when their row identifiers (OID suffixes after the base OID) are identical — meaning they describe the same entity.
817 +
818 +In practice, this means that the row number (index) in one table corresponds directly to the same row in another.
819 +
820 +For example:
821 +
822 +```text
823 +ifTable.ifInOctets.2 = 123456
824 +ifXTable.ifName.2 = "xe-0/0/1"
825 +```
826 +
827 +Both OIDs end with `.2`, so they refer to the same interface.
828 +
829 +This allows you to use `ifName` (from `ifXTable`) as a tag for metrics collected from `ifTable`.
830 +
831 +```yaml
832 +metrics:
833 + - MIB: IF-MIB
834 + table:
835 + OID: 1.3.6.1.2.1.2.2
836 + name: ifTable
837 + symbols:
838 + - OID: 1.3.6.1.2.1.2.2.1.10
839 + name: ifInOctets
840 + metric_tags:
841 + - tag: interface
842 + table: ifXTable
843 + symbol:
844 + OID: 1.3.6.1.2.1.31.1.1.1.1
845 + name: ifName
846 +```
847 +
848 +**What this does**:
849 +
850 +- Collects `ifInOctets` from `ifTable`.
851 +- Finds the row with the same index in `ifXTable` (e.g., `.2`).
852 +- Uses `ifName` as the `interface` tag.
853 +- Produces metrics like:
854 + ```text
855 + ifInOctets{interface="xe-0/0/1"} = 123456
856 + ```
857 +
858 +#### With Index Transformation
859 +
860 +Some tables describe related data but use **different index structures** — meaning their OID suffixes don’t line up directly.
861 +
862 +For example, in `ipIfStatsTable` the index contains **two parts**:
863 +
864 +```text
865 +ipIfStatsTable.ipIfStatsHCInOctets.2.1 = 38560
866 +ipIfStatsTable.ipIfStatsHCInOctets.2.2 = 44408
867 +```
868 +
869 +Here:
870 +
871 +- The first component (`2`) is the **IP version** (e.g., 2 = IPv4, 3 = IPv6).
872 +- The second component (`1`, `2`, `3`, …) is the **interface index**.
873 +- `ifXTable`, on the other hand, uses only the interface index (`1`, `2`, `3`, …).
874 +
875 +Because the indexes differ, they can’t be matched directly.
876 +
877 +To fix this, use `index_transform` to **select only the relevant part of the index** so it matches the target table’s format.
878 +
879 +```yaml
880 +metrics:
881 + - MIB: IP-MIB
882 + table:
883 + OID: 1.3.6.1.2.1.4.31.3
884 + name: ipIfStatsTable
885 + symbols:
886 + - OID: 1.3.6.1.2.1.4.31.3.1.6
887 + name: ipIfStatsHCInOctets
888 + chart_meta:
889 + description: Total inbound IP octets (including errors)
890 + family: 'Network/Interface/IP/Traffic/Total/In'
891 + unit: "bit/s"
892 + scale_factor: 8
893 + metric_tags:
894 + - tag: _interface
895 + table: ifXTable
896 + symbol:
897 + OID: 1.3.6.1.2.1.31.1.1.1.1
898 + name: ifName
899 + index_transform:
900 + - start: 1
901 + end: 1
902 +```
903 +
904 +**What this does**:
905 +
906 +- Collects IP traffic metrics from `ipIfStatsTable`.
907 +- Keeps only the **second index element** (`start: 1`, `end: 1`) from `2.1` → becomes `1`.
908 +- Looks up that interface index in `ifXTable` to find the corresponding `ifName`.
909 +- Produces:
910 + ```yaml
911 + ipIfStatsHCInOctets{_interface="xe-0/0/1"} = 38560
912 + ```
913 +
914 +##### How `index_transform` Works
915 +
916 +`index_transform` tells the collector which parts of the current table’s index to keep when matching rows across tables.
917 +
918 +| Concept | Example |
919 +|--------------------|-----------------------------------------------------------------------------------------------|
920 +| **Original index** | `2.1` (from `ipIfStatsTable`) → `[ipVersion, ifIndex]` |
921 +| **Target index** | `1` (from `ifXTable`) |
922 +| **Transform** | `index_transform: [ { start: 1, end: 1 } ]` |
923 +| **Result** | The collector keeps only the **second element** (`ifIndex = 1`), which now matches `ifXTable` |
924 +
925 +**In short**:
926 +
927 +- `start` and `end` positions are **zero-based** (0 = first index element).
928 +- Each range defines which parts of the index to keep.
929 +- You can list multiple ranges to combine non-contiguous parts.
930 +- The goal is to make the current table’s index **match** the target table’s index so tags align correctly.
931 +
932 +### Index-Based
933 +
934 +Index-based tags extract values directly from the **OID index** of the SNMP table rather than from a column.
935 +
936 +This is useful when a table encodes identifiers (like method, code, or port number) as part of the OID itself instead of storing them in separate columns.
937 +
938 +**The collector**:
939 +
940 +- Splits the table’s row index into numbered parts (1-based).
941 +- For each `index:` rule, assigns a tag using the specified position in the index.
942 +- Converts numeric index components to strings automatically.
943 +- Attaches all resulting tags to the metric collected from that row.
944 +
945 +```yaml
946 +metrics:
947 + - MIB: SIP-COMMON-MIB
948 + table:
949 + name: sipCommonStatusCodeTable
950 + OID: 1.3.6.1.2.1.149.1.5.1
951 + symbols:
952 + - OID: 1.3.6.1.2.1.149.1.5.1.1.3
953 + name: sipCommonStatusCodeIns
954 + chart_meta:
955 + family: 'Network/VoIP/SIP/Response/StatusCode/In'
956 + description: Total number of response messages received with the specified status code
957 + unit: "{response}/s"
958 + metric_tags:
959 + - index: 1
960 + tag: applIndex
961 + - index: 2
962 + tag: sipCommonStatusCodeMethod
963 + - index: 3
964 + tag: sipCommonStatusCodeValue
965 +```
966 +
967 +**What this does**:
968 +
969 +- Extracts the first three components of each row’s OID index and uses them as tags.
970 +- For example, if the full OID is:
971 + ```text
972 + 1.3.6.1.2.1.149.1.5.1.1.3.1.6.200
973 + ```
974 + The collector interprets:
975 + ```ini
976 + applIndex=1
977 + sipCommonStatusCodeMethod=6
978 + sipCommonStatusCodeValue=200
979 + ```
980 +- Produces metrics like:
981 + ```text
982 + sipCommonStatusCodeIns{applIndex="1", sipCommonStatusCodeMethod="6", sipCommonStatusCodeValue="200"} = 42
983 + ```
984 +
985 +## Tag Transformation
986 +
987 +Tag transformations let you **modify or extract parts of SNMP values** to produce clear, human-readable tags.
988 +
989 +They work the same in **both** places:
990 +
991 +- `metadata` (e.g., device model, OS name), and
992 +- `metric_tags` (e.g., per-row interface labels).
993 +
994 +**Available Tag Transformations**:
995 +
996 +| Transformation | Purpose | Example Input → Output |
997 +|----------------------------------|-------------------------------------------------|------------------------------------------------------------------|
998 +| `mapping` | Replace numeric/string codes with names. | `1 → "ethernet"`, `161 → "lag"` |
999 +| `extract_value` | Extract a substring via regex (first group). | `"RouterOS CCR2004-16G-2S+" → "CCR2004-16G-2S+"` |
1000 +| `match_pattern` + `match_value` | Replace the value using regex groups or static. | `"Palo Alto Networks VM-Series firewall" → "VM-Series firewall"` |
1001 +| `match` + `tags` (multiple tags) | Create **several** tags from one value. | `"xe-0/0/1" → if_family=xe, fpc=0, pic=0, port=1` |
1002 +
1003 +**Combination & Behavior**:
1004 +
1005 +| Rule | Description |
1006 +|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
1007 +| **Where** | Can be used inside `metadata.*.fields.*.symbols[]` and `metric_tags[]`. |
1008 +| **Order of application** | 1️⃣ `match_pattern` + `match_value` **or** `extract_value` (whichever is present) → 2️⃣ `mapping` → 3️⃣ `match` + `tags` (if defined). |
1009 +| **No match behavior** | • `extract_value`: keeps the original value.<br/>• `match_pattern`: skips the value (tag not emitted).<br/>• `match` + `tags`: emits no tags. |
1010 +| **Multiple symbols** | If multiple `symbols` are listed for the same tag, the **first non-empty result** is used. |
1011 +| **Mapping key consistency** | Keys in a `mapping` must all be the same type — all numeric or all string. |
1012 +| **Safety** | Keep regexes simple and, when possible, **anchor them** (e.g. `^pattern$`) to prevent unwanted matches. |
1013 +
1014 +**Quick Syntax Recap**:
1015 +
1016 +- `mapping`
1017 + ```yaml
1018 + mapping:
1019 + 6: "ethernet"
1020 + 161: "lag"
1021 + ```
1022 +- `extract_value`
1023 + ```yaml
1024 + extract_value: 'RouterOS ([A-Za-z0-9-+]+)' # first capture group is used
1025 + ```
1026 +
1027 +- `match_pattern` + `match_value`
1028 + ```yaml
1029 + match_pattern: 'Palo Alto Networks\s+(PA-\d+ series firewall|VM-Series firewall)'
1030 + match_value: '$1' # or a static value like 'Router' when matched
1031 + ```
1032 +- `match` + `tags` (multiple tags)
1033 + ```yaml
1034 + match: '^([A-Za-z]+)[-_]?(\d+)\/(\d+)\/(\d+)$'
1035 + tags:
1036 + if_family: $1
1037 + fpc: $2
1038 + pic: $3
1039 + port: $4
1040 + ```
1041 +
1042 +### Mapping
1043 +
1044 +Use `mapping` to replace raw tag values with **human-readable text labels**.
1045 +
1046 +**The collector**:
1047 +
1048 +- Looks up the raw value in the mapping table.
1049 +- Replaces it with the corresponding string.
1050 +- If the value is not found in the mapping, the **original value** is **kept**.
1051 +- Keys can be numeric or string, but must be consistent in type.
1052 +- Mapping is applied to tag values from `metadata` or `metric_tags`.
1053 +
1054 +```yaml
1055 +metrics:
1056 + - MIB: IF-MIB
1057 + table:
1058 + OID: 1.3.6.1.2.1.2.2
1059 + name: ifTable
1060 + symbols:
1061 + - OID: 1.3.6.1.2.1.2.2.1.10
1062 + name: ifInOctets
1063 + metric_tags:
1064 + - tag: if_type
1065 + symbol:
1066 + OID: 1.3.6.1.2.1.2.2.1.3
1067 + name: ifType
1068 + mapping:
1069 + 1: "other"
1070 + 6: "ethernet"
1071 + 24: "loopback"
1072 + 131: "tunnel"
1073 + 161: "lag"
1074 +```
1075 +
1076 +**What this does**:
1077 +
1078 +- Replaces numeric interface type codes (1, 6, 24, 131, 161) with readable names (`other`, `ethernet`, `loopback`, `tunnel`, `lag`).
1079 +- If a device reports an unknown type, the original numeric value is used.
1080 +- Works identically for `metadata` fields and `metric_tags`.
1081 +
1082 +### Extract Value
1083 +
1084 +Use `extract_value` to capture a part of a string using a **regular expression**.
1085 +
1086 +**The collector**:
1087 +
1088 +- Applies the pattern to the raw value.
1089 +- Replaces the value with the **first capture group** `( … )`.
1090 +- Keeps the **original value** if no match is found.
1091 +- Searches anywhere in the string unless you anchor the pattern with `^` or `$`.
1092 +- Uses the **first non-empty** result when multiple `symbols` are defined.
1093 +
1094 +```yaml
1095 +metadata:
1096 + device:
1097 + fields:
1098 + model:
1099 + symbols:
1100 + # Example: 'RouterOS CCR2004-16G-2S+' → 'CCR2004-16G-2S+'
1101 + - OID: 1.3.6.1.2.1.1.1.0
1102 + name: sysDescr
1103 + extract_value: 'RouterOS ([A-Za-z0-9-+]+)'
1104 + # Example: 'CSS326-24G-2S+ SwOS v2.13' → 'CSS326-24G-2S+'
1105 + - OID: 1.3.6.1.2.1.1.1.0
1106 + name: sysDescr
1107 + extract_value: '([A-Za-z0-9-+]+) SwOS'
1108 +```
1109 +
1110 +### Match Pattern
1111 +
1112 +Use `match_pattern` and `match_value` together to build a tag value using multiple **regex capture groups**.
1113 +
1114 +**The collector**:
1115 +
1116 +- Tests the value against the regular expression in `match_pattern`.
1117 +- If it **matches**, replaces the value with `match_value`.
1118 +- Within `match_value`, you can reference **capture groups** using `$1`, `$2`, `$3`, etc.
1119 +- If the value **does not match**, it is skipped (ignored).
1120 +- Works both for reformatting captured text and for assigning a static replacement when matched.
1121 +
1122 +**Example 1 — Reformat using capture groups**:
1123 +
1124 +```yaml
1125 +metadata:
1126 + device:
1127 + fields:
1128 + product_name:
1129 + symbol:
1130 + OID: 1.3.6.1.2.1.1.1.0
1131 + name: sysDescr
1132 + match_pattern: 'Palo Alto Networks\s+(PA-\d+ series firewall|WildFire Appliance|VM-Series firewall)'
1133 + match_value: "$1"
1134 + # Examples:
1135 + # - Palo Alto Networks VM-Series firewall → VM-Series firewall
1136 + # - Palo Alto Networks PA-3200 series firewall → PA-3200 series firewall
1137 + # - Palo Alto Networks WildFire Appliance → WildFire Appliance
1138 +```
1139 +
1140 +**Example 2 — Assign static value on match**:
1141 +
1142 +```yaml
1143 +metadata:
1144 + device:
1145 + fields:
1146 + type:
1147 + symbols:
1148 + - OID: 1.3.6.1.2.1.1.1.0
1149 + name: sysDescr
1150 + # RouterOS devices
1151 + match_pattern: 'RouterOS (CCR.*)'
1152 + match_value: 'Router'
1153 +```
1154 +
1155 +### Match (Multiple Tags)
1156 +
1157 +Use `match` and `tags` to create **multiple tags** from a single SNMP value using a **regular expression** with capture groups.
1158 +
1159 +**The collector**:
1160 +
1161 +- Applies the regex in match to the raw value.
1162 +- If it `matches`, creates all tags listed under `tags`, substituting `$1`, `$2`, `$3`, etc. from the capture groups.
1163 +- If it **doesn’t match**, none of those tags are added.
1164 +- Tags that resolve to an **empty capture** are not added.
1165 +
1166 +**Example 1 — Split OS name and model from sysDescr (metadata)**:
1167 +
1168 +```yaml
1169 +metadata:
1170 + device:
1171 + fields:
1172 + type:
1173 + symbols:
1174 + - OID: 1.3.6.1.2.1.1.1.0
1175 + name: sysDescr
1176 + match: '^(\S+)\s+(.*)$'
1177 + tags:
1178 + os_name: $1 # e.g. 'RouterOS'
1179 + model: $2 # e.g. 'CCR2004-16G-2S+'
1180 +```
1181 +
1182 +> Input like `RouterOS CCR2004-16G-2S+` becomes: `os_name=RouterOS`, `model=CCR2004-16G-2S+`.
1183 +
1184 +**Example 2 — Derive multiple labels from interface names (metric_tags)**:
1185 +
1186 +```yaml
1187 +metric_tags:
1188 + - symbol:
1189 + OID: 1.3.6.1.2.1.2.2.1.2
1190 + name: ifDescr
1191 + match: '^([A-Za-z]+)[-_]?(\d+)\/(\d+)\/(\d+)$'
1192 + tags:
1193 + if_family: $1 # e.g. 'xe' or 'ge' or 'GigabitEthernet' → 'GigabitEthernet'
1194 + fpc: $2 # '0'
1195 + pic: $3 # '0'
1196 + port: $4 # '1'
1197 +```
1198 +
1199 +- Handles common patterns like `xe-0/0/1`, `ge-0/0/0`, or `GigabitEthernet1/0/24`.
1200 +- Output tags might be: `if_family=xe`, `fpc=0`, `pic=0`, `port=1`.
1201 +
1202 +## Value Transformation
1203 +
1204 +Value transformations let you **process or normalize raw SNMP metric values** before they are stored and charted.
1205 +
1206 +They are applied **per symbol (per OID)** during SNMP data collection. They modify only **metric values**, not tags or metadata, and are **not applied to virtual metrics**.
1207 +
1208 +These transformations are typically used to:
1209 +
1210 +- Extract numeric substrings from mixed strings.
1211 +- Scale or convert units (bytes → bits, megabits → bits).
1212 +- Map discrete states (1 = up, 2 = down, etc.) into named dimensions.
1213 +
1214 +**Available Value Transformations**:
1215 +
1216 +| Transformation | Purpose | Example Input → Output |
1217 +|---------------------------------|-------------------------------------------------------------------|-------------------------------------|
1218 +| `mapping` | Convert numeric or string codes into state dimensions. | `1 → up`, `2 → down`, `3 → testing` |
1219 +| `extract_value` | Extract a numeric substring via regex. | `"23.8 °C" → "23"` |
1220 +| `scale_factor` | Multiply values by a constant to adjust units. | `"1.5" (MBps) × 8 → 12 (Mbps)` |
1221 +| `match_pattern` + `match_value` | *Not applicable* for metric values (use `extract_value` instead). | — |
1222 +
1223 +**Combination & Behavior**:
1224 +
1225 +| Rule | Description |
1226 +|---------------------------|---------------------------------------------------------------------------------------------------------------------------|
1227 +| **Where** | Value transformations are used inside `metrics[*].symbol` or `metrics[*].symbols[]`. |
1228 +| **Order of application** | 1️⃣ `extract_value` (if present) → 2️⃣ `mapping` → 3️⃣ `scale_factor`. |
1229 +| **Scale factor position** | `scale_factor` is always applied **last**, after all other transformations. |
1230 +| **Data type handling** | Transformations preserve numeric type (integer/float) unless the mapping converts it to a multi-value metric. |
1231 +| **Error handling** | If a transformation fails (e.g., regex doesn’t match), the collector keeps the original value. |
1232 +| **Applicability** | Transformations affect metric values only — not metadata or tags. |
1233 +| **Mapping behavior** | Always produces a multi-value metric where each mapped entry becomes a dimension; the active one reports `1`, others `0`. |
1234 +
1235 +**Quick Syntax Recap**:
1236 +
1237 +- `mapping`
1238 + ```yaml
1239 + mapping:
1240 + 1: up
1241 + 2: down
1242 + 3: testing
1243 + ```
1244 +
1245 +- `extract_value`
1246 + ```yaml
1247 + extract_value: '(\d+)' # First capture group is used
1248 + ```
1249 +
1250 +- `scale_factor`
1251 + ```yaml
1252 + scale_factor: 8 # Octets → bits
1253 + ```
1254 +
1255 +### Mapping
1256 +
1257 +Use `mapping` to convert raw metric values into **state dimensions**.
1258 +
1259 +Each mapping entry defines a **dimension name** and the numeric or string value that triggers it.
1260 +
1261 +**The collector**:
1262 +
1263 +- Evaluates the value against the mapping table.
1264 +- For each mapping entry, creates a **dimension** named after the mapped key.
1265 +- Sets that dimension to `1` if the current value matches the key, or `0` otherwise.
1266 +- If the value doesn’t match any key, all mapped dimensions are `0`.
1267 +- Works only for **metric values**, not for tags or metadata.
1268 +
1269 +```yaml
1270 +metrics:
1271 + - OID: 1.3.6.1.2.1.2.2.1.7
1272 + name: ifAdminStatus
1273 + chart_meta:
1274 + description: Current administrative state of the interface
1275 + family: 'Network/Interface/Status/Admin'
1276 + unit: "{status}"
1277 + mapping:
1278 + 1: up
1279 + 2: down
1280 + 3: testing
1281 +```
1282 +
1283 +**What this does**:
1284 +
1285 +- Converts SNMP integer values (1, 2, 3) into a **multi-value metric** with dimensions `up`, `down`, and `testing`.
1286 +- The dimension corresponding to the current value reports `1`; all others report `0`.
1287 +
1288 +### Extract Value
1289 +
1290 +Use `extract_value` to extract a **numeric or string portion** from the raw SNMP value using a **regular expression**.
1291 +
1292 +This is often used when a metric is encoded as a string that contains numeric data (e.g. `"23.8 °C"`).
1293 +
1294 +**The collector**:
1295 +
1296 +- Applies the regular expression to the raw SNMP value.
1297 +- Uses the **first capture group** `( … )` as the new metric value.
1298 +- If the pattern doesn’t match, the original value is kept.
1299 +- Works for any metric type (string or numeric).
1300 +- When multiple `symbols` are defined, the first non-empty result is used.
1301 +
1302 +```yaml
1303 +metrics:
1304 + - MIB: CORIANT-GROOVE-MIB
1305 + table:
1306 + OID: 1.3.6.1.4.1.42229.1.2.3.1.1
1307 + name: shelfTable
1308 + symbols:
1309 + - OID: 1.3.6.1.4.1.42229.1.2.3.1.1.1.3
1310 + name: coriant.groove.shelfInletTemperature
1311 + # Example: "23.8 °C" → "23"
1312 + extract_value: '(\d+)'
1313 + chart_meta:
1314 + description: Shelf inlet temperature
1315 + family: 'Hardware/Shelf/Temperature/Inlet'
1316 + unit: "Cel"
1317 +```
1318 +
1319 +**What this does**:
1320 +
1321 +- Applies the regex `(\d+)` to the string `"23.8 °C"`.
1322 +- Extracts only the numeric part `"23"` and uses it as the metric value.
1323 +- If the value doesn’t match, the original string is retained.
1324 +- Ideal for string metrics that embed numbers, units, or labels.
1325 +
1326 +### Scale Factor
1327 +
1328 +Use `scale_factor` to **multiply collected metric values** by a constant.
1329 +
1330 +This transformation is typically used to convert between units (for example, bytes to bits).
1331 +
1332 +**The collector**:
1333 +
1334 +- Multiplies the raw SNMP value by the specified factor.
1335 +- Applies to both integer and floating-point values.
1336 +- Keeps the result in the same numeric type (integer or float).
1337 +- Works for **metric values only** (not for tags or metadata).
1338 +- Applies **after all other transformations** on the same metric (such as `extract_value`).
1339 +
1340 +```yaml
1341 +metrics:
1342 + - MIB: IP-MIB
1343 + table:
1344 + OID: 1.3.6.1.2.1.4.31.1
1345 + name: ipSystemStatsTable
1346 + symbols:
1347 + - OID: 1.3.6.1.2.1.4.31.1.1.6
1348 + name: ipSystemStatsHCInOctets
1349 + chart_meta:
1350 + description: Octets received in input IP datagrams
1351 + family: 'Network/IP/Traffic/Total/In'
1352 + unit: "bit/s"
1353 + scale_factor: 8 # Octets → bits
1354 +
1355 + - MIB: IF-MIB
1356 + symbol:
1357 + OID: 1.3.6.1.2.1.31.1.1.1.15
1358 + name: ifHighSpeed
1359 + chart_meta:
1360 + description: Estimate of the interface's current bandwidth
1361 + family: 'Network/Interface/Speed'
1362 + unit: "bit/s"
1363 + scale_factor: 1000000 # Megabits → bits
1364 +```
1365 +
1366 +**What this does**:
1367 +
1368 +- Multiplies octet counters by `8`, reporting traffic in **bits per second** instead of bytes.
1369 +- Converts `ifHighSpeed` from **megabits** to **bits**.
1370 +- Ensures scaling happens **after** other transformations, such as value extraction or regex processing.
1371 +
1372 +## Virtual Metrics
1373 +
1374 +- Virtual metrics are **calculated metrics** built from other metrics in your profile (or inherited ones).
1375 +- They don’t query SNMP; they **reuse existing metric values** to create totals, fallbacks, or per-row aggregations.
1376 +- Once computed, they behave like normal metrics: charted, tagged, and alertable.
1377 +
1378 +Common use cases:
1379 +
1380 +- **Fallbacks**: prefer 64-bit counters, fall back to 32-bit if missing.
1381 +- **Sums/Combines**: add related metrics (e.g., in + out traffic).
1382 +- **Per-row totals**: aggregate multiple columns into one per-interface metric.
1383 +
1384 +### Structure
1385 +
1386 +```yaml
1387 +virtual_metrics:
1388 + - name: <string>
1389 + sources:
1390 + - { metric: <metricName>, table: <tableName>, as: <dimensionName> }
1391 + # Optional: direct primary source set
1392 +
1393 + alternatives:
1394 + - sources:
1395 + - { metric: <metricNameA>, table: <tableName>, as: <dimensionName> }
1396 + - { metric: <metricNameB>, table: <tableName>, as: <dimensionName> }
1397 + - sources:
1398 + - { metric: <fallbackMetricA>, table: <tableName>, as: <dimensionName> }
1399 + - { metric: <fallbackMetricB>, table: <tableName>, as: <dimensionName> }
1400 +
1401 + per_row: <true|false>
1402 + group_by: <label | [labels]>
1403 + chart_meta:
1404 + description: ...
1405 + family: ...
1406 + unit: ...
1407 +```
1408 +
1409 +### Config reference
1410 +
1411 +| Item | Field | Type | Required | Default | Applies to | Description |
1412 +|--------------------|----------------|----------------------|----------|---------|--------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
1413 +| **Virtual Metric** | `name` | string | yes | — | all | Unique within the profile. Used as metric/chart base name. |
1414 +| | `sources` | array\<Source\> | no* | — | totals, per_row, grouped | Direct source set. Ignored if `alternatives` exist (alternatives take precedence). |
1415 +| | `alternatives` | array\<Alternative\> | no* | — | totals, per_row, grouped | Ordered fallback sets. The first alternative whose sources produce data is used. |
1416 +| | `per_row` | bool | no | false | per-row/grouped | When `true`, emits one output per input row; sources become dimensions; row tags attach. |
1417 +| | `group_by` | string / array | no | — | per-row/grouped | Label(s) used as row-key hints (in order). Missing/empty hints fall back to a full-tag stable key. With `per_row:false`, this acts like PromQL’s `sum by (...)`. |
1418 +| | `chart_meta` | object | no | — | all | Presentation metadata (`description`, `family`, `unit`, `type`). |
1419 +| **Source** | `metric` | string | yes | — | — | Name of an existing metric (scalar or table column metric). |
1420 +| | `table` | string | yes | — | — | Table name for the originating metric. Must match the metric’s table when used in per-row/grouped. |
1421 +| | `as` | string | yes | — | — | Dimension name within the composite (e.g., `in`, `out`). |
1422 +| **Alternative** | `sources` | array\<Source\> | yes | — | — | All sources in an alternative are evaluated together. If none produce data, the collector tries the next alternative. Per-row/group rules apply within the winning alternative. |
1423 +
1424 +> At least one of `sources` or `alternatives` **must be defined**.
1425 +
1426 +#### Rules & Constraints
1427 +
1428 +| Rule | Description |
1429 +|-----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
1430 +| **Precedence** | If both `sources` and `alternatives` exist, `alternatives` take precedence. |
1431 +| **Same-table requirement** | When `per_row` or `group_by` is used, all sources must originate from the same table. For alternatives, this rule applies within each alternative set. |
1432 +| **per_row: true** | One output per input row; multiple sources become chart dimensions (`as`); row tags attach automatically. |
1433 +| **group_by (with per_row:true)** | Acts as row-key hints (in order). Missing or empty hints fall back to a full-tag composite key. |
1434 +| **group_by (with per_row:false)** | Aggregates rows by the listed labels, similar to PromQL’s `sum by (...)`. |
1435 +| **Alternative evaluation** | Alternatives are checked in order. The first whose sources produce data becomes the “winner”; others are ignored. |
1436 +| **Parent metadata** | The virtual metric emits charts using its own `name` and `chart_meta`, even when data comes from an alternative. |
1437 +| **Dimensions** | Each `as` value defines a dimension in the resulting chart (e.g., `in`, `out`, `total`). |
1438 +| **Totals vs per-row** | Omitting both `per_row` and `group_by` produces a single total chart across all rows (device-wide view). |
1439 +
1440 +### Examples
1441 +
1442 +#### Per-row aggregation from one table (in + out traffic)
1443 +
1444 +```yaml
1445 +virtual_metrics:
1446 + - name: ifTotalTraffic
1447 + sources:
1448 + - { metric: _ifHCInOctets, table: ifXTable, as: in }
1449 + - { metric: _ifHCOutOctets, table: ifXTable, as: out }
1450 + per_row: true
1451 + group_by: ["interface"]
1452 + chart_meta:
1453 + description: Traffic per interface
1454 + family: 'Network/Interface/Traffic'
1455 + unit: "bit/s"
1456 +```
1457 +
1458 +**What this does**:
1459 +
1460 +- Creates **one output per input row** in `ifXTable`.
1461 +- Each chart represents one interface with two dimensions: `in` and `out`.
1462 +- `group_by: ["interface"]` provides key hints to keep per-interface charts stable.
1463 +- If a hint is missing or empty, a full-tag composite key is used instead.
1464 +- **Constraint**: `per_row` or `group_by` requires all sources to come from the same table.
1465 +
1466 +#### Total aggregation (sum across all interfaces)
1467 +
1468 +```yaml
1469 +virtual_metrics:
1470 + - name: ifTotalTraffic
1471 + sources:
1472 + - { metric: _ifHCInOctets, table: ifXTable, as: in }
1473 + - { metric: _ifHCOutOctets, table: ifXTable, as: out }
1474 + chart_meta:
1475 + description: Total traffic across all interfaces
1476 + family: 'Network/Total/Traffic'
1477 + unit: "bit/s"
1478 +```
1479 +
1480 +**What this does**:
1481 +
1482 +- Aggregates data from **all rows** in `ifXTable` into a **single chart**.
1483 +- Produces two dimensions (`in`, `out`) representing the total interface traffic for the entire device.
1484 +- No `per_row` or `group_by` fields → a single total chart (device-wide view).
1485 +
1486 +#### Grouped aggregation (sum by label)
1487 +
1488 +```yaml
1489 +virtual_metrics:
1490 + - name: ifTypeTraffic
1491 + sources:
1492 + - { metric: _ifHCInOctets, table: ifXTable, as: in }
1493 + - { metric: _ifHCOutOctets, table: ifXTable, as: out }
1494 + per_row: false
1495 + group_by: ["ifType"]
1496 + chart_meta:
1497 + description: Traffic aggregated by interface type
1498 + family: 'Network/InterfaceType/Traffic'
1499 + unit: "bit/s"
1500 +```
1501 +
1502 +**What this does**:
1503 +
1504 +- Performs **PromQL-like “sum by (ifType)” aggregation**.
1505 +- Combines all rows sharing the same `ifType` label into grouped totals.
1506 +- Result: one chart with `in` and `out` dimensions aggregated by interface type.
1507 +- **Constraint**: all sources must come from the same table.
1508 +
1509 +#### Alternatives (total; prefer 64-bit, fallback to 32-bit)
1510 +
1511 +```yaml
1512 +virtual_metrics:
1513 + - name: ifTotalPacketsUcast
1514 + alternatives:
1515 + - sources:
1516 + - { metric: _ifHCInUcastPkts, table: ifXTable, as: in }
1517 + - { metric: _ifHCOutUcastPkts, table: ifXTable, as: out }
1518 + - sources:
1519 + - { metric: _ifInUcastPkts, table: ifTable, as: in }
1520 + - { metric: _ifOutUcastPkts, table: ifTable, as: out }
1521 + chart_meta:
1522 + description: Total unicast packets across all interfaces (in/out)
1523 + family: 'Network/Total/Packet/Unicast'
1524 + unit: "{packet}/s"
1525 +```
1526 +
1527 +**What this does**:
1528 +
1529 +- Defines two **alternatives**, each as a list of sources.
1530 +- At runtime, the collector **picks the first alternative whose sources produce data** (HC first).
1531 +- Once a winner is found, **later alternatives are ignored**.
1532 +- The parent emits metrics using **its own** `name` and `chart_meta`, sourcing values from the selected child.
1533 +- If both `sources` and `alternatives` are present, `alternatives` take precedence.
1534 +
1535 +#### Composite (multi-source total: unicast/multicast/broadcast
1536 +
1537 +```yaml
1538 +virtual_metrics:
1539 + - name: ifTotalPacketsByKind
1540 + sources:
1541 + - { metric: _ifHCInUcastPkts, table: ifXTable, as: in_ucast }
1542 + - { metric: _ifHCOutUcastPkts, table: ifXTable, as: out_ucast }
1543 + - { metric: _ifHCInMulticastPkts, table: ifXTable, as: in_mcast }
1544 + - { metric: _ifHCOutMulticastPkts, table: ifXTable, as: out_mcast }
1545 + - { metric: _ifHCInBroadcastPkts, table: ifXTable, as: in_bcast }
1546 + - { metric: _ifHCOutBroadcastPkts, table: ifXTable, as: out_bcast }
1547 + chart_meta:
1548 + description: Total packets across all interfaces by kind (in/out)
1549 + family: 'Network/Total/Packet/ByKind'
1550 + unit: "{packet}/s"
1551 +```
1552 +
1553 +What this does
1554 +
1555 +- Builds a **single total chart** combining multiple related packet counters.
1556 +- Each `as` becomes a **dimension** (`in_ucast`, `out_ucast`, `in_mcast`, …).
1557 +- No `per_row`/`group_by` → totals aggregated across all interfaces.