github.com/netdata/go.d.plugin@v0.58.1/modules/chrony/collect.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package chrony
     4  
     5  import (
     6  	"fmt"
     7  	"time"
     8  )
     9  
    10  const scaleFactor = 1000000000
    11  
    12  func (c *Chrony) collect() (map[string]int64, error) {
    13  	if c.client == nil {
    14  		client, err := c.newClient(c.Config)
    15  		if err != nil {
    16  			return nil, err
    17  		}
    18  		c.client = client
    19  	}
    20  
    21  	mx := make(map[string]int64)
    22  
    23  	if err := c.collectTracking(mx); err != nil {
    24  		return nil, err
    25  	}
    26  	if err := c.collectActivity(mx); err != nil {
    27  		return mx, err
    28  	}
    29  
    30  	return mx, nil
    31  }
    32  
    33  const (
    34  	// https://github.com/mlichvar/chrony/blob/7daf34675a5a2487895c74d1578241ca91a4eb70/ntp.h#L70-L75
    35  	leapStatusNormal         = 0
    36  	leapStatusInsertSecond   = 1
    37  	leapStatusDeleteSecond   = 2
    38  	leapStatusUnsynchronised = 3
    39  )
    40  
    41  func (c *Chrony) collectTracking(mx map[string]int64) error {
    42  	reply, err := c.client.Tracking()
    43  	if err != nil {
    44  		return fmt.Errorf("error on collecting tracking: %v", err)
    45  	}
    46  
    47  	mx["stratum"] = int64(reply.Stratum)
    48  	mx["leap_status_normal"] = boolToInt(reply.LeapStatus == leapStatusNormal)
    49  	mx["leap_status_insert_second"] = boolToInt(reply.LeapStatus == leapStatusInsertSecond)
    50  	mx["leap_status_delete_second"] = boolToInt(reply.LeapStatus == leapStatusDeleteSecond)
    51  	mx["leap_status_unsynchronised"] = boolToInt(reply.LeapStatus == leapStatusUnsynchronised)
    52  	mx["root_delay"] = int64(reply.RootDelay * scaleFactor)
    53  	mx["root_dispersion"] = int64(reply.RootDispersion * scaleFactor)
    54  	mx["skew"] = int64(reply.SkewPPM * scaleFactor)
    55  	mx["last_offset"] = int64(reply.LastOffset * scaleFactor)
    56  	mx["rms_offset"] = int64(reply.RMSOffset * scaleFactor)
    57  	mx["update_interval"] = int64(reply.LastUpdateInterval * scaleFactor)
    58  	// handle chrony restarts
    59  	if reply.RefTime.Year() != 1970 {
    60  		mx["ref_measurement_time"] = time.Now().Unix() - reply.RefTime.Unix()
    61  	}
    62  	mx["residual_frequency"] = int64(reply.ResidFreqPPM * scaleFactor)
    63  	// https://github.com/mlichvar/chrony/blob/5b04f3ca902e5d10aa5948fb7587d30b43941049/client.c#L1706
    64  	mx["current_correction"] = abs(int64(reply.CurrentCorrection * scaleFactor))
    65  	mx["frequency"] = abs(int64(reply.FreqPPM * scaleFactor))
    66  
    67  	return nil
    68  }
    69  
    70  func (c *Chrony) collectActivity(mx map[string]int64) error {
    71  	reply, err := c.client.Activity()
    72  	if err != nil {
    73  		return fmt.Errorf("error on collecting activity: %v", err)
    74  	}
    75  
    76  	mx["online_sources"] = int64(reply.Online)
    77  	mx["offline_sources"] = int64(reply.Offline)
    78  	mx["burst_online_sources"] = int64(reply.BurstOnline)
    79  	mx["burst_offline_sources"] = int64(reply.BurstOffline)
    80  	mx["unresolved_sources"] = int64(reply.Unresolved)
    81  
    82  	return nil
    83  }
    84  
    85  func boolToInt(v bool) int64 {
    86  	if v {
    87  		return 1
    88  	}
    89  	return 0
    90  }
    91  
    92  func abs(v int64) int64 {
    93  	if v < 0 {
    94  		return -v
    95  	}
    96  	return v
    97  }