Skip to main content

SNMP

The OpenTelemetry Collector's snmpreceiver polls SNMP-speaking devices over UDP, converts enterprise and standard MIB OIDs to named metrics, and exports OTLP to base14 Scout. Use it for network gear (routers, switches, firewalls), power infrastructure (UPSes, PDUs), printers, and any host running net-snmp. This guide configures three representative device profiles — a Linux host, a Cisco-style router, and an APC-style UPS — and ships the metrics upstream.

The same pattern generalises to any SNMPv1/v2c/v3-capable device. Because snmpreceiver is poll-only, it is particularly well suited to monitoring infrastructure that cannot run agents itself — which makes SNMP a natural bridge into broader IoT and OT telemetry work.

Prerequisites

RequirementMinimumRecommended
SNMP versionv1v2c or v3
OTel Collector Contrib0.90.00.153.0
Target devicesSNMP-enabledSNMPv2c/v3 with community or user configured
base14 ScoutAny-

Before starting:

  • Devices must be reachable over UDP/161 from the Collector host
  • A read-only community string (v1/v2c) or SNMPv3 user with appropriate auth/priv keys
  • OTel Collector installed — see Docker Compose Setup

What You'll Monitor

snmpreceiver has no fixed metric set. Each metric below exists because the config maps an OID — scalar or column — to an OTel dotted name with an explicit unit and type, so the emitted set IS the config; you choose the names when you map each OID. The tiers are organised by how you use the metrics across three device classes: [net] for the router, [ups] for the UPS, [host] for the Linux host.

Four things shape how this surface reads, regardless of device:

  • There is no up series and no health metric. Liveness is the receiver scraping the device successfully — the device answering its OIDs. A sustained scrape error in the Collector log is the device-unreachable signal.
  • Two metric types. network.io and network.errors are monotonic cumulative sums (interface octet/error counters, each carrying a direction attribute); everything else is a gauge.
  • One endpoint per receiver instance. Use one snmp/<device> block per device (or per device class sharing credentials). Each pipeline stamps a distinct service.name, so every device appears as its own service in Scout. Column OIDs fan out to one resource per row — network.interface.name from ifName, cpu.index from the hrProcessorTable.
  • Static labels come from a processor, not the receiver. device.kind (compute / network / power), device.manufacturer, device.model.identifier, and site.id are added by a resource processor — snmpreceiver can only attach values it actually fetches over SNMP.

Several MIBs store fixed-point values as scaled integers: system.cpu.load_average.* is laLoadInt (×100), ups.battery.runtime_remaining is TimeTicks (centiseconds, not seconds), and some PowerNet frequencies use units of 0.1 Hz. Rescale these in the backend or a transform processor; do not assume base units.

The per-device-class headline pair: link state plus throughput for the router, output state plus battery runway for the UPS, load plus available memory for the host.

MetricTypeClassWhat it tells you
network.interface.oper_statusgauge[net]Operational link state (1=up, 2=down, …) — the outage signal.
network.iosum[net]Per-interface bytes in/out (ifHCOctets) — headline throughput.
ups.output.statusgauge[ups]2=onLine, 3=onBattery, … — the utility-power-lost signal.
ups.battery.capacitygauge[ups]Remaining battery capacity (%) — the runway.
system.cpu.load_average.1mgauge[host]1-minute load average ×100 — headline host load.
system.memory.availablegauge[host]Available real memory (KiB) — headline host memory.

Operational - what to alert on

The error counters, status/replace enums, voltage and load readings, and the saturation denominators (network.interface.speed, system.memory.total) the Core numbers are read against.

MetricTypeClassWhat it tells you
network.errorssum[net]Interface in/out errors — rising = a link or cabling problem.
network.interface.admin_statusgauge[net]Administrative state (1=up, 2=down) — compare with oper_status.
network.interface.speedgauge[net]Nominal speed (Mbit/s) — denominator for saturation.
ups.battery.statusgauge[ups]1=unknown, 2=normal, 3=low (replace is the separate ups.battery.replace_indicator).
ups.battery.replace_indicatorgauge[ups]2=battery needs replacing.
ups.battery.runtime_remaininggauge[ups]Estimated runtime (centiseconds, TimeTicks).
ups.input.voltagegauge[ups]Input line voltage (V) — utility quality.
ups.output.loadgauge[ups]Output load (% of rated capacity) — overload risk.
system.cpu.utilizationgauge[host]Per-CPU utilization (%, per-core fan-out).
system.cpu.load_average.5mgauge[host]5-minute load average ×100.
system.cpu.load_average.15mgauge[host]15-minute load average ×100.
system.memory.totalgauge[host]Total real memory (KiB) — denominator for memory pressure.
system.processes.countgauge[host]Running process count.

