Connecting external monitoring systems

pss-metrics — a universal metrics exporter for Perfect Streamer

A single Python 3 CLI script that retrieves statistics from the HTTP API of the PSS web server and produces output for the most common monitoring systems:

  • Zabbix (UserParameter, Low-Level Discovery, zabbix_sender trapper)

  • Prometheus (text exposition format for the textfile collector)

  • InfluxDB / Telegraf (line protocol or JSON for the exec input)

  • Generic JSON for custom scripts and Nagios-style health checks

The exporter needs no third-party dependencies: it uses only the Python 3.6+ standard library (urllib, xml.etree, json, argparse).

Files

pss-metrics.py                    main CLI (executable)
userparameter_pss.conf.example    UserParameter template for Zabbix

Installation

The exporter is shipped as /opt/pss/monitoring/pss-metrics.py. Make sure that Python 3.6 or later is installed:

# RHEL / Rocky / AlmaLinux
yum install -y python3

# Debian / Ubuntu
apt-get install -y python3

No additional packages are required.

Configuration

By default, pss-metrics connects to the node over the loopback address and determines the web server port from /opt/pss/config/pss.json. If that file can be read, it decides: the port comes from its web-server.bind-port key, and without that key it is 43971, the built-in value of the service. The file /opt/pss/config/pss_default.json is read only if there is no pss.json; if the port could not be read from either file, http://127.0.0.1:43971 is used. With the -v flag, the exporter reports which file the port was taken from. The parameters can be overridden with environment variables, the /etc/pss-metrics.conf file (key=value format) or command-line flags. Priority: CLI > env > file > defaults. PSS_URL set in any of these ways turns port auto-detection off. Before version 2.0.2.421, PSS_URL from the file did not turn auto-detection off, and a pss.json without a port key led to port 8808 from pss_default.json.

Since version 2.0.2.420, pss.json is readable only by the pss service user (the file holds passwords). An exporter run as another user (zabbix, telegraf) cannot read the port from the file and connects to port 43971; if the node’s web server runs on another port, set PSS_URL.

Supported variables:

PSS_URL          full URL, e.g. http://10.0.0.1:8808          (auto by default)
PSS_USER         login sent as HTTP Basic (for a proxy in front of PSS, see below)
PSS_PASS         password for PSS_USER
PSS_TIMEOUT      HTTP timeout, in seconds                      (default 5)
PSS_CACHE_DIR    cache directory                               (default /run/pss-metrics)
PSS_CACHE_TTL    cache TTL, in seconds                         (default 10)
PSS_CA_BUNDLE    path to CA bundle for HTTPS
PSS_INSECURE     1 — disable TLS certificate verification
PSS_VERBOSE      1 — log requests to stderr

Caching: each run performs at most one HTTP GET per endpoint within the TTL window. With TTL=10 s, even hundreds of UserParameter checks per minute result in about 6 HTTP requests per minute to each API endpoint.

Quick start

Health check (Nagios-style exit codes):

pss-metrics.py health
# OK: total=42 running=15 stopped=27 unhealthy=0 version=<version>

Zabbix LLD discovery:

pss-metrics.py discover streams
pss-metrics.py discover inputs --running-only
pss-metrics.py discover outputs

Retrieving a single metric (for use in a Zabbix UserParameter):

pss-metrics.py get summary.running
pss-metrics.py get stream.10031.bitrate
pss-metrics.py get input.10031.1.speed1
pss-metrics.py get output.10031.1.speed
pss-metrics.py get sysmon.cpu.self-usage
pss-metrics.py get server.server-version

Full export:

pss-metrics.py dump --format=json
pss-metrics.py dump --format=prometheus
pss-metrics.py dump --format=influx
pss-metrics.py dump --format=zabbix-trapper --zabbix-host=streamer-01

Metric paths

pss-metrics get accepts a dot-separated path. Empty output means “no value” (for example, the metric exists only for running streams).

server.<attr>                e.g. server.server-version, server.uptime
summary.<key>                total | running | stopped | unhealthy |
                             input_bitrate_kbps | output_bitrate_kbps
