Feature Specification: Resource otel

Created: 2026-10-07

Status: Implemented

Input: Reconstructed from the code at 093e68b6f (core/resources/otel/default.nix, core/resources/otel/test.nix, core/setups/hosts-common.nix, core/components/hosting-provider/windmill/default.nix, core/components/hosting-provider/windmill-otel.nix, core/components/hosting-provider/netbox/default.nix), pull requests #1184, #1205 and #1206.

User Scenarios & Testing (mandatory)

The otel resource lets an application send OpenTelemetry signals to the collector of its deployment. The policy holds the OTLP endpoint. For each enabled request, apply sets fediversity.otel.endpoints.<consumerName> on the node. The OTel module of each application renders its settings from that entry. The shared resource rules are in the resource family spec.

User Story 1 - Send telemetry from an application (Priority: P1)

An operator of the hosting provider wants traces and metrics from windmill and netbox. Each component requests "otel".otel with enable = true and its consumerName, and imports its OTel module (windmill-otel.nix, netbox/otel.nix). The module sets OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES on the services. For netbox, it also wraps gunicorn and netbox rqworker in opentelemetry-instrument.

Why this priority: telemetry from the platform services is the purpose of the resource.

Independent Test: nix-unit-resources-otel, tests test-endpoint-flows-to-windmill and test-endpoint-flows-to-netbox, and test-otel-wiring.

Acceptance Scenarios:

  1. Given the policy endpoint = "http://otel.example:4318", When the windmill node evaluates, Then systemd.services.windmill-server.environment.OTEL_EXPORTER_OTLP_ENDPOINT is that endpoint.
  2. Given the same policy, When the netbox node evaluates, Then systemd.services.netbox.environment.OTEL_EXPORTER_OTLP_ENDPOINT is that endpoint.

User Story 2 - Find the collector of the deployment (Priority: P1)

A node of the deployment provides otel. core/setups/hosts-common.nix sets the policy endpoint with mkDefault to http://<host of the otel provider>:4318. The traffic uses plain HTTP on the internal network. An environment can replace the endpoint.

Why this priority: without an endpoint, no application sends telemetry.

Independent Test: nix-unit-resources-otel, test test-endpoint-defaults-to-group-collector.

Acceptance Scenarios:

  1. Given a deployment with a node that provides otel and no override, When the windmill node evaluates, Then the endpoint is http://<fqdn of that node>:4318.

User Story 3 - Keep telemetry off (Priority: P2)

A deployment has no collector, or an environment sets endpoint = null. apply returns an empty list. fediversity.otel.endpoints has no entry, and no service gets OTel settings.

Why this priority: an application must not send signals to an address that does not exist.

Independent Test: nix-unit-resources-otel, test test-endpoint-absent-with-null-override.

Acceptance Scenarios:

  1. Given endpoint = null, When the windmill node evaluates, Then windmill-server has no OTEL_EXPORTER_OTLP_ENDPOINT.

Edge Cases

  • When no request on a node is enabled, apply adds no module, also when an endpoint is set.
  • The result applies to one consumer. An application on the same node that imports an OTel module but does not request the resource gets no OTel settings.

Requirements (mandatory)

Functional Requirements

  • FR-001: The request MUST accept enable (default false) and consumerName. The request MUST contain only data, so that it can be written to JSON.
  • FR-002: The policy MUST accept endpoint, a string or null (default null).
  • FR-003: apply MUST return [ ] when endpoint is null.
  • FR-004: apply MUST otherwise return, for each request with enable = true, a module that imports core/resources/otel/option.nix and sets fediversity.otel.endpoints.<consumerName> to endpoint.
  • FR-005: core/setups/hosts-common.nix MUST default endpoint to http://<host of the otel provider>:4318 when a node of the deployment provides otel, and to null otherwise.
  • FR-006: core/setups/hosts-common.nix MUST add the process output to the imports of each node.

Key Entities

  • endpoint: the OTLP HTTP endpoint of the collector, for example http://otel-collector.vpn:4318.
  • fediversity.otel.endpoints.<consumerName>: the endpoint on the application node, declared in core/resources/otel/option.nix. It is absent when the request is not enabled or the policy has no endpoint. The OTel module of each application imports the option file and reads the entry.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: nix-unit-resources-otel (4 tests) and nix-unit-resources-plain-requests pass.

Assumptions

  • The collector listens for OTLP over HTTP on port 4318. The comment in core/setups/hosts-common.nix says that the port must match the httpPort default of the collector.
  • The internal network is trusted, so the signals travel without TLS.

Known Deviations

None.