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
34 changes: 22 additions & 12 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,41 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install PlatformIO
run: python -m pip install -U platformio

# Make repo Variables + Secrets available to all subsequent steps
- name: Export env for build
run: |
python -m pip install -U platformio
echo "::add-mask::${{ secrets.WIFI_PASS }}"
{
echo "WIFI_SSID=${{ vars.WIFI_SSID }}"
echo "WIFI_PASS=${{ secrets.WIFI_PASS }}"
echo "OTEL_COLLECTOR_HOST=${{ vars.OTEL_COLLECTOR_HOST }}"
echo "OTEL_COLLECTOR_PORT=${{ vars.OTEL_COLLECTOR_PORT }}"
echo "OTEL_SERVICE_NAME=${{ vars.OTEL_SERVICE_NAME }}"
echo "OTEL_SERVICE_NAMESPACE=${{ vars.OTEL_SERVICE_NAMESPACE }}"
echo "OTEL_SERVICE_VERSION=${{ vars.OTEL_SERVICE_VERSION }}"
echo "OTEL_SERVICE_INSTANCE=${{ vars.OTEL_SERVICE_INSTANCE }}"
echo "OTEL_DEPLOY_ENV=${{ vars.OTEL_DEPLOY_ENV }}"
} >> "$GITHUB_ENV"

- name: PlatformIO Update
run: |
pio update
run: pio update

- name: Build for ESP32 (esp32dev)
run: |
platformio ci examples/basic/main.cpp --project-conf platformio.ini --lib "." -e esp32dev
run: platformio ci src/main.cpp --project-conf platformio.ini --lib "." -e esp32dev

- name: Build for Pico W (rpipicow)
run: |
platformio ci examples/basic/main.cpp --project-conf platformio.ini --lib "." -e rpipicow
run: platformio ci src/main.cpp --project-conf platformio.ini --lib "." -e rpipicow

- name: Build for ESP8266 (esp8266 d1_mini)
run: |
platformio ci examples/basic/main.cpp --project-conf platformio.ini --lib "." -e esp8266

run: platformio ci src/main.cpp --project-conf platformio.ini --lib "." -e esp8266

139 changes: 117 additions & 22 deletions include/OtelDefaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,128 @@

#include <map>
#include <ArduinoJson.h>
#include <sys/time.h> // for gettimeofday()
#include <sys/time.h> // gettimeofday()

// This header provides:
// - Time helpers (nowUnixNano/Millis)
// - OTLP JSON KeyValue serializers (string/double/int) using ArduinoJson v7 APIs
// - OTelResourceConfig with legacy-compatible helpers used by Metrics/Tracer:
// setAttribute(), addResourceAttributes(JsonObject)
// and newer helpers used by Logger:
// set(), clear(), toJson(resource)
// - defaultResource() and defaultTraceResource() singletons

