Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ All examples assume use of the Arduino framework under PlatformIO, and that you

The example code shows how to do this with the `time` library and NTP.

### Concurrency and performance

Where supported (RP2040 and *some* ESP32 boards), the code to process and send the data is moved to the second core of the device.

This removes any blocking code and ensures that the HTTP POST call does not interfere with the main loop.

---

## 🚀 Installation with PlatformIO
Expand Down Expand Up @@ -173,15 +179,18 @@ Override defaults in `OtelDefaults.h` or via `-D` flags:
| ------------------------ | ------------------ | ----------------------------------------------- |
| `WIFI_SSID` | `"default"` | Wi‑Fi SSID |
| `WIFI_PASS` | `"default"` | Wi‑Fi password |
| `OTEL_COLLECTOR_HOST` | `"http://…:4318"` | OTLP HTTP endpoint |
| `OTEL_COLLECTOR_PORT` | `4318` | OTLP HTTP port |
| `OTEL_COLLECTOR_BASE_URL`| `Null` | The base URL (http://192.168.8.10:4318) of the otel collector |
| `OTEL_SERVICE_NAME` | `"demo_service"` | Name of your service |
| `OTEL_SERVICE_NAMESPACE` | `"demo_namespace"` | Service namespace |
| `OTEL_SERVICE_VERSION` | `"v1.0.0"` | Semantic version |
| `OTEL_SERVICE_INSTANCE` | `"instance-1"` | Unique instance ID |
| `OTEL_DEPLOY_ENV` | `"dev"` | Deployment environment (e.g. `prod`, `staging`) |
| `OTEL_WORKER_BURST` | `16` | The number of telemetry messages to process at a time |
| `OTEL_WORKER_SLEEP_MS` | `0` | How long to sleep between processing messages (0 is instant) |
| `OTEL_QUEUE_CAPACITY` | `128` | The maximum number of telemetry messages we can store before we start to drop data |
| `DEBUG` | `Null` | Print verbose messages including OTEL Payload to the serial port |


---

## 🤝 Contributing
Expand Down
73 changes: 65 additions & 8 deletions include/OtelSender.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,77 @@
#ifndef OTEL_SENDER_H
#define OTEL_SENDER_H

#pragma once
#include <Arduino.h>
#include <ArduinoJson.h>
#include <atomic>

// Optional compile-time on/off switch for all network sends.
// You can set -DOTEL_SEND_ENABLE=0 in platformio.ini for latency tests.
#ifndef OTEL_SEND_ENABLE
#define OTEL_SEND_ENABLE 1
#endif

#ifndef OTEL_WORKER_BURST
#define OTEL_WORKER_BURST 8
#endif

#ifndef OTEL_WORKER_SLEEP_MS
#define OTEL_WORKER_SLEEP_MS 0
#endif

#ifndef OTEL_QUEUE_CAPACITY
#define OTEL_QUEUE_CAPACITY 128
#endif
// Base URL of your OTLP/HTTP collector (no trailing slash), e.g. "http://192.168.8.50:4318"
// You can override this via build_flags: -DOTEL_COLLECTOR_BASE_URL="\"http://…:4318\""
#ifndef OTEL_COLLECTOR_BASE_URL
#define OTEL_COLLECTOR_BASE_URL "http://192.168.8.50:4318"
#endif

#ifndef OTEL_COLLECTOR_HOST
#define OTEL_COLLECTOR_HOST "http://192.168.8.10:4318"
// Internal queue capacity for async sender on RP2040.
// Keep small to bound RAM; increase if you see drops.
#ifndef OTEL_QUEUE_CAPACITY
#define OTEL_QUEUE_CAPACITY 16
#endif

namespace OTel {
struct OTelQueuedItem {
const char* path; // "/v1/logs", "/v1/traces", "/v1/metrics"
String payload; // serialized JSON
};

class OTelSender {
public:
// Main API: called by logger/tracer/metrics to send serialized JSON to OTLP/HTTP
static void sendJson(const char* path, JsonDocument& doc);
};

} // namespace OTel
// Start the RP2040 core-1 worker (no-op on non-RP2040). Call once after Wi-Fi is ready.
static void beginAsyncWorker();

// Diagnostics (published via your health metrics if you like)
static uint32_t droppedCount(); // number of items dropped due to full queue
static bool queueIsHealthy(); // worker started?

private:
// ---------- SPSC ring buffer (core0 producer -> core1 consumer) ----------
static constexpr size_t QCAP = OTEL_QUEUE_CAPACITY;
static OTelQueuedItem q_[QCAP];
static std::atomic<size_t> head_; // producer writes
static std::atomic<size_t> tail_; // consumer writes
static std::atomic<uint32_t> drops_;
static std::atomic<bool> worker_started_;

static bool enqueue_(const char* path, String&& payload);
static bool dequeue_(OTelQueuedItem& out);

// ---------- Worker ----------
static void pumpOnce_(); // send one item if present
static void workerLoop_(); // runs on core 1 (RP2040)
static void launchWorkerOnce_();

// ---------- Utilities ----------
static String fullUrl_(const char* path); // build collector URL + path

// inside class OTelSender (near the bottom)
#ifdef ARDUINO_ARCH_RP2040
friend void otel_worker_entry();
#endif
};

