PTP Metrics Exporter API v1¶
This section contains the API reference for the PTP Metrics Exporter.
The application pod runs as a DaemonSet on nodes labeled
ptp-metrics-exporter=enabled. It collects PTP synchronization statistics
from ptp4l (via UDS), phc2sys and ts2phc (via monitoring sockets), and exposes
them in OpenMetrics format.
For in-cluster access (e.g., from Prometheus or other monitoring tools), use the Kubernetes service DNS name:
ptp-metrics-exporter.ptp-metrics-exporter.svc.cluster.local:9110
This headless service (clusterIP: None) resolves directly to the pod IPs
of the exporter DaemonSet on each node. Individual pods can also be reached
via their host IP or pod IP on port 9110.
Endpoints¶
Provides OpenMetrics-formatted statistics for all PTP instances configured on the node, including ptp4l, phc2sys, and ts2phc sources.
Normal response codes
200
Request parameters
None
Response parameters
PTP statistics in OpenMetrics format.
# HELP ptp_exporter_build Exporter build identification
# TYPE ptp_exporter_build info
ptp_exporter_build_info{node="controller-0",python="3.11.15",version="1.0.0"} 1.0
# HELP ptp_grandmaster_clock_class IEEE 1588 Grandmaster clock class
# TYPE ptp_grandmaster_clock_class gauge
ptp_grandmaster_clock_class{domain="0",gm_identity="001e67fffe0a1234",instance="ptpinst0",node="controller-0"} 6.0
# HELP ptp_grandmaster_clock_accuracy IEEE 1588 Grandmaster clock accuracy
# TYPE ptp_grandmaster_clock_accuracy gauge
ptp_grandmaster_clock_accuracy{domain="0",gm_identity="001e67fffe0a1234",instance="ptpinst0",node="controller-0"} 33.0
# HELP ptp_grandmaster_clock_variance IEEE 1588 Grandmaster offset scaled log variance
# TYPE ptp_grandmaster_clock_variance gauge
ptp_grandmaster_clock_variance{domain="0",gm_identity="001e67fffe0a1234",instance="ptpinst0",node="controller-0"} 20061.0
# HELP ptp_grandmaster_priority1 BMCA Grandmaster Priority1
# TYPE ptp_grandmaster_priority1 gauge
ptp_grandmaster_priority1{domain="0",gm_identity="001e67fffe0a1234",instance="ptpinst0",node="controller-0"} 128.0
# HELP ptp_grandmaster_priority2 BMCA Grandmaster Priority2
# TYPE ptp_grandmaster_priority2 gauge
ptp_grandmaster_priority2{domain="0",gm_identity="001e67fffe0a1234",instance="ptpinst0",node="controller-0"} 128.0
# HELP ptp_grandmaster_identity Grandmaster clock identity
# TYPE ptp_grandmaster_identity info
ptp_grandmaster_identity_info{domain="0",gm_identity="001e67fffe0a1234",iface="ens1f0",instance="ptpinst0",node="controller-0"} 1.0
# HELP ptp_time_traceable 1 if time is traceable to a primary reference, 0 otherwise
# TYPE ptp_time_traceable gauge
ptp_time_traceable{domain="0",instance="ptpinst0",node="controller-0"} 1.0
# HELP ptp_sync_state 1 if synchronized, 0 otherwise
# TYPE ptp_sync_state gauge
ptp_sync_state{domain="0",instance="ptpinst0",node="controller-0"} 1.0
# HELP ptp_offset_from_master_ns PTP slave clock offset to master in nanoseconds
# TYPE ptp_offset_from_master_ns gauge
ptp_offset_from_master_ns{domain="0",instance="ptpinst0",node="controller-0"} -42.0
# HELP ptp_mean_path_delay_ns Mean path delay in nanoseconds
# TYPE ptp_mean_path_delay_ns gauge
ptp_mean_path_delay_ns{domain="0",instance="ptpinst0",node="controller-0"} 312.0
# HELP ptp_port_state IEEE 1588 port state enumeration
# TYPE ptp_port_state gauge
ptp_port_state{domain="0",iface="ens1f0",instance="ptpinst0",node="controller-0"} 9.0
# HELP ptp_offset_rms_ns RMS of PTP offset in nanoseconds
# TYPE ptp_offset_rms_ns gauge
ptp_offset_rms_ns{domain="0",iface="ens1f0",instance="ptpinst0",node="controller-0"} 51.0
# HELP ptp_offset_mean_ns Mean PTP offset in nanoseconds
# TYPE ptp_offset_mean_ns gauge
ptp_offset_mean_ns{domain="0",iface="ens1f0",instance="ptpinst0",node="controller-0"} -10.0
# HELP ptp_offset_stddev_ns Standard deviation of PTP offset in nanoseconds
# TYPE ptp_offset_stddev_ns gauge
ptp_offset_stddev_ns{domain="0",iface="ens1f0",instance="ptpinst0",node="controller-0"} 50.0
# HELP ptp_instance_summary_interval summary_interval config value (0=no meaningful aggregation)
# TYPE ptp_instance_summary_interval gauge
ptp_instance_summary_interval{domain="0",instance="ptpinst0",node="controller-0"} 6.0
# HELP ptp_sync_messages_received Total Sync messages received
# TYPE ptp_sync_messages_received counter
ptp_sync_messages_received_total{domain="0",iface="ens1f0",instance="ptpinst0",node="controller-0"} 15230.0
# HELP ptp_sync_messages_lost Total Sync messages lost (sequence gaps)
# TYPE ptp_sync_messages_lost counter
ptp_sync_messages_lost_total{domain="0",iface="ens1f0",instance="ptpinst0",node="controller-0"} 0.0
# HELP ptp_sync_timeout_events Total Sync timeout events
# TYPE ptp_sync_timeout_events counter
ptp_sync_timeout_events_total{domain="0",iface="ens1f0",instance="ptpinst0",node="controller-0"} 0.0
# HELP ptp_announce_timeout_events Total announce timeout events
# TYPE ptp_announce_timeout_events counter
ptp_announce_timeout_events_total{domain="0",iface="ens1f0",instance="ptpinst0",node="controller-0"} 2.0
# HELP ptp_sync_mismatch Total Sync/FollowUp mismatch events
# TYPE ptp_sync_mismatch counter
ptp_sync_mismatch_total{domain="0",iface="ens1f0",instance="ptpinst0",node="controller-0"} 0.0
# HELP ptp_followup_mismatch Total FollowUp mismatch events
# TYPE ptp_followup_mismatch counter
ptp_followup_mismatch_total{domain="0",iface="ens1f0",instance="ptpinst0",node="controller-0"} 0.0
# HELP ptp_gm_transition Total Grandmaster identity transitions
# TYPE ptp_gm_transition counter
ptp_gm_transition_total{domain="0",instance="ptpinst0",node="controller-0"} 1.0
# HELP ptp_phc_adjustment_ns Servo-filtered PHC-to-system-clock offset in nanoseconds
# TYPE ptp_phc_adjustment_ns gauge
ptp_phc_adjustment_ns{clock="ens1f0",domain="0",instance="phcinst0",node="controller-0"} 54.0
# HELP ptp_phc_delay_ns Estimated delay between PHC and system clock in nanoseconds
# TYPE ptp_phc_delay_ns gauge
ptp_phc_delay_ns{clock="ens1f0",domain="0",instance="phcinst0",node="controller-0"} 0.0
# HELP ptp_phc_offset_rms_ns Windowed RMS of PHC-to-system-clock offset in nanoseconds
# TYPE ptp_phc_offset_rms_ns gauge
ptp_phc_offset_rms_ns{clock="ens1f0",domain="0",instance="phcinst0",node="controller-0"} 73.0
# HELP ptp_phc_offset_stddev_ns Windowed standard deviation of PHC offset in nanoseconds
# TYPE ptp_phc_offset_stddev_ns gauge
ptp_phc_offset_stddev_ns{clock="ens1f0",domain="0",instance="phcinst0",node="controller-0"} 35.0
# HELP ptp_phc_offset_max_abs_ns Maximum absolute offset in current stats window in nanoseconds
# TYPE ptp_phc_offset_max_abs_ns gauge
ptp_phc_offset_max_abs_ns{clock="ens1f0",domain="0",instance="phcinst0",node="controller-0"} 105.0
# HELP ptp_phc_offset_num_samples Number of samples in most recent stats window
# TYPE ptp_phc_offset_num_samples gauge
ptp_phc_offset_num_samples{clock="ens1f0",domain="0",instance="phcinst0",node="controller-0"} 8.0
# HELP ptp_phc2sys_utc_offset_seconds TAI-UTC offset configured for phc2sys (-O option)
# TYPE ptp_phc2sys_utc_offset_seconds gauge
ptp_phc2sys_utc_offset_seconds{instance="phcinst0",node="controller-0"} 37.0
# HELP ptp_ts2phc_offset_ns ts2phc servo offset in nanoseconds
# TYPE ptp_ts2phc_offset_ns gauge
ptp_ts2phc_offset_ns{clock="NMEA0",instance="tsinst0",node="controller-0"} 150.0
# HELP ptp_ts2phc_delay_ns ts2phc delay in nanoseconds (-1 = unavailable)
# TYPE ptp_ts2phc_delay_ns gauge
ptp_ts2phc_delay_ns{clock="NMEA0",instance="tsinst0",node="controller-0"} -1.0
# HELP ptp_exporter_collection_errors Number of failed collection attempts
# TYPE ptp_exporter_collection_errors counter
ptp_exporter_collection_errors_total{instance="ptpinst0",node="controller-0"} 0.0
ptp_exporter_collection_errors_total{instance="phcinst0",node="controller-0"} 0.0
ptp_exporter_collection_errors_total{instance="tsinst0",node="controller-0"} 0.0
# HELP ptp_exporter_collection_duration_seconds Duration of most recent collection cycle
# TYPE ptp_exporter_collection_duration_seconds gauge
ptp_exporter_collection_duration_seconds{instance="ptpinst0",node="controller-0"} 0.000453
ptp_exporter_collection_duration_seconds{instance="phcinst0",node="controller-0"} 0.001012
ptp_exporter_collection_duration_seconds{instance="tsinst0",node="controller-0"} 0.000142
# HELP ptp_exporter_source_state Probe state: 0=unknown, 1=enabled, 2=disabled
# TYPE ptp_exporter_source_state gauge
ptp_exporter_source_state{instance="ptpinst0",node="controller-0",source="offset_stats_np"} 1.0
ptp_exporter_source_state{instance="ptpinst0",node="controller-0",source="sync_lost_field"} 1.0
ptp_exporter_source_state{instance="phcinst0",node="controller-0",source="phc2sys_mon_socket"} 1.0
ptp_exporter_source_state{instance="tsinst0",node="controller-0",source="ts2phc_mon_socket"} 1.0
# HELP ptp_exporter_last_success_seconds Unix timestamp of last successful collection
# TYPE ptp_exporter_last_success_seconds gauge
ptp_exporter_last_success_seconds{instance="ptpinst0",node="controller-0"} 1.7836136875e+09
ptp_exporter_last_success_seconds{instance="phcinst0",node="controller-0"} 1.7836136868e+09
ptp_exporter_last_success_seconds{instance="tsinst0",node="controller-0"} 1.7836136870e+09
# EOF
Returns 200 if the exporter process is alive. Used as the Kubernetes liveness probe target.
Normal response codes
200
Returns 200 after the first successful collection cycle completes. Returns 503 during startup before any data is available. Used as the Kubernetes readiness probe target.
Normal response codes
200
Error response codes
serviceUnavailable (503)
Deployment Prerequisites¶
linuxptp patches — The host must run the patched linuxptp that provides:
Read-only UDS socket for ptp4l (
uds_ro_address)OFFSET_STATS_NP management TLV (
summary_interval > 0)PORT_SERVICE_STATS_NP with
sync_lostfieldMonitoring socket for phc2sys (
mon_socket_path)Monitoring socket for ts2phc (
mon_socket_path)
PTP instance configuration — Config files must exist at
/etc/linuxptp/ptpinstance/in the format:ptp4l-<instance>.conf— containsuds_ro_addressin[global]phc2sys-<instance>.conf— containsmon_socket_pathin[global]ts2phc-<instance>.conf— containsmon_socket_pathin[global]
Node label — Target nodes must be labeled:
~(keystone_admin)]$ system host-label-assign <hostname> ptp-metrics-exporter=enabled
Application upload and apply:
~(keystone_admin)]$ system application-upload ptp-metrics-exporter-<version>.tgz ~(keystone_admin)]$ system application-apply ptp-metrics-exporter
Configuration Parameters¶
The exporter is configured via Helm chart values. Overrides can be applied
using system helm-override-update.
Parameter |
Default |
Description |
|---|---|---|
|
|
How often (seconds) to poll ptp4l via UDS |
|
|
How often (seconds) to poll phc2sys monitoring socket |
|
|
How often (seconds) to poll ts2phc monitoring socket |
|
|
How often to re-probe disabled data sources (e.g., OFFSET_STATS_NP) |
|
|
Comma-separated clock classes considered “locked” for sync_state |
|
|
Log verbosity (DEBUG, INFO, WARNING, ERROR) |
|
|
TCP port for the metrics HTTP endpoint |
|
|
Node label selector for DaemonSet scheduling |
|
|
CPU request |
|
|
CPU limit |
|
|
Memory request |
|
|
Memory limit |
Override example:
~(keystone_admin)]$ system helm-override-update ptp-metrics-exporter \
ptp-metrics-exporter ptp-metrics-exporter \
--set exporter.collectionIntervalPtp4lSeconds=2
Then re-apply:
~(keystone_admin)]$ system application-apply ptp-metrics-exporter
Metrics Reference¶
Grandmaster Quality¶
Metric |
Type |
Labels |
Description |
|---|---|---|---|
|
Gauge |
domain, gm_identity, instance, node |
IEEE 1588 clock class (6=locked, 7=holdover, 135=holdover-in-spec) |
|
Gauge |
domain, gm_identity, instance, node |
IEEE 1588 clock accuracy enumeration |
|
Gauge |
domain, gm_identity, instance, node |
Scaled log variance of GM offset |
|
Gauge |
domain, gm_identity, instance, node |
BMCA Priority1 field |
|
Gauge |
domain, gm_identity, instance, node |
BMCA Priority2 field |
|
Info |
domain, gm_identity, iface, instance, node |
GM clock identity (info metric, value always 1) |
|
Gauge |
domain, instance, node |
1 if time is traceable to primary reference, 0 otherwise |
Sync Quality¶
Metric |
Type |
Labels |
Description |
|---|---|---|---|
|
Gauge |
domain, instance, node |
Current slave-to-master offset (nanoseconds) |
|
Gauge |
domain, instance, node |
Mean path delay (nanoseconds) |
|
Gauge |
domain, instance, node |
1=synchronized, 0=not synchronized, NaN=unknown |
|
Gauge |
domain, iface, instance, node |
IEEE 1588 port state (9=SLAVE, 6=MASTER, 3=LISTENING, etc.) |
Offset Stability (requires summary_interval > 0)¶
Metric |
Type |
Labels |
Description |
|---|---|---|---|
|
Gauge |
domain, iface, instance, node |
Root mean square of offset over summary window |
|
Gauge |
domain, iface, instance, node |
Mean offset over summary window |
|
Gauge |
domain, iface, instance, node |
Standard deviation of offset over summary window |
|
Gauge |
domain, instance, node |
Configured summary_interval value (0=no meaningful aggregation) |
phc2sys Servo¶
Metric |
Type |
Labels |
Description |
|---|---|---|---|
|
Gauge |
clock, domain, instance, node |
PHC-to-system-clock servo offset (nanoseconds) |
|
Gauge |
clock, domain, instance, node |
Estimated delay between PHC and system clock |
|
Gauge |
clock, domain, instance, node |
Windowed RMS of PHC offset |
|
Gauge |
clock, domain, instance, node |
Windowed standard deviation of PHC offset |
|
Gauge |
clock, domain, instance, node |
Maximum absolute offset in stats window |
|
Gauge |
clock, domain, instance, node |
Number of samples in stats window |
|
Gauge |
instance, node |
TAI-UTC offset configured for phc2sys (-O option) |
ts2phc (GNSS-synced GM nodes)¶
Metric |
Type |
Labels |
Description |
|---|---|---|---|
|
Gauge |
instance, clock, node |
ts2phc servo offset (nanoseconds) |
|
Gauge |
instance, clock, node |
ts2phc delay (-1 sentinel = delay unavailable) |
Message Sync/Loss Counters¶
Metric |
Type |
Labels |
Description |
|---|---|---|---|
|
Counter |
domain, iface, instance, node |
Total Sync messages received |
|
Counter |
domain, iface, instance, node |
Expected Sync messages not received (sequence gaps) |
|
Counter |
domain, iface, instance, node |
Port state changes due to sync timeout |
|
Counter |
domain, iface, instance, node |
Announce receipt timeout events |
|
Counter |
domain, iface, instance, node |
Sync/FollowUp mismatch events |
|
Counter |
domain, iface, instance, node |
FollowUp mismatch events |
|
Counter |
domain, instance, node |
Number of Grandmaster identity transitions |
Self-Monitoring¶
Metric |
Type |
Labels |
Description |
|---|---|---|---|
|
Counter |
instance, node |
Failed collection attempts per instance |
|
Gauge |
instance, node |
Duration of most recent collection cycle |
|
Gauge |
instance, node, source |
Probe state: 0=unknown, 1=enabled, 2=disabled |
|
Gauge |
instance, node |
Unix timestamp of last successful collection |
|
Info |
node, version, python |
Build identification |
Troubleshooting¶
Exporter pods not scheduling¶
Verify the node label:
~(keystone_admin)]$ system host-label-list <hostname> | grep ptp-metrics-exporter
If missing, assign it:
~(keystone_admin)]$ system host-label-assign <hostname> ptp-metrics-exporter=enabled
Metrics returning NaN¶
ptp4l not running or UDS socket missing: check that
/var/run/ptp4l-<instance>-roexists on the host.phc2sys/ts2phc not patched: verify
mon_socket_pathis present in the daemon config and the socket file exists.summary_intervalnot configured or set to 0: stability metrics (ptp_offset_rms_ns,ptp_offset_mean_ns,ptp_offset_stddev_ns) will report NaN because no meaningful aggregation occurs with a single sample.
Collection errors incrementing¶
Check ptp_exporter_source_state:
0(unknown) — probe pending, will be attempted at nextNP_PROBE_INTERVAL_Sboundary.1(enabled) — source healthy and being collected.2(disabled) — source returned error on probe. Will re-probe periodically. Check that the daemon is running and socket exists.
Pod CrashLoopBackOff¶
Check logs:
~(keystone_admin)]$ kubectl -n ptp-metrics-exporter logs -l app=ptp-metrics-exporter
Verifying metrics endpoint manually¶
From the host:
~(keystone_admin)]$ curl http://<pod-ip>:9110/metrics
~(keystone_admin)]$ curl http://<pod-ip>:9110/healthz
~(keystone_admin)]$ curl http://<pod-ip>:9110/readyz
Architecture Note¶
The exporter runs as a DaemonSet with one pod per labeled node. Each pod:
Watches
/host/etc/linuxptp/ptpinstance/for config file changes (inotify)For each discovered ptp4l instance, polls via SOCK_DGRAM UDS at the configured interval
For each phc2sys/ts2phc instance, connects to the monitoring socket (SOCK_STREAM, JSON protocol)
Stores collected data in an in-memory snapshot (not on-demand per HTTP request)
Serves
/metricsfrom the snapshot — HTTP serving never blocks on collection
Volume mounts:
Container Path |
Host Path |
Mode |
Purpose |
|---|---|---|---|
|
|
RW |
UDS sockets (exporter creates reply socket for DGRAM) |
|
|
RO |
psutil reads phc2sys/ts2phc cmdline for config discovery |
|
|
RO |
Configuration watcher (inotify) |
|
emptyDir (memory-backed, 32Mi) |
RW |
Python tempfiles |
Security context:
Runs as non-root (UID 65534 / nobody)
Read-only root filesystem
All Linux capabilities dropped
No privilege escalation