namespace OTel {

// -------------------------------------------------------------------------------------------------
// Time helpers
// -------------------------------------------------------------------------------------------------

/**
* @brief Get the current UNIX time in nanoseconds.
* Uses the POSIX gettimeofday() clock, which you should have
* synchronized via configTime()/time().
*/
/** UNIX timestamp in nanoseconds. Ensure clock is synced (configTime(), etc.) */
static inline uint64_t nowUnixNano() {
struct timeval tv;
gettimeofday(&tv, nullptr);
// seconds→ns, usec→ns
return uint64_t(tv.tv_sec) * 1000000000ULL
+ uint64_t(tv.tv_usec) * 1000ULL;
return static_cast<uint64_t>(tv.tv_sec) * 1000000000ULL
+ static_cast<uint64_t>(tv.tv_usec) * 1000ULL;
}

/** UNIX timestamp in milliseconds (spare helper) */
static inline uint64_t nowUnixMillis() {
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<uint64_t>(tv.tv_sec) * 1000ULL
+ static_cast<uint64_t>(tv.tv_usec) / 1000ULL;
}

// Portable uint64 -> String (no printf/ULL reliance; RP2040-safe)
inline String u64ToString(uint64_t v) {
if (v == 0) return String("0");
char buf[21]; // max 20 digits + NUL
char* p = &buf[20];
*p = '\0';
while (v > 0) {
*--p = char('0' + (v % 10));
v /= 10;
}
return String(p);
}

// -------------------------------------------------------------------------------------------------
// OTLP JSON KeyValue helpers (ArduinoJson v7 deprecation-safe)
// -------------------------------------------------------------------------------------------------

/**
* Serialise a string KeyValue into an OTLP JSON attributes array:
* {"key":"<key>","value":{"stringValue":"<value>"}}.
*/
inline void serializeKeyValue(JsonArray &arr, const String &key, const String &value) {
JsonObject kv = arr.add<JsonObject>();
kv["key"] = key;
JsonObject any = kv["value"].to<JsonObject>();
any["stringValue"] = value;
}

/** Double-valued KeyValue */
inline void serializeKeyDouble(JsonArray &arr, const String &key, double value) {
JsonObject kv = arr.add<JsonObject>();
kv["key"] = key;
JsonObject any = kv["value"].to<JsonObject>();
any["doubleValue"] = value;
}

/** Int64-valued KeyValue */
inline void serializeKeyInt(JsonArray &arr, const String &key, int64_t value) {
JsonObject kv = arr.add<JsonObject>();
kv["key"] = key;
JsonObject any = kv["value"].to<JsonObject>();
any["intValue"] = value;
}

// -------------------------------------------------------------------------------------------------
// Resource attributes container (back-compat + new helpers)
// -------------------------------------------------------------------------------------------------

/**
* Holds resource attributes (service/host/instance/etc.).
* This struct supports:
* - Legacy calls used by your Metrics/Tracer code:
* setAttribute(k,v), addResourceAttributes(JsonObject target)
* (these write "attributes" directly under the passed object)
* - Newer usage for logs envelope:
* toJson(resource) -> writes into resource["attributes"]
*/
struct OTelResourceConfig {
// internal map of attributes
std::map<String, String> attrs;

void setAttribute(const String& key, const String& value) {
attrs[key] = value;
}
// Newer API
void set(const String &k, const String &v) { attrs[k] = v; }
void set(const char *k, const String &v) { attrs[String(k)] = v; }
void clear() { attrs.clear(); }
bool empty() const { return attrs.empty(); }

void serializeKeyValue(JsonArray &arr, const String &k, const String &v) const {
JsonObject kv = arr.add<JsonObject>();
kv["key"] = k;
JsonObject val = kv["value"].to<JsonObject>();
val["stringValue"] = v;
// Backwards-compatible API expected by existing Metrics/Tracer code
void setAttribute(const String &k, const String &v) { attrs[k] = v; }
void setAttribute(const char *k, const String &v) { attrs[String(k)] = v; }

/**
* Legacy helper used by Metrics/Tracer paths:
* Writes attributes directly under the given target as:
* target["attributes"] = [ {key, value:{stringValue}}, ... ]
*/
void addResourceAttributes(JsonObject target) const {
if (attrs.empty()) return;
JsonArray attributes = target["attributes"].to<JsonArray>();
for (auto &p : attrs) {
serializeKeyValue(attributes, p.first, p.second);
}
}

void addResourceAttributes(JsonObject &resource) const {
/**
* Logs envelope helper:
* Writes into "resource.attributes" of the given resource object:
* resource["attributes"] = [ {key, value:{stringValue}}, ... ]
*/
void toJson(JsonObject resource) const {
if (attrs.empty()) return;
JsonArray attributes = resource["attributes"].to<JsonArray>();
for (auto &p : attrs) {
Expand All @@ -45,11 +133,18 @@ struct OTelResourceConfig {
}
};

inline OTelResourceConfig getDefaultResource() {
return OTelResourceConfig();
// -------------------------------------------------------------------------------------------------
// Singletons (headers-only, inline ok)
// -------------------------------------------------------------------------------------------------

/** Default resource for general use (metrics/logs/etc.) */
static inline OTelResourceConfig& defaultResource() {
static OTelResourceConfig rc;
return rc;
}


} // namespace OTel

#endif
#endif // OTEL_DEFAULTS_H

Loading