fix(northstar): initialise OTel SDK and source the telemetry environment (#555)

Northstar carried working northstar.dns.* instruments but shipped no
telemetry, so its dashboard was empty and the only northstar data in
Elasticsearch was journald scraped under the systemd unit name.

Two gaps, both outside the instrumentation. northstarStartCmd never called
initTelemetry, unlike every other service command, so the instruments
recorded into a no-op provider. The unit also did not source
/etc/spinifex/telemetry.env, which every other application unit reads for
OTEL_EXPORTER_OTLP_ENDPOINT, MULGA_ENV and MULGA_SOURCE — so even an
initialised SDK would have had no endpoint and no env label.

Add an invariant covering the second gap: any unit launching an spx service
must source the telemetry drop-in. A service missing it starts healthy and
silently reports nothing, which only surfaces when someone notices an empty
dashboard. Verified the test fails against the unpatched unit.
This commit is contained in:
Josh Siviour
2026-07-20 13:22:27 +10:00
committed by GitHub
parent ffc34b735b
commit 08fc5e4c58
3 changed files with 38 additions and 0 deletions
+1
View File
@@ -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
+3
View File
@@ -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"),
+34
View File
@@ -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)
}
}
}