Diagnostic - for investigation and tuning

Inventory and second-order context. Reach for these during an incident or a capacity review.

MetricTypeClassWhat it tells you
system.network.interfaces.countgauge[net]ifNumber — interface inventory.
system.users.countgauge[host]Active user sessions.
system.memory.cachedgauge[host]Cached memory (KiB).
system.memory.bufferedgauge[host]Buffered memory (KiB).
ups.battery.temperaturegauge[ups]Battery temperature (Cel).
ups.input.frequencygauge[ups]Input line frequency (Hz).
ups.output.voltagegauge[ups]Output voltage (V).
ups.output.currentgauge[ups]Output current (A).

Full receiver reference: OTel SNMP Receiver.

The runnable example with a built-in SNMP simulator lives at base14/examples — components/snmp-telemetry. It ships three simulated devices (communities linux-host, cisco-router, apc-ups) on udp://snmpsim:1161, so the config below works unchanged against the simulator if you swap the real endpoints for that address.

Key Alerts to Configure

The state reads below — oper_status == 2, output.status == 3, battery.status == 3, replace_indicator == 2 — are MIB-defined enum values, not invented thresholds. Everything else is relative to your own baseline or the device's own rating; tune to your fleet.

AlertConditionWhy it matters
Link down (unplanned)network.interface.oper_status == 2 while network.interface.admin_status == 1The interface is administratively up but operationally down — an unplanned outage, not a config change.
Interface errors risingrate(network.errors) > 0 / rising vs baselineErrors climbing point to a link, duplex, or cabling fault.
Interface saturationnetwork.io rate approaching network.interface.speedThe link is near its nominal capacity; expect drops and queueing.
UPS on batteryups.output.status == 3 (onBattery)Utility power is lost; the load is now on battery runway.
UPS battery low / replaceups.battery.status == 3 or ups.battery.replace_indicator == 2The battery is degraded or end-of-life; schedule a replacement.
UPS battery runway shortups.battery.capacity dropping vs baseline / ups.battery.runtime_remaining fallingRemaining runtime is shrinking; plan a graceful shutdown before it hits zero.
UPS overloadups.output.load high vs the unit's rated capacityThe UPS is carrying more than it should; shed load or upgrade.
Host memory pressuresystem.memory.available dropping vs baselineFree real memory is shrinking toward swap or OOM.
Host CPU saturationsystem.cpu.load_average.1m rising above the core countSustained load above the core count means the run queue is backing up.
Device unreachablesustained snmpreceiver scrape errors / no data for the deviceThe device stopped answering its OIDs — there is no up series, so the scrape error is the liveness signal.

Access Setup

No code runs on the device. All you need is SNMP read access.

SNMPv2c — enable snmpd and set a read-only community:

/etc/snmp/snmpd.conf (Linux)
rocommunity readonly_community_here default
sysLocation "rack-A1, row-3"
sysContact "ops@example.com"

Then restart snmpd and test from the host that will run the Collector:

snmpwalk -v2c -c readonly_community_here -t 2 target-host:161 \
1.3.6.1.2.1.1.1

SNMPv3 — prefer authPriv with SHA/AES:

/etc/snmp/snmpd.conf
createUser monitor SHA "auth-key-here" AES "priv-key-here"
rouser monitor priv

For network gear, the vendor CLI equivalents apply (Cisco snmp-server community, Junos snmp { community }, etc.). Always scope communities and SNMPv3 users to the Collector host's source address when the device supports it.

Configuration

The snmpreceiver takes one endpoint per receiver instance, so use one instance per device (or per device class sharing credentials). Metrics are defined by OID with an explicit unit and either scalar_oids (values ending in .0) or column_oids (indexed tables). Table rows fan out to separate resources via resource_attributes.

