Logging
Comprehensive description of Spotflow logging including technical details.
Spotflow provides an end-to-end logging solution designed specifically for embedded devices.
This page walks you through all the aspects related to Spotflow logging, from integrating it into devices, through understanding the transport protocol, to analyzing and troubleshooting logs in the web application.
Getting Started with Device Integration
Guide: Zephyr or Nordic nRF Connect SDK
Spotflow offers native integration for devices running Zephyr and Nordic nRF Connect SDK through a lightweight software module. This module integrates seamlessly with your existing logging infrastructure - simply add it as a dependency and use the standard logging macros you're already familiar with.
For devices running other platforms or when you cannot use Spotflow device module, integration is also possible via standard MQTT interface. Spotflow platform exposes scalable MQTT broker accessible anywhere from the Internet that can be used to ingest logs. See Transport Protocol section for details.
Transport Protocol
Spotflow uses an optimized transport protocol based on TCP, MQTT and TLS and two serialization formats (CBOR and JSON).
MQTT over TLS
All log transmission uses MQTT over TLS (MQTTS) for secure, reliable communication:
- TLS Version: 1.2 or higher
- Certificate: Let's Encrypt ISRG Root X1 (pre-installed on many systems or included in Spotflow SDKs)
- Authentication: Devices authenticate using ingest keys as MQTT passwords and their unique device IDs as MQTT usernames.
Serialization format
There are two flavours of the protocol, differing in their serialization format:
- CBOR-based: recommended for maximum memory and bandwidth efficiency. Used by Spotflow Zephyr Module.
- JSON-based: recommended for maximum simplicity and interoperability between platforms.
Log Message Format - CBOR
CBOR (Concise Binary Object Representation) is very memory and bandwidth efficient binary serialization format. We recommend using CBOR to achieve maximum efficiency for embedded devices with limited bandwidth and processing power.
Spotflow Zephyr module uses CBOR to serialize log messages with optimized, single byte field identifiers and constant values to reduce overhead.
The log messages follow the following CDDL schema:
log-message = {
? 1 => tstr, ; body: fully interpolated log line string (optional when bodyTemplate is used)
? (
2 => tstr, ; bodyTemplate (optional): printf-like interpolation string
3 => body-template-values ; bodyTemplateValues (optional): values for interpolation
),
? 4 => severity, ; severity (recommended)
? 5 => labels, ; labels (optional): user-defined key-value pairs for additional context
? 6 => uint, ; deviceUptimeMs (optional): device uptime in milliseconds in range [0, 2^63 - 1]
? 7 => uint ; deviceTimestampMs (optional): device timestamp in milliseconds in range [0, 2^63 - 1]
}
labels = {* (tstr => (tstr / int / float / bool))} ; Strongly typed key-value pairs
; Integer severity values
debug-severity = 30
info-severity = 40
warning-severity = 50
error-severity = 60
critical-severity = 70
severity = (debug-severity / info-severity / warning-severity / error-severity / critical-severity)
; A strongly typed array of values, or an array of byte string representations (big-endian) of the values
body-template-values = [ * (tstr / int / float / bool / null) ] / [ * bstr ]
Log Message Format - JSON
JSON (JavaScript Object Notation) is a lightweight data interchange format that's easy for humans to read and write. While not as efficient as CBOR, JSON is widely used and supported across different platforms.
We recommend using JSON for custom MQTT implementations, when maximum simplicity and interoperability is required while higher bandwidth is acceptable.
The log messages follow the following JSON structure:
{
// Fully interpolated log line string (optional when bodyTemplate is used)
"body": "SmartLock was Unlocked",
// (Optional) printf-like interpolation string for the log line
"bodyTemplate": "SmartLock was %s",
// (Optional) array of values for interpolation in the bodyTemplate
"bodyTemplateValues": ["Unlocked"],
// (Recommended) Log severity, possible values: "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
"severity": "INFO",
// (Optional) device uptime when the log was generated (milliseconds since the device booted)
"deviceUptimeMs": 23455,
// (Optional) time when the log was generated (milliseconds since the UNIX epoch)
"deviceTimestampMs": 1748530133808,
// (Optional) you can add extra metadata to your logs
"labels": {
"initiatorKind": "MobileApp",
"userId": "1234567890"
}
}
Device ID
Ideally, each physical device should use its own unique device ID for log ingestion (possibly even its own Ingestion Key). However, we know that mistakes in device provisioning and configuration can happen so our transmission protocol is robust to multiple devices using the same device ID at the same time. In such cases, the devices will still to send logs to Spotflow without disruption.
At least once delivery
Once a log message is ingested by our MQTT broker, we guarantee that the message will be processed and made available for querying. No data loss is tolerated after acceptance. However, depending on the MQTT QoS level used for publishing, some messages might get lost before they are ingested by the broker.
Analyze Logs in the Web Application
Once your device is integrated and sending logs, you can analyze them in the web application. The main entry point is the Events page, which gives you a comprehensive view of all events collected from your devices. There, you can filter logs by their content, device ID, severity, and other metadata.

You can click on individual log messages to see their details, and it is possible to drill down into specific events by matching their metadata.

Learn more
How is this guide?