A C++17 telemetry ingestion service for accepting IoT sensor readings, storing recent readings in memory, emitting structured telemetry events, and exposing runtime metrics.
The project combines a small REST API with a telemetry pipeline: incoming readings update metrics, generate structured events, flow through a bounded asynchronous queue, and can be exported to stdout, files, HTTP endpoints, TCP, or UDP sinks.
The Telemetry API is deployed on Render using a multi-stage Docker build with automatic health checks. Runtime metrics are securely exposed through a Prometheus-compatible endpoint and visualized using Grafana Cloud.
- API Health Endpoint: https://your-service.onrender.com/health
- Grafana Dashboard: https://jumbopeach1255.grafana.net/public-dashboards/5eb8f1deb72d4fa6b1ed6b0e22ae938e
Note
- The root endpoint (
/) is intentionally not implemented. Use the/healthendpoint to verify the service is running.- The
/metricsendpoint is protected using Bearer token authentication via theTELEMETRY_METRICS_TOKENenvironment variable and is intended for Prometheus/Grafana Cloud scraping.
- REST API built with C++17 and
cpp-httplib - JSON request and response handling with
nlohmann/json - Thread-safe in-memory telemetry storage
- Average temperature and reading count statistics
- Structured event logging with correlation and request IDs
- Asynchronous telemetry pipeline with batching, sampling, rate limiting, and overflow policies
- Bounded per-sink queues with retry and exponential backoff
- Sink implementations for stdout, file, HTTP, TCP, and UDP
- Counters, gauges, histograms, timers, and summaries
- Prometheus-compatible metrics endpoint
- OTLP-ready JSON metrics endpoint
- Health endpoint with process diagnostics
- Server-sent event stream for live telemetry events
- Threshold alert engine with cooldowns and stdout notifications
- JSON configuration with environment variable overrides
- Config file watcher for runtime pipeline updates
- Unit tests for storage, metrics, pipeline behavior, serialization, and sink failures
- Optional
clang-tidy,cppcheck, and coverage build support
- C++17
- CMake 3.16+
cpp-httplibfor the embedded HTTP servernlohmann/jsonfor JSON parsing and serialization- GitHub Actions for CI
Both third-party headers are vendored under include/, so no package manager is required for the default build.
telemetry-api/
|-- include/
| |-- httplib.h
| |-- nlohmann/json.hpp
| |-- telemetry.hpp
| |-- telemetry_alerting.hpp
| |-- telemetry_config.hpp
| |-- telemetry_diagnostics.hpp
| |-- telemetry_event.hpp
| |-- telemetry_exporter.hpp
| |-- telemetry_metrics.hpp
| |-- telemetry_monitoring.hpp
| |-- telemetry_pipeline.hpp
| |-- telemetry_queue.hpp
| |-- telemetry_serializer.hpp
| |-- telemetry_sinks.hpp
| `-- telemetry_store.hpp
|-- src/
| |-- main.cpp
| `-- telemetry_*.cpp
|-- tests/
| |-- metrics_test.cpp
| |-- pipeline_test.cpp
| |-- serialization_test.cpp
| |-- sink_failure_test.cpp
| `-- telemetry_test.cpp
|-- .github/workflows/
|-- CMakeLists.txt
`-- README.md
cmake -S . -B build
cmake --build build --parallelOn Windows with a multi-config generator, the executable is usually placed under a configuration directory such as build/Debug/telemetry_api.exe or build/Release/telemetry_api.exe.
Linux/macOS:
./build/telemetry_apiWindows PowerShell:
.\build\Debug\telemetry_api.exeBy default, the server listens on:
http://0.0.0.0:8080
Use TELEMETRY_PORT or a JSON config file to change the port.
Set TELEMETRY_METRICS_TOKEN to require Bearer authentication on /metrics. Grafana Cloud Hosted Collector requires the metrics endpoint to be authenticated.
The repository includes a multi-stage Dockerfile and a render.yaml Blueprint.
- Push the repository to GitHub.
- In Render, create a new Blueprint and connect the repository.
- Render builds the Docker image and checks /health before making the service live.
The server reads Render's PORT environment variable automatically. TELEMETRY_PORT remains available as an explicit override.
After deployment, verify https://your-service.onrender.com/health.
Accepts a sensor reading, stores it in memory, updates sensor metrics, and emits a structured event into the telemetry pipeline.
curl -X POST http://localhost:8080/telemetry \
-H "Content-Type: application/json" \
-H "X-Correlation-Id: demo-correlation-id" \
-H "X-Request-Id: demo-request-id" \
-d '{"sensor_id":"sensor_1","temperature":25.5,"humidity":60,"timestamp":1710000000}'Successful response:
Telemetry added
Invalid JSON or missing fields return 400:
{ "error": "invalid telemetry payload" }Returns all telemetry records currently stored in memory.
curl http://localhost:8080/telemetry[
{
"sensor_id": "sensor_1",
"temperature": 25.5,
"humidity": 60,
"timestamp": 1710000000
}
]Returns aggregate statistics for stored readings.
curl http://localhost:8080/stats{ "avg_temperature": 25.5, "count": 1 }Flushes the telemetry pipeline.
curl -X POST http://localhost:8080/flushflushed
Returns process health and lightweight runtime diagnostics.
curl http://localhost:8080/healthExample fields include status, process_id, host, thread_id, and uptime_ms.
Returns a Prometheus-compatible metrics scrape.
curl http://localhost:8080/metricsMetrics include HTTP request timing, active requests, pipeline counters, sink drops, and sensor reading metrics.
Returns metrics as schema-tagged JSON through the OTLP-ready exporter abstraction.
curl http://localhost:8080/otlp/v1/metricsStreams accepted telemetry events as server-sent events.
curl -N http://localhost:8080/telemetry/liveThe stream sends heartbeat comments when no events are available.
The server can run with defaults, environment variables, or a JSON config file.
Set TELEMETRY_CONFIG to load a JSON configuration file:
$env:TELEMETRY_CONFIG = "telemetry.config.json"
.\build\Debug\telemetry_api.exeExample config:
{
"monitoring": {
"host": "0.0.0.0",
"port": 8080
},
"pipeline": {
"queue_size": 8192,
"batch_size": 128,
"worker_count": 2,
"flush_interval_ms": 1000,
"overflow_policy": "drop_newest",
"sampling_rate": 1.0,
"rate_limit_per_second": 0
},
"sinks": [
{
"type": "stdout",
"name": "console"
},
{
"type": "file",
"name": "events-file",
"target": "telemetry.log",
"queue_size": 4096,
"overflow_policy": "drop_oldest",
"retry": {
"max_attempts": 3,
"initial_backoff_ms": 50,
"max_backoff_ms": 2000
}
}
],
"alerts": [
{
"name": "high_temperature",
"metric": "sensor_temperature_celsius",
"op": ">",
"threshold": 80,
"cooldown_ms": 30000
}
]
}Supported sink type values:
stdoutfilehttptcpudp
For http, tcp, and udp sinks, set target to the destination URL or host/port, for example:
{
"type": "http",
"name": "collector",
"target": "http://localhost:4318/events"
}{ "type": "udp", "name": "udp-collector", "target": "udp://localhost:9000" }Supported overflow policies:
drop_newestdrop_oldestblock
Supported alert operators:
>>=<<===
Environment variables override file values for selected runtime settings:
| Variable | Description |
|---|---|
TELEMETRY_CONFIG |
Path to a JSON config file |
TELEMETRY_PORT |
HTTP server port |
TELEMETRY_QUEUE_SIZE |
Main pipeline queue size |
TELEMETRY_BATCH_SIZE |
Pipeline batch size |
TELEMETRY_WORKERS |
Number of pipeline worker threads |
TELEMETRY_SAMPLING_RATE |
Event sampling rate from 0.0 to 1.0 |
When TELEMETRY_CONFIG is set, the file is watched and pipeline settings are reloaded while the process is running. Sinks and alert rules are loaded during startup.
Build and run the test suite:
cmake -S . -B build
cmake --build build --parallel
ctest --test-dir build --output-on-failureThe configured tests are:
telemetry_testmetrics_testpipeline_testserialization_testsink_failure_test
Enable clang-tidy during compilation:
cmake -S . -B build -DTELEMETRY_ENABLE_CLANG_TIDY=ON
cmake --build build --parallelRun cppcheck if it is installed:
cmake --build build --target cppcheckBuild with coverage instrumentation on GCC or Clang:
cmake -S . -B build-coverage -DTELEMETRY_ENABLE_COVERAGE=ON
cmake --build build-coverage --parallel
ctest --test-dir build-coverage --output-on-failureGitHub Actions builds the project, runs tests, executes cppcheck, and validates a coverage build on Ubuntu.
This project is for educational purposes and demonstration of modern C++ backend and telemetry service design.
