First published: Last updated:
Prior Work
Originally published in Japanese at https://zenn.dev/ymotongpoo/books/tinygo-otel-esp32/viewer/10-prior-art.
This book is not the first attempt to send OpenTelemetry telemetry from an ESP32. This chapter takes up three cases. For each one, it checks what the authors did and where they ran into the same constraints as this book. All three work in C or C++ environments.
ClickHouse’s espresso machine
The ClickHouse blog post “Instrumenting my espresso machine with OpenTelemetry” (July 2026) describes how the author instrumented the control board of an espresso machine with OpenTelemetry. The machine contains GaggiMate, an open source control board that runs on an ESP32. Over OTLP, it sends traces and metrics to ClickHouse Cloud. In the traces, one shot is the parent span, and each stage of the shot is a child span. The metrics include the boiler temperature and pressure.
The first obstacle in the post is that the OTLP protobuf schema is too large. The post says that the author fed the official OTLP definitions directly to nanopb, a protobuf library for microcontrollers. Compilation then stopped with an error about messages larger than 64kB. The author extracted only the needed parts into a single otlp.proto and kept the field numbers identical to the official definitions. This way, the Collector can read the data as normal OTLP. This book also borrows only the field numbers from the official definitions and hand-writes the encoder, because the official protobuf runtime does not work (Chapter 5).
The second obstacle is the stack. According to the post, the 12 KB stack assigned to the export task sometimes ran out during the mbedTLS handshake, which verifies a bundle of CA certificates. The author increased it to 16 KB. The cause is different, but this book also ended up increasing the goroutine stack from 8 KB to 16 KB (Chapter 9).
The third is time. The post says that right after boot, the ESP32’s clock points to 1970. If the device sends data as it is, the backend cannot find the data. So the firmware holds off sending until NTP moves the clock past 2020. This book also sets the clock before it sends (Chapter 8).
base14 Scout
The base14 documentation “ESP32 Firmware to OpenTelemetry” uses a setup in which the device does not speak OTLP. At the start, the documentation says that OpenTelemetry has neither a C SDK nor a path for microcontrollers. Its reasons are as follows. The C++ SDK is POSIX-only and too heavy for the ESP32. A full stack of OTLP/HTTP, protobuf, and TLS does not fit in the default firmware build.
So the firmware sends its own small JSON format over MQTT. This is a versioned format called SME-v1. A bridge service receives it and converts it into OpenTelemetry signals. The conversion to OTLP happens outside the device. The documentation also mentions the option to encode OTLP protobuf on the device with nanopb, but it states clearly that the example does not implement it.
The documentation includes a breakdown of flash usage. Most of it goes to the Wi-Fi, TCP/IP, and TLS libraries, and the loop that encodes and sends telemetry is a few KB. The documentation uses this to argue that adding structured telemetry to a networked device increases flash usage only slightly. In this book too, the encoder choice did not decide the flash size. The TLS code that comes in through the dependencies of the HTTP client did (Chapter 7).
A request to opentelemetry-cpp
opentelemetry-cpp is the official C++ implementation of OpenTelemetry. Its issue #2483, “Add support for embedded devices?”, was opened in January 2024. It asked for support for embedded devices that run C++, such as Arduino and IoT devices.
A project member replied with a question. If the code builds for the target architecture, and the device connects to a network that it can send data to, is anything fundamentally different from a normal environment? The member then said that the request to “support embedded devices” is too general to act on without knowing the device, the platform, the compiler, and the available libraries. The issue was closed later, after a user reported that they had published a component for ESP-IDF.
The reply assumes “if the code builds”. That part does not hold for TinyGo. As Chapter 4 shows, the Go SDK does not build with TinyGo. The reason is not a lack of memory. The SDK assumes features of a host OS.
Where this book stands
This book differs from the three cases in the following ways. I write the device program in Go and build it with TinyGo. The device speaks OTLP/HTTP directly, with no bridge in between. The destination is a Collector on the same LAN. The device does not carry TLS, and the Collector handles encryption toward the outside.
The device speaks OTLP directly, as in the ClickHouse case. Heavy processing moves off the device, as in the base14 case. In this book, the device builds the data up to the OTLP format, and only TLS and authentication go to the Collector. This setup sits between the ClickHouse case and the base14 case.