config/otel-collector.yaml
receivers:
snmp/linux:
collection_interval: 30s
endpoint: udp://linux-host.internal:161
version: v2c
community: ${env:SNMP_COMMUNITY_LINUX}

resource_attributes:
device.id:
scalar_oid: "1.3.6.1.2.1.1.5.0" # sysName
cpu.index:
indexed_value_prefix: "cpu_"

metrics:
system.processes.count:
description: Number of processes running (hrSystemProcesses)
unit: "{processes}"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.2.1.25.1.6.0"

system.users.count:
description: Active user sessions (hrSystemNumUsers)
unit: "{users}"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.2.1.25.1.5.0"

system.memory.total:
description: Total real memory (UCD memTotalReal)
unit: KiBy
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.2021.4.5.0"

system.memory.available:
description: Available real memory (UCD memAvailReal)
unit: KiBy
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.2021.4.6.0"

system.memory.cached:
description: Cached memory (UCD memCached)
unit: KiBy
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.2021.4.11.0"

system.memory.buffered:
description: Buffered memory (UCD memBuffer)
unit: KiBy
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.2021.4.14.0"

system.cpu.load_average.1m:
description: "1-minute load average x 100 (UCD laLoadInt.1)"
unit: "1"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.2021.10.1.5.1"

system.cpu.load_average.5m:
description: "5-minute load average x 100 (UCD laLoadInt.2)"
unit: "1"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.2021.10.1.5.2"

system.cpu.load_average.15m:
description: "15-minute load average x 100 (UCD laLoadInt.3)"
unit: "1"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.2021.10.1.5.3"

system.cpu.utilization:
description: Per-CPU utilization (hrProcessorLoad)
unit: "%"
gauge: { value_type: int }
column_oids:
- oid: "1.3.6.1.2.1.25.3.3.1.2"
resource_attributes: [cpu.index]

snmp/router:
collection_interval: 30s
endpoint: udp://edge-router.internal:161
version: v2c
community: ${env:SNMP_COMMUNITY_ROUTER}

resource_attributes:
device.id:
scalar_oid: "1.3.6.1.2.1.1.5.0"
network.interface.name:
oid: "1.3.6.1.2.1.31.1.1.1.1" # ifName

attributes:
direction:
enum: [receive, transmit]

metrics:
system.network.interfaces.count:
description: Number of network interfaces (IF-MIB ifNumber)
unit: "{interfaces}"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.2.1.2.1.0"

network.io:
description: Interface I/O bytes (ifHCInOctets / ifHCOutOctets)
unit: By
sum:
value_type: int
monotonic: true
aggregation: cumulative
column_oids:
- oid: "1.3.6.1.2.1.31.1.1.1.6"
resource_attributes: [network.interface.name]
attributes:
- { name: direction, value: receive }
- oid: "1.3.6.1.2.1.31.1.1.1.10"
resource_attributes: [network.interface.name]
attributes:
- { name: direction, value: transmit }

network.errors:
description: Interface errors (ifInErrors / ifOutErrors)
unit: "{errors}"
sum:
value_type: int
monotonic: true
aggregation: cumulative
column_oids:
- oid: "1.3.6.1.2.1.2.2.1.14"
resource_attributes: [network.interface.name]
attributes:
- { name: direction, value: receive }
- oid: "1.3.6.1.2.1.2.2.1.20"
resource_attributes: [network.interface.name]
attributes:
- { name: direction, value: transmit }

network.interface.speed:
description: Interface nominal speed (ifHighSpeed)
unit: "Mbit/s"
gauge: { value_type: int }
column_oids:
- oid: "1.3.6.1.2.1.31.1.1.1.15"
resource_attributes: [network.interface.name]

network.interface.admin_status:
description: "ifAdminStatus - 1=up, 2=down, 3=testing"
unit: "1"
gauge: { value_type: int }
column_oids:
- oid: "1.3.6.1.2.1.2.2.1.7"
resource_attributes: [network.interface.name]