sysmon.cpu.<attr>            self-usage | total-usage | cores
sysmon.memory.<attr>         self-usage-kb | available-kb | total-kb
sysmon.netbw.<iface>.<attr>  rx-bw | tx-bw  (interface name as in XML)
stream.<id>.<attr>           any <stream> attribute
input.<sid>.<iid>.<attr>     any <input> attribute
output.<sid>.<oid>.<attr>    any <output> attribute

Useful per-stream attributes (from /data/stream/detail):

stream:  state, state-str, bitrate, thread-usage, mpts
input:   speed1, recv-bytes, recv-packets, recv-err,
         stat-disc, stat-disc1, stat-scrambled, stat-scrambled1,
         health-state-good, health-status, check-status
output:  speed, sent-bytes, sent-packets, sent-err, uri, type

The rates are given in kilobits per second: speed1 on an input, speed on an output. The speed attribute exists only on UDP outputs; for the other output types the rate is derived from the increment of sent-bytes over your own polling interval.

Zabbix integration

Two scenarios are supported; choose the one that suits your environment.

  1. Static UserParameter + LLD (Zabbix agent v1 / v2)

    Copy userparameter_pss.conf.example to /etc/zabbix/zabbix_agentd.d/pss.conf, restart zabbix-agent and import on the server a template with LLD prototypes that use the pss.discover keys. Example bindings:

    UserParameter=pss.discover[*],/opt/pss/monitoring/pss-metrics.py discover $1
    UserParameter=pss.get[*],/opt/pss/monitoring/pss-metrics.py get $1
    UserParameter=pss.health,/opt/pss/monitoring/pss-metrics.py health
    

    On the Zabbix server:

    Discovery rule key:        pss.discover[streams]
    Item prototype keys:       pss.get[input.{#STREAM_ID}.1.speed1]
                               pss.get[stream.{#STREAM_ID}.bitrate]
                               pss.get[summary.unhealthy]
    
  2. Trapper (push) via zabbix_sender

    Run it on a timer (cron / systemd) and pipe the output:

    /opt/pss/monitoring/pss-metrics.py dump --format=zabbix-trapper \
        --zabbix-host="$(hostname)" \
      | zabbix_sender -z zabbix.example.com -i -
    

Prometheus integration

Two options.

  1. Textfile collector (recommended for one-shot environments).

    Run a periodic export via a systemd timer or cron:

    */1 * * * * /opt/pss/monitoring/pss-metrics.py dump --format=prometheus \
        > /var/lib/node_exporter/textfile_collector/pss.prom.$$ \
        && mv /var/lib/node_exporter/textfile_collector/pss.prom.$$ \
              /var/lib/node_exporter/textfile_collector/pss.prom
    

    node_exporter will serve the file via –collector.textfile.directory.

  2. Direct scraping through a small wrapper (for example, socat + pss-metrics dump) or any third-party HTTP proxy of your choice.

Telegraf / InfluxDB integration

Telegraf inputs.exec:

[[inputs.exec]]
  commands = ["/opt/pss/monitoring/pss-metrics.py dump --format=influx"]
  interval = "10s"
  timeout  = "5s"
  data_format = "influx"

For the JSON parser, use –format=json and configure data_format = “json”, specifying the field paths.

HTTPS and authentication

The exporter is intended to run on the node itself: the PSS web server accepts requests from the local address without authorisation. The PSS_USER/PSS_PASS variables are passed as HTTP Basic credentials, which are useful when access to the API is published through an intermediate proxy with Basic authorisation; the exporter does not pass the PSS web server’s own Digest authorisation.

Access over HTTPS:

PSS_URL=https://streamer.example.com:43981 pss-metrics.py health

Self-signed certificates: set PSS_INSECURE=1 (not recommended) or specify PSS_CA_BUNDLE=/path/to/ca.pem.

Exit codes

pss-metrics follows the Nagios convention:

0  OK
1  WARNING       (e.g. running streams report unhealthy)
2  CRITICAL      (PSS is unreachable)
3  UNKNOWN       (invalid arguments / internal error)

get prints an empty string and exits with code 0 if the requested entity does not exist: Zabbix treats an empty value as “NOT_SUPPORTED” rather than as an agent failure.

Troubleshooting

pss-metrics.py -v health        # log every HTTP request to stderr
pss-metrics.py --cache-ttl=0 …  # bypass cache while debugging
rm -rf /run/pss-metrics         # purge cache