diff --git a/build/systemd/spinifex-northstar.service b/build/systemd/spinifex-northstar.service index 3e80e82e7..ff43360a0 100644 --- a/build/systemd/spinifex-northstar.service +++ b/build/systemd/spinifex-northstar.service @@ -5,6 +5,7 @@ After=spinifex-nats.service spinifex-predastore.service Wants=spinifex-predastore.service [Service] +EnvironmentFile=-/etc/spinifex/telemetry.env Type=simple Slice=spinifex-system.slice User=spinifex-northstar diff --git a/cmd/spinifex/cmd/service.go b/cmd/spinifex/cmd/service.go index 6b85aae4c..76cfba5e0 100644 --- a/cmd/spinifex/cmd/service.go +++ b/cmd/spinifex/cmd/service.go @@ -885,6 +885,9 @@ var northstarStartCmd = &cobra.Command{ SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { fmt.Println("Starting northstar service...") + + defer initTelemetry("northstar", false)() + return runNorthstarStart(northstarStartOptions{ configFile: viper.GetString("config"), configOverride: viper.GetString("northstar-config"), diff --git a/spinifex/systemd/units_invariants_test.go b/spinifex/systemd/units_invariants_test.go index e30411164..e373fe039 100644 --- a/spinifex/systemd/units_invariants_test.go +++ b/spinifex/systemd/units_invariants_test.go @@ -261,3 +261,37 @@ func TestRG11_LeanUnits(t *testing.T) { } } } + +// TestApplicationUnitsExportTelemetry asserts every unit that runs an spx +// application service sources the telemetry drop-in. That file carries +// OTEL_EXPORTER_OTLP_ENDPOINT, MULGA_ENV and MULGA_SOURCE, so a unit missing it +// starts a service whose instruments record into a no-op provider — the process +// runs healthy and simply reports nothing, which is invisible until someone +// notices an empty dashboard. +// +// Units that host an agent or a one-shot rather than an spx service are exempt: +// they either export on their own (the collectors) or have nothing to export. +func TestApplicationUnitsExportTelemetry(t *testing.T) { + dir := unitsDir(t) + const telemetry = "EnvironmentFile=-/etc/spinifex/telemetry.env" + + exempt := []string{ + "spinifex-nats-watchdog.service", // periodic health probe, no OTel SDK + "spinifex-shutdown.service", // one-shot drain on halt + "regenerate-ssh-host-keys.service", + } + + for _, name := range unitFiles(t, dir) { + if !strings.HasSuffix(name, ".service") || slices.Contains(exempt, name) { + continue + } + u := readUnit(t, dir, name) + // Only units that actually launch an spx service can emit telemetry. + if !strings.Contains(u, "/usr/local/bin/spx service ") { + continue + } + if !hasDirective(u, telemetry) { + t.Errorf("%s runs an spx service but does not source %s; its telemetry would be silently dropped", name, telemetry) + } + } +}