network.interface.oper_status:
description: "ifOperStatus - 1=up, 2=down, 3=testing, 4=unknown, 5=dormant"
unit: "1"
gauge: { value_type: int }
column_oids:
- oid: "1.3.6.1.2.1.2.2.1.8"
resource_attributes: [network.interface.name]

snmp/ups:
collection_interval: 30s
endpoint: udp://ups-dc01.internal:161
version: v2c
community: ${env:SNMP_COMMUNITY_UPS}

resource_attributes:
device.id:
scalar_oid: "1.3.6.1.2.1.1.5.0"

metrics:
ups.battery.status:
description: "Battery status - 1=unknown, 2=normal, 3=low"
unit: "1"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.2.1.1.0"

ups.battery.capacity:
description: Remaining battery capacity (upsAdvBatteryCapacity)
unit: "%"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.2.2.1.0"

ups.battery.temperature:
description: Battery temperature (upsAdvBatteryTemperature)
unit: "Cel"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.2.2.2.0"

ups.battery.runtime_remaining:
description: Estimated runtime remaining, centiseconds (TimeTicks)
unit: "cs"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.2.2.3.0"

ups.battery.replace_indicator:
description: "1=no replacement needed, 2=battery needs replacement"
unit: "1"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.2.2.4.0"

ups.input.voltage:
description: Input line voltage (upsAdvInputLineVoltage)
unit: "V"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.3.2.1.0"

ups.input.frequency:
description: Input line frequency (upsAdvInputFrequency)
unit: "Hz"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.3.2.4.0"

ups.output.status:
description: "Output status - 2=onLine, 3=onBattery, 4=onSmartBoost, ..."
unit: "1"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.4.1.1.0"

ups.output.voltage:
description: Output voltage (upsAdvOutputVoltage)
unit: "V"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.4.2.1.0"

ups.output.load:
description: Output load as percent of rated capacity
unit: "%"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.4.2.3.0"

ups.output.current:
description: Output current (upsAdvOutputCurrent)
unit: "A"
gauge: { value_type: int }
scalar_oids:
- oid: "1.3.6.1.4.1.318.1.1.1.4.2.4.0"

processors:
memory_limiter:
check_interval: 5s
limit_percentage: 80
spike_limit_percentage: 25

batch:
timeout: 10s
send_batch_size: 1024

# Static metadata per pipeline. snmpreceiver only attaches values
# it can retrieve via SNMP; constants like service.name and
# device.kind are added here. Each device gets a distinct
# service.name so it appears as its own service in Scout.
resource/linux:
attributes:
- { key: service.name, value: "linux-host-01", action: insert }
- { key: service.namespace, value: ${env:SERVICE_NAMESPACE}, action: insert }
- { key: deployment.environment.name, value: ${env:ENVIRONMENT}, action: insert }
- { key: environment, value: ${env:ENVIRONMENT}, action: insert }
- { key: device.kind, value: compute, action: insert }
- { key: device.manufacturer, value: "generic-linux", action: insert }
- { key: device.model.identifier, value: "net-snmp", action: insert }
- { key: site.id, value: ${env:SITE_ID}, action: insert }

resource/router:
attributes:
- { key: service.name, value: "cisco-router-01", action: insert }
- { key: service.namespace, value: ${env:SERVICE_NAMESPACE}, action: insert }
- { key: deployment.environment.name, value: ${env:ENVIRONMENT}, action: insert }
- { key: environment, value: ${env:ENVIRONMENT}, action: insert }
- { key: device.kind, value: network, action: insert }
- { key: device.manufacturer, value: "cisco", action: insert }
- { key: device.model.identifier, value: "ISR-C2900", action: insert }
- { key: site.id, value: ${env:SITE_ID}, action: insert }

resource/ups:
attributes:
- { key: service.name, value: "apc-ups-01", action: insert }
- { key: service.namespace, value: ${env:SERVICE_NAMESPACE}, action: insert }
- { key: deployment.environment.name, value: ${env:ENVIRONMENT}, action: insert }
- { key: environment, value: ${env:ENVIRONMENT}, action: insert }
- { key: device.kind, value: power, action: insert }
- { key: device.manufacturer, value: "apc", action: insert }
- { key: device.model.identifier, value: "Smart-UPS-SRT", action: insert }
- { key: site.id, value: ${env:SITE_ID}, action: insert }

