85.1.54. pepsi-telemetry-client

per-host feature-telemetry aggregator and submitter

Manual section:

1

85.1.54.1.1. Name

pepsi-telemetry-client - aggregate local feature-usage telemetry and submit it to the central collector.

85.1.54.1.2. Synopsis

pepsi-telemetry-client [GLOBAL-OPTIONS] serve

85.1.54.1.3. Description

pepsi-telemetry-client is the per-host producer side of Pepsi’s anonymous feature telemetry (the central collector is pepsi-telemetry(1)). It is a small long-lived daemon that:

  • listens on a local UNIX socket for feature-usage events emitted by the Pepsi programs on the same host (the stage workers and pepsi-ingress(1), via the internal telemetry_update API);

  • accumulates the events in memory — a per-interval count for each feature plus the cumulative set of features seen this run;

  • every SUBMIT_INTERVAL (default: at most once per minute) submits the counts to the collector at TELEMETRY_SERVER under this deployment’s anonymous SYSTEM_ID and resets the per-interval counts (re-merging them for retry if a submission fails);

  • on shutdown (SIGINT/SIGTERM) makes one final submission so a clean stop does not lose the current interval.

It holds no secrets beyond the anonymous SYSTEM_ID; its only outbound traffic is HTTPS to the collector. Its database connection (as the pepsi role) serves two purposes and no others: a LISTEN on the telemetry_changed channel, and the one-row pepsi.telemetry_client liveness record described below. Without a database it still works, following the configuration file on its heartbeat.

Telemetry is opt-in: unless [pepsi] SHARE_TELEMETRY has been set to yes, the producer API is a no-op that opens no socket and the daemon runs dormant — it binds no socket, gathers nothing and submits nothing. That is what an installation which never answered the question gets, whether or not the service unit is enabled. An absent option, an absent [pepsi] section and an unparseable value all read as off — “I could not tell” is never consent — and the switch is consulted before [pepsi-telemetry-client] is parsed at all, so a typo in a section that cannot matter cannot affect a dormant daemon.

The producer programs connect to the socket lazily and tolerate the daemon being absent (events are simply dropped while it is down), so ordering between the daemon and the rest of the pipeline does not matter.

85.1.54.1.4. Dormant and active

The daemon re-reads the configuration file — the file, through the same single reader of SHARE_TELEMETRY every other component uses — whenever

  • the telemetry_changed notification arrives. Whoever rewrites the switch sends it after writing the file, in both directions: pepsi-setup(1) (run and the wizard) and the write-config task of pepsi-setup apply, through which the browser console changes it. The payload (on / off) is informational; the notification carries no authority, and a notification that disagrees with the file changes nothing;

  • it receives SIGHUP;

  • its heartbeat fires (every minute), so a hand edit — or a notification missed while the database was away — takes effect within a minute anyway.

Going from dormant to active binds the socket and starts submitting. Going from active to dormant — consent withdrawn — closes every producer connection, removes the socket, and discards whatever was gathered and not yet sent rather than making a final submission. An enabled daemon that cannot submit (no usable SYSTEM_ID, or a [pepsi-telemetry-client] section that does not parse) also stays dormant, and says why in its log and in its status row, instead of exiting into a restart loop.

Producers install their sink once, at start-up. pepsi-dispatch(1) listens on the same channel and retires its stage workers, so the pipeline starts (or stops) reporting without a restart; the long-lived pepsi-ingress(1) and pepsi-httpd(1) start reporting after their next restart. (After switching off nothing they send is received: the socket is gone.)

85.1.54.1.4.1. The status row

The daemon keeps one row in pepsi.telemetry_client: whether the file it last read has telemetry on, whether it is submitting, whether a usable SYSTEM_ID is configured — a boolean, never the identifier — a short reason when an enabled daemon is dormant, its version, and a heartbeat refreshed every minute. A clean stop deletes the row; a row older than three heartbeats reads as a daemon that is not running. pepsi-httpd(1), which may read the table and not write it, uses it to decide whether the setup console can offer to switch telemetry on (see Enabling from the console).

85.1.54.1.5. Enabling the service

pepsi.target deliberately does not start pepsi-telemetry-client.service, unlike the pipeline’s own daemons: the target is the single switch that starts the pipeline, so a unit it Wantsed would run on every deployment whatever the operator answered. (The unit is PartOf= the target, so stopping or restarting pepsi.target stops or restarts the telemetry client. That direction is wanted; only the pulling-in is not.)

Instead pepsi-setup(1) arms the unit at the end of a successful pepsi-setup run (which is also what the wizard offers to run for you) when SHARE_TELEMETRY is on: enable --now. When it is off, setup leaves the unit exactly as the operator left it — it never starts it, and it no longer stops it: a running daemon is dormant and submits nothing, and keeping it running is what lets the browser console offer to switch telemetry on later. Either way setup then sends the telemetry_changed notification, so a running daemon follows the new answer at once (turning telemetry off takes effect immediately, not at the next heartbeat). A deployment that wants no telemetry daemon at all disables the unit (systemctl disable --now pepsi-telemetry-client.service); setup never undoes that while the answer is no.

On a host without systemd nothing is done and nothing is said about the unit — there is no unit to arm. Where systemd does not know the unit (a source install, say) setup says so only if telemetry is on, since a deployment that opted out has nothing to do either way. Without root it logs the one systemctl command to run.