4 changes: 2 additions & 2 deletions library.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "otel-embedded-cpp",
"version": "1.0.1",
"version": "1.0.2",
"description": "OpenTelemetry logging, tracing, and metrics for embedded C++ devices (ESP32, RP2040 Pico W, ESP8266).",
"keywords": [
"OpenTelemetry",
Expand All @@ -16,7 +16,7 @@
],
"authors": [
{
"name": "Your Name",
"name": "Matthew Macdonald-Wallace",
"maintainer": true
}
],
Expand Down
13 changes: 5 additions & 8 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ lib_deps =
build_flags =
-DWIFI_SSID=\"${sysenv.WIFI_SSID}\"
-DWIFI_PASS=\"${sysenv.WIFI_PASS}\"
-DOTEL_COLLECTOR_HOST=\"${sysenv.OTEL_COLLECTOR_HOST}\"
-DOTEL_COLLECTOR_PORT=${sysenv.OTEL_COLLECTOR_PORT}
-DOTEL_COLLECTOR_BASE_URL="\"http://192.168.8.10:4318\""
-DOTEL_SERVICE_NAME=\"${sysenv.OTEL_SERVICE_NAME}\"
-DOTEL_SERVICE_NAMESPACE=\"${sysenv.OTEL_SERVICE_NAMESPACE}\"
-DOTEL_SERVICE_VERSION=\"${sysenv.OTEL_SERVICE_VERSION}\"
Expand All @@ -37,8 +36,7 @@ lib_deps =
build_flags =
-DWIFI_SSID=\"${sysenv.WIFI_SSID}\"
-DWIFI_PASS=\"${sysenv.WIFI_PASS}\"
-DOTEL_COLLECTOR_HOST=\"${sysenv.OTEL_COLLECTOR_HOST}\"
-DOTEL_COLLECTOR_PORT=${sysenv.OTEL_COLLECTOR_PORT}
-DOTEL_COLLECTOR_BASE_URL="\"http://192.168.8.10:4318\""
-DOTEL_SERVICE_NAME=\"${sysenv.OTEL_SERVICE_NAME}\"
-DOTEL_SERVICE_NAMESPACE=\"${sysenv.OTEL_SERVICE_NAMESPACE}\"
-DOTEL_SERVICE_VERSION=\"${sysenv.OTEL_SERVICE_VERSION}\"
Expand All @@ -59,10 +57,9 @@ lib_deps =
build_flags =
-DWIFI_SSID=\"${sysenv.WIFI_SSID}\"
-DWIFI_PASS=\"${sysenv.WIFI_PASS}\"
-DOTEL_COLLECTOR_HOST=\"${sysenv.OTEL_COLLECTOR_HOST}\"
-DOTEL_COLLECTOR_PORT=${sysenv.OTEL_COLLECTOR_PORT}
-DOTEL_COLLECTOR_BASE_URL="\"http://192.168.8.10:4318\""
-DOTEL_SERVICE_NAME=\"${sysenv.OTEL_SERVICE_NAME}\"
-DOTEL_SERVICE_NAMESPACE=\"${sysenv.OTEL_SERVICE_NAMESPACE}\"
-DOTEL_SERVICE_VERSION=\"${sysenv.OTEL_SERVICE_VERSION}\"
-DOTEL_SERVICE_INSTANCE=\"${sysenv.OTEL_SERVICE_INSTANCE}\"
-DOTEL_DEPLOY_ENV=\"${sysenv.OTEL_DEPLOY_ENV}\"
-DOTEL_SERVICE_INSTANCE=\"esp8266\"
-DOTEL_DEPLOY_ENV=\"esp8266\"
Loading