exporters:
otlphttp/b14:
endpoint: ${env:OTEL_EXPORTER_OTLP_ENDPOINT}
tls:
insecure_skip_verify: true

service:
pipelines:
metrics/linux:
receivers: [snmp/linux]
processors: [memory_limiter, resource/linux, batch]
exporters: [otlphttp/b14]
metrics/router:
receivers: [snmp/router]
processors: [memory_limiter, resource/router, batch]
exporters: [otlphttp/b14]
metrics/ups:
receivers: [snmp/ups]
processors: [memory_limiter, resource/ups, batch]
exporters: [otlphttp/b14]

Environment Variables

.env
SNMP_COMMUNITY_LINUX=readonly_community_here
SNMP_COMMUNITY_ROUTER=readonly_community_here
SNMP_COMMUNITY_UPS=readonly_community_here

# Service identity — each device pipeline stamps its own service.name
# (linux-host-01 / cisco-router-01 / apc-ups-01). These env vars
# apply to all three.
SERVICE_NAMESPACE=network-infra
ENVIRONMENT=demo
SITE_ID=your-site-id

OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.<your-tenant>.base14.io

Every metric carries a service.name/service.namespace/environment set and the IoT device schema: device.id, device.kind (compute / network / power), device.manufacturer, device.model.identifier, site.id. Network gear is a compute device with device.kind=network — there is no separate network.device.* namespace. Each simulated (or real) device appears as its own service in Scout because each receiver pipeline stamps a distinct service.name.

Semconv version note: deployment.environment.name is the current OTel attribute (introduced in semantic conventions v1.27.0, stable as of v1.41.0). Scout's UI filters on the lowercase environment key, so emit it alongside the OTel-native deployment.environment.name. The legacy deployment.environment is still accepted for backward compatibility.

Shipping via a Local Scout Collector

The otlphttp/b14 exporter above ships directly to Scout. If you already run a tenant-local Scout Collector — recommended when you have multiple apps on the same host, need local buffering, or want a single point of auth — forward metrics to it instead:

config/otel-collector.yaml (alternative)
exporters:
otlphttp/upstream:
endpoint: http://otel-collector-base14:4318

Then join the Scout Collector's Docker network so DNS resolves the container name:

docker-compose.yaml
services:
otel-collector:
# ...
networks:
- default
- otel-collector-network

networks:
otel-collector-network:
external: true

For setting up that upstream Scout Collector, see Docker Compose Setup.

Verify the Setup

Start the Collector and check for successful scrapes within 60 seconds. From the host running the Collector:

# Probe each device reachability and credentials
snmpwalk -v2c -c "$SNMP_COMMUNITY_LINUX" -t 2 linux-host.internal:161 1.3.6.1.2.1.1.1
snmpwalk -v2c -c "$SNMP_COMMUNITY_ROUTER" -t 2 edge-router.internal:161 1.3.6.1.2.1.31.1.1.1.6
snmpwalk -v2c -c "$SNMP_COMMUNITY_UPS" -t 2 ups-dc01.internal:161 1.3.6.1.4.1.318.1.1.1.2.2

# Confirm the Collector emitted metrics
docker logs otel-collector 2>&1 | grep -E 'Name: (network\.io|ups\.|system\.)'

Troubleshooting

no such host or DNS lookup failures

Cause: The Collector cannot resolve the device hostname, or a Docker network isolates it from the device.

Fix:

  1. Use an IP literal in endpoint if DNS is not available inside the Collector container
  2. On Docker Desktop, use host.docker.internal to reach services on the host
  3. Run the Collector with network_mode: host if the target is on the host's network segment

Request timeout on scrape

Cause: Device is slow to respond, or UDP packets are being dropped.

Fix:

  1. Raise timeout: 10s on the receiver block
  2. Lower collection_interval pressure if the device is resource- constrained (default 30s is usually fine)
  3. Verify UDP/161 is not blocked by an ACL or firewall between Collector and device

No Such Instance for Counter64 OIDs

Cause: The device does not support the ifXTable (IF-MIB high-capacity counters), common on older hardware.

Fix:

Fall back to 32-bit counters:

