Skip to main content

IoT & Edge Observability

IoT and edge systems break the assumptions most observability tooling is built on. Devices are constrained, links are intermittent, fleets are large, and the thing emitting telemetry is often not the thing being measured. These guides cover instrumenting that world with OpenTelemetry and shipping the signals to base14 Scout, vendor-neutral and OTLP-native from the device up.

Why IoT is different

A web service has a stable host, a fast network, and an SDK that speaks OTLP natively. An IoT estate has none of those guarantees:

  • Constrained devices. Microcontrollers have kilobytes of RAM and no room for a full OTLP/HTTP + protobuf stack. There is no OpenTelemetry C SDK and no MCU story today, so the device-to-edge hop needs a compact, transport-friendly encoding.
  • Intermittent connectivity. Cellular and radio links drop. Spans and metrics have to be buffered at the edge and forwarded on reconnect, with clock-skew repair so late data lands on the right timeline.
  • Fleet scale and proxy identity. Thousands of devices report through a handful of gateways. When a gateway speaks for a device, the telemetry has to carry whose signal it is, which the current semantic conventions do not express.
  • Industrial protocols. OPC-UA and Sparkplug B dominate the factory floor, and neither has a Collector receiver in contrib. Bridging them to OTLP is on you until that lands upstream.

The state of OpenTelemetry for IoT

The ecosystem is early here, and these guides are built around the gaps rather than pretending they do not exist:

  • No protocol receivers. Contrib ships snmpreceiver plus the generic log receivers, but no MQTT, CoAP, OPC-UA, or Sparkplug B receiver. The bridge examples in this track are the workaround, and a working model for the receiver these protocols still lack. Each bridge is built so that swapping in a future receiver is a deletion, not a rewrite: declarative mapping, state held explicitly, and instruments created the way a receiver would. The clean end state is an mqttreceiver that subscribes and decodes, paired with protocol-specific processors for the stateful work; until that lands, the bridges stand in.
  • No constrained-device SDK. The embedded C effort is not active in the OpenTelemetry org, and the C++ and Rust embedded tracks are unresolved. Firmware emits a compact payload that an edge Collector translates into OTLP.
  • No fleet or device semantic-convention group. Firmware version, provisioning identity, gateway hop, battery, and signal strength are all undefined upstream. The conventions below are Scout's working schema until that group exists.
  • No canonical end-to-end example. There is no IoT equivalent of the OpenTelemetry demo. This track is one, built phase by phase, from a microcontroller through the edge to Scout.

Guides in this track

Each phase ships a runnable example and a guide. Every example runs locally with Docker, no cloud account required.

PhaseGuideWhat it coversStatus
1MQTT trace context propagationTrace context flowing across an MQTT 5 broker via user properties, visualized as one end-to-end trace in Scout.Available
2Edge Collector patternsDisk-buffered store-and-forward, interval downsampling, priority routing, and battery-aware filtering at the edge, surviving simulated disconnects.Available
3OPC-UA to OTel bridgeA bridge that subscribes to an OPC-UA server and emits OTLP metrics with industrial asset attributes, fault logs, and session spans.Available
4Sparkplug B decoderDecoding NBIRTH / DBIRTH / DDATA into OTLP metrics with device lifecycle state and sequence-gap detection.Available
5ESP32 firmware to OTelConstrained-device firmware (ESP-IDF, C) emitting a compact SME-v1 JSON payload over MQTT, bridged to OTLP and shipped through an edge Collector.Available
Flagship example

Phase 5 is the constrained-device payoff: a real ESP32 firmware emitting OpenTelemetry in a world with no C SDK. If you want the end-to-end constrained-device story - on-device trace context, a versioned wire envelope, and a bridge to OTLP - start there.

Resource attributes we use

Consistency across the phases above matters more than waiting for upstream alignment, so the schema is locked here before any example uses it. These are Scout conventions pending upstream discussion, not ratified semantic conventions. Where an attribute reuses an existing convention it is noted; the rest are proposed for a future device.* / fleet.* working group, justified by the concrete usage these examples provide.

Compute devices (device.*)

Sensors, microcontrollers, gateways, and network gear.

AttributeMeaning
device.idUnique device identifier. Upstream device.id is opt-in under recent semconv; Scout treats it as opt-in by default.
device.manufacturerDevice maker (existing mobile-origin attribute).
device.model.identifierModel identifier (existing mobile-origin attribute).
device.serialHardware serial number.
device.firmware.versionRunning firmware version.
device.firmware.channelRelease channel, e.g. stable / beta.
device.power.sourcePower source, e.g. mains / battery.
device.battery.levelBattery level where applicable.
device.provisioning.methodHow the device obtained its identity.
device.kindDiscriminator: sensor | gateway | mcu | network.

Fleet (fleet.*)

AttributeMeaning
fleet.idFleet the device belongs to.
fleet.tenantOwning tenant.
fleet.prioritycritical | high | normal | low. Used by edge filters.

Gateway (gateway.*)

AttributeMeaning
gateway.idGateway the device reports through.
gateway.hopHop count from device to backend.

Network (network.*)

AttributeMeaning
network.signal.rssiReceived signal strength.

Physical assets (asset.*)

Pumps, conveyors, ovens, and lines, distinct from compute devices.

AttributeMeaning
asset.idUnique identifier for the physical asset.
asset.typepump | conveyor | oven | line | ...
asset.nameHuman-readable label.
asset.parent_idParent asset, for hierarchy chains.

Asset hierarchy is expressed with asset.parent_id chains. Do not introduce ad-hoc grouping attributes such as asset.group, asset.edge_node, or asset.line; encode those relationships as asset.parent_id instead.

Site (site.*)

AttributeMeaning
site.idPhysical location identifier.
site.nameHuman-readable location name.

Next steps

The MQTT trace-propagation guide is the entry point and a prerequisite for the Sparkplug and ESP32 phases. All five phases are live; the table above links each. For shipping the resulting telemetry, see the OpenTelemetry Collector Setup guides and Scout exporter wiring.

Was this page helpful?