With telemetry on and no valid SYSTEM_ID (setup was run without -c, so there was nowhere to write one) the unit is armed all the same — the daemon stays dormant and says why — and setup tells you to re-run pepsi-setup run -c <FILE> so an identifier can be generated.

85.1.54.1.5.1. Enabling from the console

The browser setup console (pepsi-httpd(1)) asks the same SHARE_TELEMETRY question, but it can only offer “yes” while this daemon is running and has a usable SYSTEM_ID — the console never generates an identifier, since minting one without consent is what opt-in rules out. When either is missing the question is shown disabled, with directions, and an API client that tries anyway is refused with 409 telemetry_client_not_ready. To make the console able to switch telemetry on, on the server:

  1. give [pepsi] an identifier: SYSTEM_ID = followed by 64 hexadecimal characters, e.g. the output of openssl rand -hex 32;

  2. start the daemon: systemctl enable --now pepsi-telemetry-client.service. It stays dormant, submitting nothing.

A console save that switches telemetry on then writes the file through the privileged applier, which notifies the daemon; one that switches it off does the same in the other direction. Switching off is never refused. A console save also keeps an existing SYSTEM_ID, whatever the answer: it re-renders the whole file, and used to drop the identifier (so that switching on again minted a different one).

85.1.54.1.6. Submitted data

Two submissions are made (see pepsi-telemetry(1) for the endpoints):

  • POST /telemetry/usage — the per-interval feature counts, attributed to the Pepsi version the daemon was built as.

  • POST /telemetry/features — the enabled-feature snapshot, derived from the cumulative set of features seen since the daemon started (a feature is reported enabled once it has been exercised at least once this run).

No personally identifying information is sent; the only identity is the random 256-bit SYSTEM_ID that pepsi-setup(1) generates.

85.1.54.1.7. Configuration

Global switches live in [pepsi] (shared with the producers):

SHARE_TELEMETRY

Master on/off switch. Opt-in: the default is no. Until it is set to yes the daemon stays dormant and the producer API does nothing.

SYSTEM_ID

The anonymous 256-bit identifier (64 hex characters) submitted with every report. Generated automatically by pepsi-setup(1) once SHARE_TELEMETRY is on — a deployment that has not opted in never has one generated for it; required before the daemon submits anything. An operator may add one by hand while telemetry is off (so that the console can offer the switch); that is the operator’s act, not setup’s.

Treat it as write-capability material, not as a public label. The collector never issues it and never checks it beyond its shape, and a /telemetry/features snapshot is authoritative for the (system_id, version) it names: it enables exactly the features it lists and marks every other stored one disabled. So anybody who learns this value can zero, or rewrite, this deployment’s whole contribution to the public report, and can inflate its usage counts. It is a 256-bit random value and is never echoed by GET /telemetry/report, so it cannot be guessed — but it sits in pepsi.conf, so do not paste that section into a bug report, support ticket or pastebin. Anonymity is unaffected either way; what leaks is the ability to forge this deployment’s numbers.

TELEMETRY_SERVER

Collector host (default telemetry.pepsi.taler.net). The daemon submits to https://<server>/telemetry/{usage,features}. A value containing an explicit scheme:// is honoured verbatim (e.g. http://localhost:18080 for local testing).

The daemon’s own listener/submission knobs live in [pepsi-telemetry-client]:

UNIXPATH

Local listening socket (default /run/pepsi-telemetry/socket). This is the same path the producers connect to, so changing it changes both sides.

UNIXPATH_GROUP, UNIXPATH_MODE

Group and mode of the socket (defaults pepsi-telemetry and 0660), so the pepsi (stage workers) and pepsi-ingress users can connect.

SUBMIT_INTERVAL

Interval between submissions (default 60 s). Use h/m/s units.

MAX_FEATURES

Cap on the number of distinct feature names held in memory (default 4096), bounding memory against a misbehaving local producer.

85.1.54.1.8. Global Options

serve is the only subcommand. These global options precede it (a trailing flag is rejected).

-c FILE, –config FILE

Read the configuration from FILE instead of searching the default locations ($XDG_CONFIG_HOME/pepsi.conf, $HOME/.config/pepsi.conf, /etc/pepsi/pepsi.conf, /etc/pepsi.conf). The shipped unit passes -c /etc/pepsi/pepsi.conf.

-L LOGLEVEL, –log LOGLEVEL

Set the logging verbosity. LOGLEVEL is one of error, warn, info, debug or trace (default: info).

-v, –verbose

Show log messages from all sources, including third-party libraries.

-h, –help

Print a usage summary and exit.

-V, –version

Print the version and exit.

85.1.54.1.9. Files

/run/pepsi-telemetry/socket

Default UNIX socket the daemon listens on. The daemon creates the socket itself; the directory around it comes from the unit’s RuntimeDirectory=pepsi-telemetry (mode 0755, with RuntimeDirectoryPreserve=yes so a stop does not unlink a socket still bound inside it), and belongs to this unit alone. pepsi-telemetry(1), the collector, listens in /run/pepsi-collector instead: systemd chowns a runtime directory and everything in it to the declaring unit’s User= on every start, so a collector socket in this directory would silently lose the front server’s group whenever this daemon started. Collector and client are meant for separate hosts in any case.

85.1.54.1.10. See also

pepsi-telemetry(1), pepsi-ingress(1), pepsi-setup(1), pepsi-httpd(1), pepsi-dispatch(1), pepsi.conf(5).