column_oids:
- oid: "1.3.6.1.2.1.2.2.1.10" # ifInOctets (Counter32)
resource_attributes: [network.interface.name]
attributes:
- { name: direction, value: receive }

Expect wraparound on high-throughput interfaces; as a Counter32 in octets, ifInOctets wraps at 2^32 bytes (~4 GiB), so a busy link can roll over in seconds.

Metric values look wrong by a factor of 10 or 100

Cause: Several MIBs store fixed-point values as scaled integers (for example, UCD laLoadInt uses ×100; PowerNet upsAdvOutputFrequency uses units of 0.1 Hz). upsAdvBatteryRunTimeRemaining is a TimeTicks value — centiseconds, not seconds — so a 30-minute runtime reads as 180000. The Operational ups.battery.runtime_remaining and the Diagnostic ups.input.frequency are the series this most often bites.

Look at: the raw system.cpu.load_average.* and ups.battery.runtime_remaining values against what the device's own CLI reports — a clean ×100 or centisecond offset confirms it is a scaling issue, not a bad OID.

Fix:

  1. Check the MIB definition for the OID's UNITS clause
  2. Document the scale in the metric description, or
  3. Apply a transform processor to rescale before export

Scrape errors flood the log during a device outage

Cause: The receiver logs each failed scrape at error level. With no up series, a sustained run of these entries is the device-unreachable signal.

Look at: whether the affected pipeline's metrics go stale in Scout (network.io, ups.output.status, or system.memory.available stop updating) — that, alongside the scrape errors, confirms the device is down rather than a transient packet drop.

Fix:

The Collector pipeline keeps running — the error entries are expected and recoverable. To quiet them, increase collection_interval for the flaky receiver, or route the Collector's own logs through a filter/logs processor that drops snmp scrape errors.

FAQ

Does this work with SNMPv3?

Yes. Set version: v3 and provide user, security_level, auth_type, auth_password, privacy_type, and privacy_password as appropriate. Prefer authPriv with SHA-256 and AES-256 on production gear.

How do I monitor many similar devices without repeating YAML?

snmpreceiver does not have a native templating feature, but the Collector config can be rendered from a template (Jinja, envsubst, Helm). Generate one snmp/<device> block per target and share the metric definitions via YAML anchors, or manage the config as code and let the generator emit identical metric blocks.

Can I receive SNMP traps with this receiver?

No. snmpreceiver is poll-only, and the Collector has no SNMP-trap receiver (the request to add one was declined). To capture traps, forward them into the Collector as logs via snmptrapd + a file or syslog receiver.

What's the difference between using scalar_oid vs oid under resource_attributes?

scalar_oid fetches a single value (must end in .0) and stamps every metric from this receiver with it — use it for device-wide attributes like device.id from sysName. oid points to a column and produces per-index resources — use it for things that vary per row like interface names.

Why is device.kind set by a processor and not the receiver?

snmpreceiver can only attach values it fetches over SNMP. Static labels like device.kind=network don't exist on the device, so we add them with a resource processor scoped to each device pipeline. This keeps each pipeline self-contained.

Can I map string values (DisplayString) to numeric metrics?

No. A numeric metric needs a numeric SNMP type (Integer, Counter*, Gauge32, TimeTicks); snmpreceiver can read a DisplayString only as a resource-attribute value, not as a metric. If a MIB returns a DisplayString like UCD laLoad ("0.21"), switch to the integer-scaled sibling OID (laLoadInt, ×100) and document the scaling in the metric description.

Does polling add significant load on devices?

A 30-second collection_interval against a dozen scalar OIDs and a single interface table is negligible for modern network gear. For very large ifTable walks on older devices, raise the interval or reduce the column list.

What's Next?

  • Create Dashboards: Start with interface throughput, CPU load, and UPS battery capacity panels. See Create Your First Dashboard
  • Add more devices: Drop in a switch MIB, a PDU MIB, or a printer MIB — the snmpreceiver pattern is the same. The runnable example at components/snmp-telemetry shows how to add a fourth device.
  • Broaden IoT coverage: SNMP is the first hop into IoT monitoring. See the IoT & Edge instrumentation guides for MQTT, Sparkplug B, and OPC-UA paths when you need protocols SNMP cannot reach.
Was this page helpful?