-
Notifications
You must be signed in to change notification settings - Fork 12.2k
feat(sensing-server): secure opt-in OpenTelemetry log export #1465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| # Semantic-conventions gate: validates `semconv/registry/` with OpenTelemetry | ||
| # weaver and verifies the generated constants module | ||
| # (`v2/crates/wifi-densepose-sensing-server/src/semconv.rs`) is in sync with | ||
| # it (`weaver registry generate` + a no-diff check) — keeping RuView's | ||
| # telemetry names spec-adherent and drift-free. | ||
| name: semconv | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ main, develop ] | ||
| paths: | ||
| - 'semconv/**' | ||
| - 'templates/**' | ||
| - 'v2/crates/wifi-densepose-sensing-server/src/semconv.rs' | ||
| - '.github/workflows/semconv.yml' | ||
| pull_request: | ||
| paths: | ||
| - 'semconv/**' | ||
| - 'templates/**' | ||
| - 'v2/crates/wifi-densepose-sensing-server/src/semconv.rs' | ||
| - '.github/workflows/semconv.yml' | ||
| workflow_dispatch: | ||
|
|
||
| jobs: | ||
| semconv: | ||
| name: semconv (weaver) | ||
| runs-on: ubuntu-latest | ||
| env: | ||
| WEAVER_VERSION: v0.23.0 | ||
| # sha256 of weaver-x86_64-unknown-linux-gnu.tar.xz for WEAVER_VERSION | ||
| # (open-telemetry/weaver release asset). Bump both together. | ||
| WEAVER_SHA256: a9822c712d6871bd89d6530f18c5df5cea3821f642e7b8e5e49e985917f7d12d | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| persist-credentials: false | ||
| - uses: dtolnay/rust-toolchain@stable | ||
| with: | ||
| components: rustfmt | ||
| - name: Install weaver | ||
| run: | | ||
| set -euo pipefail | ||
| tarball="weaver-x86_64-unknown-linux-gnu.tar.xz" | ||
| curl -fsSL -o "$RUNNER_TEMP/$tarball" \ | ||
| "https://github.com/open-telemetry/weaver/releases/download/${WEAVER_VERSION}/${tarball}" | ||
| echo "${WEAVER_SHA256} $RUNNER_TEMP/$tarball" | sha256sum -c - | ||
| tar xJf "$RUNNER_TEMP/$tarball" -C "$RUNNER_TEMP" | ||
| echo "$RUNNER_TEMP/weaver-x86_64-unknown-linux-gnu" >> "$GITHUB_PATH" | ||
| - run: weaver registry check -r semconv/registry --future | ||
| # Codegen no-diff: regenerate the semconv constants module from the | ||
| # registry and fail if the checked-in file drifts (the generated | ||
| # module is "do not hand-edit"; the registry is the source). | ||
| - name: Regenerate semconv constants | ||
| run: | | ||
| set -euo pipefail | ||
| weaver registry generate rust v2/crates/wifi-densepose-sensing-server/src \ | ||
| -t templates -r semconv/registry --future | ||
| rustfmt --edition 2021 v2/crates/wifi-densepose-sensing-server/src/semconv.rs | ||
| - name: Verify generated constants are in sync | ||
| run: | | ||
| set -euo pipefail | ||
| changes="$(git status --porcelain -- v2/crates/wifi-densepose-sensing-server/src/semconv.rs)" | ||
| if [ -n "$changes" ]; then | ||
| echo "::error::semconv.rs is out of sync with semconv/registry/. Regenerate (see the module header) and commit." | ||
| echo "$changes" | ||
| git diff -- v2/crates/wifi-densepose-sensing-server/src/semconv.rs | ||
| exit 1 | ||
| fi | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # OpenTelemetry Collector config for the RuView observability stack | ||
| # (docker/otel-compose.yml): receive OTLP from the sensing server, export | ||
| # OTLP to the Ourios log backend. See docs/observability.md. | ||
| receivers: | ||
| otlp: | ||
| protocols: | ||
| grpc: | ||
| endpoint: 0.0.0.0:4317 | ||
| http: | ||
| endpoint: 0.0.0.0:4318 | ||
|
|
||
| processors: | ||
| batch: {} | ||
|
|
||
| exporters: | ||
| otlp/ourios: | ||
| endpoint: ourios:4317 | ||
| tls: | ||
| insecure: true | ||
|
|
||
| service: | ||
| pipelines: | ||
| logs: | ||
| receivers: [otlp] | ||
| processors: [batch] | ||
| exporters: [otlp/ourios] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| # RuView → OpenTelemetry Collector → Ourios log backend. | ||
| # | ||
| # docker compose -f docker/otel-compose.yml up | ||
| # | ||
| # Brings up an OTLP pipeline for the sensing server's logs: the server | ||
| # (built with `--features otel` and pointed at the collector via | ||
| # OTEL_EXPORTER_OTLP_ENDPOINT) exports every tracing event as an OTel | ||
| # log record; the collector forwards them to Ourios, a Parquet + | ||
| # template-mining log backend that is OTLP-native on ingest. Query the | ||
| # logs at http://localhost:4319/v1/query — see docs/observability.md. | ||
| services: | ||
| sensing-server: | ||
|
ruvnet marked this conversation as resolved.
Dismissed
ruvnet marked this conversation as resolved.
Dismissed
ruvnet marked this conversation as resolved.
Dismissed
|
||
| build: | ||
| context: .. | ||
| dockerfile: docker/Dockerfile.rust | ||
| args: | ||
| # The otel feature compiles the OTLP exporter in; export still | ||
| # only activates when OTEL_EXPORTER_OTLP_ENDPOINT is set. | ||
| SENSING_FEATURES: mqtt,otel | ||
| image: ruvnet/wifi-densepose:otel | ||
| ports: | ||
|
ruvnet marked this conversation as resolved.
Dismissed
|
||
| - "3000:3000" # REST API | ||
| - "3001:3001" # WebSocket | ||
| - "5005:5005/udp" # ESP32 CSI (see docker-compose.yml for Windows notes) | ||
| environment: | ||
| - RUST_LOG=info | ||
| # Demo default: synthetic CSI so the pipeline produces events with | ||
| # no hardware attached. Set CSI_SOURCE=esp32 for live nodes. | ||
| - CSI_SOURCE=${CSI_SOURCE:-simulated} | ||
| - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 | ||
| depends_on: | ||
| - otel-collector | ||
|
|
||
| otel-collector: | ||
|
ruvnet marked this conversation as resolved.
Dismissed
ruvnet marked this conversation as resolved.
Dismissed
ruvnet marked this conversation as resolved.
Dismissed
|
||
| image: otel/opentelemetry-collector-contrib:0.116.0@sha256:70217a89d27c678ead44f196d80aa8c2717cb68d0301dbdc40331dbec0a3e605 | ||
| command: ["--config=/etc/otelcol-contrib/config.yaml"] | ||
| volumes: | ||
| - ./otel-collector.yaml:/etc/otelcol-contrib/config.yaml:ro | ||
| ports: | ||
|
ruvnet marked this conversation as resolved.
Dismissed
|
||
| - "4317:4317" # OTLP gRPC (also reachable from the host) | ||
| - "4318:4318" # OTLP HTTP | ||
| depends_on: | ||
| - ourios | ||
|
|
||
| # Ourios — OTLP-native log backend (Parquet + Drain-derived template | ||
| # mining + DataFusion). Local-disk storage; the tenant derives from the | ||
| # exported resource's service.name, so RuView's logs land in tenant | ||
| # "ruview". | ||
| ourios: | ||
|
ruvnet marked this conversation as resolved.
Dismissed
ruvnet marked this conversation as resolved.
Dismissed
ruvnet marked this conversation as resolved.
Dismissed
|
||
| image: ghcr.io/jensholdgaard/ourios:0.4.0@sha256:9c88badb2089fe78dcdef317f28babba1cdd23984409439d4c4792f64a737ef0 | ||
| environment: | ||
| - OURIOS_BUCKET_ROOT=/data | ||
| - OURIOS_WAL_ROOT=/wal | ||
| - OURIOS_RECEIVER_ENABLED=1 | ||
| - OURIOS_RECEIVER_GRPC_ADDR=0.0.0.0:4317 | ||
| - OURIOS_RECEIVER_HTTP_ADDR=0.0.0.0:4318 | ||
| - OURIOS_QUERIER_ENABLED=1 | ||
| - OURIOS_QUERIER_HTTP_ADDR=0.0.0.0:4319 | ||
| ports: | ||
|
ruvnet marked this conversation as resolved.
Dismissed
|
||
| - "4319:4319" # query endpoint (http://localhost:4319/v1/query) | ||
| volumes: | ||
| - ourios-data:/data | ||
|
ruvnet marked this conversation as resolved.
Dismissed
|
||
| - ourios-wal:/wal | ||
|
ruvnet marked this conversation as resolved.
Dismissed
|
||
|
|
||
| volumes: | ||
| ourios-data: | ||
| ourios-wal: | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| # Observability: OTLP log export | ||
|
|
||
| The sensing server can export every `tracing` log event as an | ||
| OpenTelemetry log record over OTLP, with a curated set of sensing events | ||
| (presence transitions, vitals estimates, node online/offline, fall | ||
| detections, CSI capture stats, MQTT errors, model loads) carrying | ||
| registry-backed event names and attributes under the `ruview.*` | ||
| namespace. | ||
|
|
||
| ## The event registry | ||
|
|
||
| The names are not ad hoc: they are defined in a weaver-validated | ||
| semantic-conventions registry at `semconv/registry/` (attributes and log | ||
| event names, OpenTelemetry registry format). The Rust constants module | ||
| `v2/crates/wifi-densepose-sensing-server/src/semconv.rs` is **generated** | ||
| from that registry (`weaver registry generate`, template under | ||
| `templates/registry/rust/`) and CI (`.github/workflows/semconv.yml`) | ||
| fails if either the registry stops validating or the generated module | ||
| drifts. Executed Rust tests additionally reject any hard-coded | ||
| `ruview.*` instrumentation key that is absent from the generated registry. | ||
| Exported resources carry the registry's schema URL so downstream consumers | ||
| can identify the exact conventions version. | ||
|
|
||
| Curated events: | ||
|
|
||
| | Event | Emitted when | | ||
| | --- | --- | | ||
| | `ruview.node.online` | first frame from a sensing node (CSI or edge vitals) | | ||
| | `ruview.node.offline` | node evicted after 60 s without frames | | ||
| | `ruview.presence.changed` | smoothed presence classification flips (transition-only) | | ||
| | `ruview.vitals.estimate` | periodic breathing / heart-rate estimate (every 100 ticks) | | ||
| | `ruview.fall.detected` | edge-vitals fall flag rising edge, per node | | ||
| | `ruview.csi.stats` | periodic capture snapshot: frames processed, active nodes | | ||
| | `ruview.mqtt.error` | MQTT publish/connection error in the HA publisher | | ||
| | `ruview.model.loaded` | inference model loaded via the model API | | ||
|
|
||
| ## Enabling export | ||
|
|
||
| Export is doubly gated so the default build and the default runtime are | ||
| both unaffected: | ||
|
|
||
| 1. **Build** with the `otel` cargo feature (compiles in the OTLP | ||
| exporter stack, same gating principle as `mqtt`): | ||
|
|
||
| ```sh | ||
| cargo build --release -p wifi-densepose-sensing-server --features mqtt,otel | ||
| ``` | ||
|
|
||
| 2. **Run** with `OTEL_EXPORTER_OTLP_ENDPOINT` set (unset ⇒ the OTLP | ||
| pipeline is never constructed and logging behaves exactly as before): | ||
|
|
||
| ```sh | ||
| OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \ | ||
| ./target/release/sensing-server --source simulated | ||
| ``` | ||
|
|
||
| Use an `https://` collector endpoint outside a trusted local network. The | ||
| `otel` feature includes Rustls and native certificate roots; standard OTLP | ||
| environment variables can supply authentication headers. The Compose example | ||
| uses plaintext only for container-to-container traffic on its private network. | ||
|
|
||
| Logs export with resource attribute `service.name = "ruview"` and schema URL | ||
| `https://raw.githubusercontent.com/ruvnet/RuView/main/semconv/schema/ruview-0.1.0.yaml`. | ||
| Curated sensing | ||
| events are emitted only after the configured exporter initializes | ||
| successfully; without it, the pre-existing stderr output is unchanged. | ||
|
|
||
| ## Full stack: `docker compose` | ||
|
|
||
| `docker/otel-compose.yml` brings up the whole pipeline — | ||
| sensing server (synthetic CSI by default) → OpenTelemetry Collector → | ||
| [Ourios](https://github.com/jensholdgaard/ourios), an OTLP-native log | ||
| backend built on Parquet + online log-template mining + DataFusion: | ||
|
|
||
| ```sh | ||
| docker compose -f docker/otel-compose.yml up | ||
| ``` | ||
|
|
||
| The collector and backend image tags are pinned to immutable multi-platform | ||
| digests so the demo resolves to the reviewed images. | ||
|
|
||
| Ourios derives the tenant from `service.name`, so all RuView logs land | ||
| in tenant `ruview`. | ||
|
|
||
| ## Example queries | ||
|
|
||
| Ourios mines every log line into a stable `template_id` online at | ||
| ingest, which makes template-level questions cheap. Its query endpoint | ||
| speaks a small logs DSL: | ||
|
|
||
| Which log templates dominate RuView's output? | ||
|
|
||
| ```sh | ||
| curl -s http://localhost:4319/v1/query \ | ||
| -H 'X-Ourios-Tenant: ruview' \ | ||
| -H 'Content-Type: text/plain' \ | ||
| -d 'severity >= trace | range(-1h, now) | count by template_id | sort count desc | limit 10' | ||
| ``` | ||
|
|
||
| Recent warnings and errors (fall detections, MQTT failures): | ||
|
|
||
| ```sh | ||
| curl -s http://localhost:4319/v1/query \ | ||
| -H 'X-Ourios-Tenant: ruview' \ | ||
| -H 'Content-Type: text/plain' \ | ||
| -d 'severity >= warn | limit 50' | ||
| ``` | ||
|
|
||
| Did a RuView deploy change what the service logs? Template drift between | ||
| two time windows (new / vanished / changed templates): | ||
|
|
||
| ```sh | ||
| curl -s http://localhost:4319/v1/query \ | ||
| -H 'X-Ourios-Tenant: ruview' \ | ||
| -H 'Content-Type: text/plain' \ | ||
| -d 'drift from -7d to now' | ||
| ``` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.