API
sysMonitor.hpp
Go to the documentation of this file.
1 /** \file sysMonitor.hpp
2  * \brief The MagAO-X sysMonitor app main program which provides functions to read and report system statistics
3  * \author Chris Bohlman (cbohlman@pm.me)
4  *
5  * To view logdump files: logdump -f sysMonitor
6  *
7  * To view sysMonitor with cursesIndi:
8  * 1. /opt/MagAOX/bin/xindiserver -n xindiserverMaths
9  * 2. /opt/MagAOX/bin/sysMonitor -n sysMonitor
10  * 3. /opt/MagAOX/bin/cursesINDI
11  *
12  * \ingroup sysMonitor_files
13  *
14  * History:
15  * - 2018-08-10 created by CJB
16  */
17 #ifndef sysMonitor_hpp
18 #define sysMonitor_hpp
19 
20 #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
21 #include "../../magaox_git_version.h"
22 
23 #include <iostream>
24 #include <string>
25 #include <fstream>
26 #include <vector>
27 #include <sstream>
28 #include <algorithm>
29 #include <iterator>
30 #include <sys/wait.h>
31 
32 
33 namespace MagAOX
34 {
35 namespace app
36 {
37 
38 /** MagAO-X application to read and report system statistics
39  *
40  */
41 class sysMonitor : public MagAOXApp<>, public dev::telemeter<sysMonitor>
42 {
43 
44  friend class dev::telemeter<sysMonitor>;
45 
46 protected:
47  int m_warningCoreTemp = 0; ///< User defined warning temperature for CPU cores
48  int m_criticalCoreTemp = 0; ///< User defined critical temperature for CPU cores
49  int m_warningDiskTemp = 0; ///< User defined warning temperature for drives
50  int m_criticalDiskTemp = 0; ///< User defined critical temperature for drives
51 
52  pcf::IndiProperty m_indiP_core_loads; ///< Indi variable for reporting CPU core loads
53  pcf::IndiProperty m_indiP_core_temps; ///< Indi variable for reporting CPU core temperature(s)
54  pcf::IndiProperty m_indiP_drive_temps; ///< Indi variable for reporting drive temperature(s)
55  pcf::IndiProperty m_indiP_usage; ///< Indi variable for reporting drive usage of all paths
56 
57  std::vector<float> m_coreTemps; ///< List of current core temperature(s)
58  std::vector<float> m_coreLoads; ///< List of current core load(s)
59 
60  std::vector<std::string> m_diskNameList; ///< vector of names of the hard disks to monitor
61  std::vector<std::string> m_diskNames; ///< vector of names of the hard disks returned by hdd_temp
62  std::vector<float> m_diskTemps; ///< vector of current disk temperature(s)
63 
64  float m_rootUsage = 0; ///< Disk usage in root path as a value out of 100
65  float m_dataUsage = 0; ///< Disk usage in /data path as a value out of 100
66  float m_bootUsage = 0; ///< Disk usage in /boot path as a value out of 100
67  float m_ramUsage = 0; ///< RAM usage as a decimal value between 0 and 1
68 
69  /// Updates Indi property values of all system statistics
70  /** This includes updating values for core loads, core temps, drive temps, / usage, /boot usage, /data usage, and RAM usage
71  * Unsure if this method can fail in any way, as of now always returns 0
72  *
73  * \TODO: Check to see if any method called in here can fail
74  * \returns 0 on completion
75  */
76  int updateVals();
77 
78 public:
79 
80  /// Default c'tor.
81  sysMonitor();
82 
83  /// D'tor, declared and defined for noexcept.
84  ~sysMonitor() noexcept
85  {
86  }
87 
88  /// Setup the user-defined warning and critical values for core and drive temperatures
89  virtual void setupConfig();
90 
91  /// Load the warning and critical temperature values for core and drive temperatures
92  virtual void loadConfig();
93 
94  /// Registers all new Indi properties for each of the reported values to publish
95  virtual int appStartup();
96 
97  /// Implementation of reading and logging each of the measured statistics
98  virtual int appLogic();
99 
100  /// Do any needed shutdown tasks; currently nothing in this app
101  virtual int appShutdown();
102 
103 
104  /// Finds all CPU core temperatures
105  /** Makes system call and then parses result to add temperatures to vector of values
106  *
107  * \returns -1 on error with system command or output reading
108  * \returns 0 on successful completion otherwise
109  */
110  int findCPUTemperatures( std::vector<float>& /**< [out] the vector of measured CPU core temperatures*/ );
111 
112 
113  /// Parses string from system call to find CPU temperatures
114  /** When a valid string is read in, the value from that string is stored
115  *
116  * \returns -1 on invalid string being read in
117  * \returns 0 on completion and storing of value
118  */
119  int parseCPUTemperatures( std::string, /**< [in] the string to be parsed*/
120  float& /**< [out] the return value from the string*/
121  );
122 
123 
124  /// Checks if any core temperatures are warning or critical levels
125  /** Warning and critical temperatures are either user-defined or generated based on initial core temperature values
126  *
127  * \returns 1 if a temperature value is at the warning level
128  * \returns 2 if a temperature value is at critical level
129  * \returns 0 otherwise (all temperatures are considered normal)
130  */
131  int criticalCoreTemperature( std::vector<float>& /**< [in] the vector of temperature values to be checked*/ );
132 
133  /// Finds all CPU core usage loads
134  /** Makes system call and then parses result to add usage loads to vector of values
135  *
136  * \returns -1 on error with system command or output file reading
137  * \returns 0 on completion
138  */
139  int findCPULoads( std::vector<float>& /**< [out] the vector of measured CPU usages*/ );
140 
141 
142  /// Parses string from system call to find CPU usage loads
143  /** When a valid string is read in, the value from that string is stored
144  *
145  * \returns -1 on invalid string being read in
146  * \returns 0 on completion and storing of value
147  */
148  int parseCPULoads( std::string, /**< [in] the string to be parsed*/
149  float& /**< [out] the return value from the string*/
150  );
151 
152 
153  /// Finds all drive temperatures
154  /** Makes 'hddtemp' system call and then parses result to add temperatures to vector of values
155  * For hard drive temp utility:
156  * `wget http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/h/hddtemp-0.3-0.31.beta15.el7.x86_64.rpm`
157  * `su`
158  * `rpm -Uvh hddtemp-0.3-0.31.beta15.el7.x86_64.rpm`
159  * Check install with rpm -q -a | grep -i hddtemp
160  *
161  * \returns -1 on error with system command or output reading
162  * \returns 0 on successful completion otherwise
163  */
164  int findDiskTemperature( std::vector<std::string> & hdd_names, ///< [out] the names of the drives reported by hddtemp
165  std::vector<float> & hdd_temps ///< [out] the vector of measured drive temperatures
166  );
167 
168 
169  /// Parses string from system call to find drive temperatures
170  /** When a valid string is read in, the drive name and value from that string is stored
171  *
172  * \returns -1 on invalid string being read in
173  * \returns 0 on completion and storing of value
174  */
175  int parseDiskTemperature( std::string & driveName, ///< [out] the name of the drive
176  float & temp, ///< [out] the return value from the string
177  const std::string & line ///< [in] the string to be parsed
178  );
179 
180 
181  /// Checks if any drive temperatures are warning or critical levels
182  /** Warning and critical temperatures are either user-defined or generated based on initial drive temperature values
183  *
184  * \returns 1 if a temperature value is at the warning level
185  * \returns 2 if a temperature value is at critical level
186  * \returns 0 otherwise (all temperatures are considered normal)
187  */
188  int criticalDiskTemperature( std::vector<float>& /**< [in] the vector of temperature values to be checked*/ );
189 
190 
191  /// Finds usages of space for following directory paths: /; /data; /boot
192  /** These usage values are stored as integer values between 0 and 100 (e.g. value of 39 means directory is 39% full)
193  * If directory is not found, space usage value will remain 0
194  * \TODO: What about multiple drives? What does this do?
195  *
196  * \returns -1 on error with system command or output reading
197  * \returns 0 if at least one of the return values is found
198  */
199  int findDiskUsage( float&, /**< [out] the return value for usage in root path*/
200  float&, /**< [out] the return value for usage in /data path*/
201  float& /**< [out] the return value for usage in /boot path*/
202  );
203 
204 
205  /// Parses string from system call to find drive usage space
206  /** When a valid string is read in, the value from that string is stored
207  *
208  * \returns -1 on invalid string being read in
209  * \returns 0 on completion and storing of value
210  */
211  int parseDiskUsage( std::string, /**< [in] the string to be parsed*/
212  float&, /**< [out] the return value for usage in root path*/
213  float&, /**< [out] the return value for usage in /data path*/
214  float& /**< [out] the return value for usage in /boot path*/
215  );
216 
217 
218  /// Finds current RAM usage
219  /** This usage value is stored as a decimal value between 0 and 1 (e.g. value of 0.39 means RAM usage is 39%)
220  *
221  * \returns -1 on error with system command or output reading
222  * \returns 0 on completion
223  */
224  int findRamUsage( float& /**< [out] the return value for current RAM usage*/ );
225 
226 
227  /// Parses string from system call to find RAM usage
228  /** When a valid string is read in, the value from that string is stored
229  *
230  * \returns -1 on invalid string being read in
231  * \returns 0 on completion and storing of value
232  */
233  int parseRamUsage( std::string, /**< [in] the string to be parsed*/
234  float& /**< [out] the return value for current RAM usage*/
235  );
236 
237  /** \name Chrony Status
238  * @{
239  */
240 protected:
241  std::string m_chronySourceMac;
242  std::string m_chronySourceIP;
243  std::string m_chronySynch;
244  double m_chronySystemTime {0};
245  double m_chronyLastOffset {0};
246  double m_chronyRMSOffset {0};
247  double m_chronyFreq {0};
248  double m_chronyResidFreq {0};
249  double m_chronySkew {0};
250  double m_chronyRootDelay {0};
252  double m_chronyUpdateInt {0};
253  std::string m_chronyLeap;
254 
255  pcf::IndiProperty m_indiP_chronyStatus;
256  pcf::IndiProperty m_indiP_chronyStats;
257 
258 public:
259  /// Finds current chronyd status
260  /** Uses the chrony tracking command
261  *
262  * \returns -1 on error
263  * \returns 0 on success
264  */
265  int findChronyStatus();
266 
267  ///@}
268 
269  /** \name Set Latency
270  * This thread spins up the cpus to minimize latency when requested
271  *
272  * @{
273  */
274  bool m_setLatency {false};
275 
276  int m_setlatThreadPrio {0}; ///< Priority of the set latency thread, should normally be > 00.
277 
278  std::thread m_setlatThread; ///< A separate thread for the actual setting of low latency
279 
280  bool m_setlatThreadInit {true}; ///< Synchronizer to ensure set lat thread initializes before doing dangerous things.
281 
282  pid_t m_setlatThreadID {0}; ///< Set latency thread ID.
283 
284  pcf::IndiProperty m_setlatThreadProp; ///< The property to hold the setlat thread details.
285 
286  ///Thread starter, called by threadStart on thread construction. Calls setlatThreadExec.
287  static void setlatThreadStart( sysMonitor * s /**< [in] a pointer to a sysMonitor instance (normally this) */);
288 
289  /// Execute the frame grabber main loop.
290  void setlatThreadExec();
291 
292  pcf::IndiProperty m_indiP_setlat;
293 
294 public:
296 
297  ///@}
298 
299  /** \name Telemeter Interface
300  *
301  * @{
302  */
303  int checkRecordTimes();
304 
305  int recordTelem( const telem_coreloads * );
306 
307  int recordTelem( const telem_coretemps * );
308 
309  int recordTelem( const telem_drivetemps * );
310 
311  int recordTelem( const telem_usage * );
312 
313  int recordTelem( const telem_chrony_status * );
314 
315  int recordTelem( const telem_chrony_stats * );
316 
317  int recordCoreLoads(bool force = false);
318 
319  int recordCoreTemps(bool force = false);
320 
321  int recordDriveTemps(bool force = false);
322 
323  int recordUsage(bool force = false);
324 
325  int recordChronyStatus(bool force = false);
326 
327  int recordChronyStats(bool force = false);
328 
329  ///@}
330 
331 };
332 
333 inline sysMonitor::sysMonitor() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
334 {
335  //m_loopPause = 100000; //Set default to 1 milli-second due to mpstat averaging time of 1 sec.
336  return;
337 }
338 
340 {
341  config.add("diskNames", "", "diskNames", argType::Required, "", "diskNames", false, "vector<string>", "The names (/dev/sdX) of the drives to monitor");
342  config.add("warningCoreTemp", "", "warningCoreTemp", argType::Required, "", "warningCoreTemp", false, "int", "The warning temperature for CPU cores.");
343  config.add("criticalCoreTemp", "", "criticalCoreTemp", argType::Required, "", "criticalCoreTemp", false, "int", "The critical temperature for CPU cores.");
344  config.add("warningDiskTemp", "", "warningDiskTemp", argType::Required, "", "warningDiskTemp", false, "int", "The warning temperature for the disk.");
345  config.add("criticalDiskTemp", "", "criticalDiskTemp", argType::Required, "", "criticalDiskTemp", false, "int", "The critical temperature for disk.");
346 
348 }
349 
351 {
352  config(m_diskNameList, "diskNames");
353  config(m_warningCoreTemp, "warningCoreTemp");
354  config(m_criticalCoreTemp, "criticalCoreTemp");
355  config(m_warningDiskTemp, "warningDiskTemp");
356  config(m_criticalDiskTemp, "criticalDiskTemp");
357 
359 }
360 
362 {
363 
364  //REG_INDI_NEWPROP_NOCB(m_indiP_core_temps, "core_temps", pcf::IndiProperty::Number);
365 
366 
367 
368  REG_INDI_NEWPROP_NOCB(m_indiP_core_temps, "core_temps", pcf::IndiProperty::Number);
369  m_indiP_core_temps.add(pcf::IndiElement("max"));
370  m_indiP_core_temps.add(pcf::IndiElement("min"));
371  m_indiP_core_temps.add(pcf::IndiElement("mean"));
372 
373  REG_INDI_NEWPROP_NOCB(m_indiP_core_loads, "core_loads", pcf::IndiProperty::Number);
374  m_indiP_core_loads.add(pcf::IndiElement("max"));
375  m_indiP_core_loads.add(pcf::IndiElement("min"));
376  m_indiP_core_loads.add(pcf::IndiElement("mean"));
377 
378  REG_INDI_NEWPROP_NOCB(m_indiP_drive_temps, "drive_temps", pcf::IndiProperty::Number);
380  for (unsigned int i = 0; i < m_diskTemps.size(); i++)
381  {
382  m_indiP_drive_temps.add (pcf::IndiElement(m_diskNames[i]));
383  m_indiP_drive_temps[m_diskNames[i]].set<double>(m_diskTemps[i]);
384  }
385 
386  REG_INDI_NEWPROP_NOCB(m_indiP_usage, "resource_use", pcf::IndiProperty::Number);
387  m_indiP_usage.add(pcf::IndiElement("root_usage"));
388  m_indiP_usage.add(pcf::IndiElement("boot_usage"));
389  m_indiP_usage.add(pcf::IndiElement("data_usage"));
390  m_indiP_usage.add(pcf::IndiElement("ram_usage"));
391 
392  m_indiP_usage["root_usage"].set<double>(0.0);
393  m_indiP_usage["boot_usage"].set<double>(0.0);
394  m_indiP_usage["data_usage"].set<double>(0.0);
395  m_indiP_usage["ram_usage"].set<double>(0.0);
396 
397 
398 
399  REG_INDI_NEWPROP_NOCB(m_indiP_chronyStatus, "chrony_status", pcf::IndiProperty::Text);
400  m_indiP_chronyStatus.add(pcf::IndiElement("synch"));
401  m_indiP_chronyStatus.add(pcf::IndiElement("source"));
402 
403  REG_INDI_NEWPROP_NOCB(m_indiP_chronyStats, "chrony_stats", pcf::IndiProperty::Number);
404  m_indiP_chronyStats.add(pcf::IndiElement("system_time"));
405  m_indiP_chronyStats.add(pcf::IndiElement("last_offset"));
406  m_indiP_chronyStats.add(pcf::IndiElement("rms_offset"));
407 
410 
412  {
413  return log<software_error,-1>({__FILE__,__LINE__});
414  }
415 
417  {
418  log<software_critical>({__FILE__, __LINE__});
419  return -1;
420  }
421 
423  return 0;
424 }
425 
427 {
428 
429  m_coreTemps.clear();
430  int rvCPUTemp = findCPUTemperatures(m_coreTemps);
431  if (rvCPUTemp >= 0)
432  {
434  }
435 
436  if (rvCPUTemp >= 0)
437  {
438  if (rvCPUTemp == 1)
439  {
440  log<telem_coretemps>(m_coreTemps, logPrio::LOG_WARNING);
441  }
442  else if (rvCPUTemp == 2)
443  {
444  log<telem_coretemps>(m_coreTemps, logPrio::LOG_ALERT);
445  }
446 
447  recordCoreTemps();
448  }
449  else
450  {
451  log<software_error>({__FILE__, __LINE__,"Could not log values for CPU core temps."});
452  }
453 
454  m_coreLoads.clear();
455  int rvCPULoad = findCPULoads(m_coreLoads);
456 
457  if(rvCPULoad >= 0)
458  {
459  recordCoreLoads();
460  }
461  else
462  {
463  log<software_error>({__FILE__, __LINE__,"Could not log values for CPU core loads."});
464  }
465 
466 
467  m_diskNames.clear();
468  m_diskTemps.clear();
469  int rvDiskTemp = findDiskTemperature(m_diskNames, m_diskTemps);
470 
471  if (rvDiskTemp >= 0)
472  {
473  rvDiskTemp = criticalDiskTemperature(m_diskTemps);
474  }
475 
476  if (rvDiskTemp >= 0)
477  {
478  if (rvDiskTemp == 1)
479  {
480  log<telem_drivetemps>({m_diskNames, m_diskTemps}, logPrio::LOG_WARNING);
481  }
482  else if (rvDiskTemp == 2)
483  {
484  log<telem_drivetemps>({m_diskNames, m_diskTemps}, logPrio::LOG_ALERT);
485  }
486  else
487  {
489  }
490  }
491  else
492  {
493  log<software_error>({__FILE__, __LINE__,"Could not log values for drive temps."});
494  }
495 
496  int rvDiskUsage = findDiskUsage(m_rootUsage, m_dataUsage, m_bootUsage);
497  int rvRamUsage = findRamUsage(m_ramUsage);
498 
499 
500  if (rvDiskUsage >= 0 && rvRamUsage >= 0)
501  {
502  recordUsage();
503  }
504  else
505  {
506  log<software_error>({__FILE__, __LINE__,"Could not log values for usage."});
507  }
508 
509 
510  if( findChronyStatus() == 0)
511  {
512  }
513  else
514  {
515  log<software_error>({__FILE__, __LINE__,"Could not get chronyd status."});
516  }
517 
519  {
520  log<software_error>({__FILE__, __LINE__});
521  return 0;
522  }
523 
524  updateVals();
525 
526  return 0;
527 }
528 
530 {
531  try
532  {
533  if(m_setlatThread.joinable())
534  {
535  m_setlatThread.join();
536  }
537  }
538  catch(...){}
539 
541 
542  return 0;
543 }
544 
545 int sysMonitor::findCPUTemperatures(std::vector<float>& temps)
546 {
547  std::vector<std::string> commandList{"sensors"};
548 
549  std::vector<std::string> commandOutput, commandError;
550 
551  if(sys::runCommand(commandOutput, commandError, commandList) < 0)
552  {
553  if(commandOutput.size() < 1) return log<software_error,-1>({__FILE__, __LINE__});
554  else return log<software_error,-1>({__FILE__, __LINE__, commandOutput[0]});
555  }
556 
557  if(commandError.size() > 0)
558  {
559  for(size_t n=0; n< commandError.size(); ++n)
560  {
561  log<software_error>({__FILE__, __LINE__, "sensors stderr: " + commandError[n]});
562  }
563  }
564 
565  int rv = -1;
566  for(size_t n=0; n < commandOutput.size(); ++n)
567  {
568  float tempVal;
569  if (parseCPUTemperatures(commandOutput[n], tempVal) == 0)
570  {
571  temps.push_back(tempVal);
572  rv = 0;
573  }
574  }
575  return rv;
576 }
577 
578 int sysMonitor::parseCPUTemperatures(std::string line, float& temps)
579 {
580  if (line.length() <= 1)
581  {
582  temps = -999;
583  return -1;
584  }
585 
586  std::string str = line.substr(0, 5);
587  if (str.compare("Core ") == 0)
588  {
589  size_t st = line.find(':',0);
590  if(st == std::string::npos)
591  {
592  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing CPU temperatures."});
593  temps = -999;
594  return -1;
595  }
596 
597  ++st;
598 
599  size_t ed = line.find('C', st);
600  if(ed == std::string::npos)
601  {
602  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing CPU temperatures."});
603  temps = -999;
604  return -1;
605  }
606 
607  --ed;
608 
609  std::string temp_str = line.substr(st, ed-st);
610  //std::cerr << str << " " << temp_str << "\n";
611 
612 
613  float temp;
614  try
615  {
616  temp = std::stof (temp_str);
617  }
618  catch (const std::invalid_argument& e)
619  {
620  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing CPU temperatures."});
621  temps = -999;
622  return -1;
623  }
624 
625  temps = temp;
626 
627  if (m_warningCoreTemp == 0)
628  {
629  std::istringstream iss(line);
630  std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},std::istream_iterator<std::string>{}};
631  try
632  {
633  tokens.at(5).pop_back();
634  tokens.at(5).pop_back();
635  tokens.at(5).pop_back();
636  tokens.at(5).pop_back();
637  tokens.at(5).erase(0,1);
638  m_warningCoreTemp = std::stof(tokens.at(5));
639  }
640  catch (const std::invalid_argument& e)
641  {
642  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing warning CPU temperatures."});
643  return -1;
644  }
645  }
646  if (m_criticalCoreTemp == 0)
647  {
648  std::istringstream iss(line);
649  std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},std::istream_iterator<std::string>{}};
650  try
651  {
652  tokens.at(8).pop_back();
653  tokens.at(8).pop_back();
654  tokens.at(8).pop_back();
655  tokens.at(8).pop_back();
656  tokens.at(8).erase(0,1);
657  m_criticalCoreTemp = std::stof(tokens.at(8));
658  }
659  catch (const std::invalid_argument& e)
660  {
661  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing critical CPU temperatures."});
662  temps = -999;
663  return -1;
664  }
665  }
666  return 0;
667  }
668  else
669  {
670  temps = -999;
671  return -1;
672  }
673 
674 }
675 
676 int sysMonitor::criticalCoreTemperature(std::vector<float>& v)
677 {
678  int coreNum = 0, rv = 0;
679  for(auto it: v)
680  {
681  float temp = it;
682  if (temp >= m_warningCoreTemp && temp < m_criticalCoreTemp )
683  {
684  std::cout << "Warning temperature for Core " << coreNum << std::endl;
685  if (rv < 2)
686  {
687  rv = 1;
688  }
689  }
690  else if (temp >= m_criticalCoreTemp)
691  {
692  std::cout << "Critical temperature for Core " << coreNum << std::endl;
693  rv = 2;
694  }
695  ++coreNum;
696  }
697  return rv;
698 }
699 
700 int sysMonitor::findCPULoads(std::vector<float>& loads)
701 {
702  std::vector<std::string> commandList{"mpstat", "-P", "ALL", "1", "1"};
703  std::vector<std::string> commandOutput, commandError;
704 
705  if(sys::runCommand(commandOutput, commandError, commandList) < 0)
706  {
707  if(commandOutput.size() < 1) return log<software_error,-1>({__FILE__, __LINE__});
708  else return log<software_error,-1>({__FILE__, __LINE__, commandOutput[0]});
709  }
710 
711  if(commandError.size() > 0)
712  {
713  for(size_t n=0; n< commandError.size(); ++n)
714  {
715  log<software_error>({__FILE__, __LINE__, "mpstat stderr: " + commandError[n]});
716  }
717  }
718 
719  int rv = -1;
720  // If output lines are less than 5 (with one CPU, guarenteed output is 5)
721  if (commandOutput.size() < 5)
722  {
723  return log<software_error,-1>({__FILE__, __LINE__, "not enough lines returned by mpstat"});
724  }
725  //start iterating at fourth line
726  for (auto line = commandOutput.begin()+4; line != commandOutput.end(); line++)
727  {
728  float loadVal;
729  if (parseCPULoads(*line, loadVal) == 0)
730  {
731  loads.push_back(loadVal);
732  rv = 0;
733  }
734  }
735  return rv;
736 }
737 
738 int sysMonitor::parseCPULoads(std::string line, float& loadVal)
739 {
740  if (line.length() <= 1)
741  {
742  log<software_error>({__FILE__, __LINE__,"zero lenght line in parseCPULoads."});
743  return -1;
744  }
745  std::istringstream iss(line);
746  std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},std::istream_iterator<std::string>{}};
747  if(tokens.size() < 8) return 1;
748  float cpu_load;
749  try
750  {
751  cpu_load = 100.0 - std::stof(tokens.at(tokens.size()-1));
752  }
753  catch (const std::invalid_argument& e)
754  {
755  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing CPU core usage."});
756  return -1;
757  }
758  catch (const std::out_of_range& e)
759  {
760  log<software_error>({__FILE__, __LINE__,"Out of range exception in parseCPULoads."});
761  return -1;
762  }
763  cpu_load /= 100;
764  loadVal = cpu_load;
765  return 0;
766 }
767 
768 int sysMonitor::findDiskTemperature( std::vector<std::string> & hdd_names,
769  std::vector<float>& hdd_temps
770  )
771 {
772  /*std::vector<std::string> commandList{"hddtemp"};//, "/dev/sda", "/dev/sdb", "/dev/sdc", "/dev/sdd", "/dev/sde", "/dev/sdf"};
773  for(size_t n=0;n<m_diskNameList.size();++n)
774  {
775  commandList.push_back(m_diskNameList[n]);
776  }
777 
778  std::vector<std::string> commandOutput, commandError;
779 
780  if(sys::runCommand(commandOutput, commandError, commandList) < 0)
781  {
782  if(commandOutput.size() < 1) return log<software_error,-1>({__FILE__, __LINE__});
783  else return log<software_error,-1>({__FILE__, __LINE__, commandOutput[0]});
784  }
785 
786  if(commandError.size() > 0)
787  {
788  for(size_t n=0; n< commandError.size(); ++n)
789  {
790  log<software_error>({__FILE__, __LINE__, "hddtemp stderr: " + commandError[n]});
791  }
792  }
793 
794  int rv = -1;
795  for (auto line: commandOutput)
796  {
797  std::string driveName;
798  float tempVal;
799  if (parseDiskTemperature(driveName, tempVal, line) == 0)
800  {
801  hdd_names.push_back(driveName);
802  hdd_temps.push_back(tempVal);
803  rv = 0;
804  }
805  }
806  return rv;*/
807 
808  return 0;
809 }
810 
811 int sysMonitor::parseDiskTemperature( std::string & driveName,
812  float & hdd_temp,
813  const std::string & line
814  )
815 {
816  float tempValue;
817  if (line.length() <= 6)
818  {
819  driveName = "";
820  hdd_temp = -999;
821  return -1;
822  }
823 
824  size_t sp = line.find(':',0);
825  driveName = line.substr(5, sp-5);
826 
827  std::istringstream iss(line);
828  std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},std::istream_iterator<std::string>{}};
829 
830  for(auto temp_s: tokens)
831  {
832  try
833  {
834  if (isdigit(temp_s.at(0)) && temp_s.substr(temp_s.length() - 1, 1) == "C")
835  {
836  temp_s.pop_back();
837  temp_s.pop_back();
838  try
839  {
840  tempValue = std::stof (temp_s);
841  }
842  catch (const std::invalid_argument& e)
843  {
844  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing drive temperatures."});
845  hdd_temp = -999;
846  driveName = "";
847  return -1;
848  }
849  hdd_temp = tempValue;
850  if (m_warningDiskTemp == 0)
851  {
852  m_warningDiskTemp = tempValue + (.1*tempValue);
853  }
854  if (m_criticalDiskTemp == 0)
855  {
856  m_criticalDiskTemp = tempValue + (.2*tempValue);
857  }
858  return 0;
859  }
860  }
861  catch (const std::out_of_range& e)
862  {
863  hdd_temp = -999;
864  driveName = "";
865  return -1;
866  }
867  }
868 
869  hdd_temp = -999;
870  driveName = "";
871  return -1;
872 }
873 
874 int sysMonitor::criticalDiskTemperature(std::vector<float>& v)
875 {
876  int rv = 0;
877  for(auto it: v)
878  {
879  float temp = it;
880  if (temp >= m_warningDiskTemp && temp < m_criticalDiskTemp )
881  {
882  std::cout << "Warning temperature for Disk" << std::endl;
883  if (rv < 2)
884  {
885  rv = 1;
886  }
887  }
888  else if (temp >= m_criticalDiskTemp)
889  {
890  std::cout << "Critical temperature for Disk " << std::endl;
891  rv = 2;
892  }
893  }
894  return rv;
895 }
896 
897 int sysMonitor::findDiskUsage(float &rootUsage, float &dataUsage, float &bootUsage)
898 {
899  std::vector<std::string> commandList{"df"};
900 
901  std::vector<std::string> commandOutput, commandError;
902 
903  if(sys::runCommand(commandOutput, commandError, commandList) < 0)
904  {
905  if(commandOutput.size() < 1) return log<software_error,-1>({__FILE__, __LINE__});
906  else return log<software_error,-1>({__FILE__, __LINE__, commandOutput[0]});
907  }
908 
909  if(commandError.size() > 0)
910  {
911  for(size_t n=0; n< commandError.size(); ++n)
912  {
913  log<software_error>({__FILE__, __LINE__, "df stderr: " + commandError[n]});
914  }
915  }
916 
917  int rv = -1;
918  for (auto line: commandOutput)
919  {
920  int rvDiskUsage = parseDiskUsage(line, rootUsage, dataUsage, bootUsage);
921  if (rvDiskUsage == 0)
922  {
923  rv = 0;
924  }
925  }
926  return rv;
927 }
928 
929 int sysMonitor::parseDiskUsage(std::string line, float& rootUsage, float& dataUsage, float& bootUsage)
930 {
931  if (line.length() <= 1)
932  {
933  return -1;
934  }
935 
936  std::istringstream iss(line);
937  std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},std::istream_iterator<std::string>{}};
938 
939  try {
940  if (tokens.at(5).compare("/") == 0)
941  {
942  tokens.at(4).pop_back();
943  try
944  {
945  rootUsage = std::stof (tokens.at(4))/100;
946  return 0;
947  }
948  catch (const std::invalid_argument& e)
949  {
950  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing drive usage."});
951  return -1;
952  }
953  }
954  else if (tokens.at(5).compare("/data") == 0)
955  {
956  tokens.at(4).pop_back();
957  try
958  {
959  dataUsage = std::stof (tokens.at(4))/100;
960  return 0;
961  }
962  catch (const std::invalid_argument& e)
963  {
964  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing drive usage."});
965  return -1;
966  }
967  }
968  else if (tokens.at(5).compare("/boot") == 0)
969  {
970  tokens.at(4).pop_back();
971  try
972  {
973  bootUsage = std::stof (tokens.at(4))/100;
974  return 0;
975  }
976  catch (const std::invalid_argument& e)
977  {
978  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing drive usage."});
979  return -1;
980  }
981  }
982  }
983  catch (const std::out_of_range& e) {
984  return -1;
985  }
986  return -1;
987 }
988 
989 int sysMonitor::findRamUsage(float& ramUsage)
990 {
991  std::vector<std::string> commandList{"free", "-m"};
992 
993  std::vector<std::string> commandOutput, commandError;
994 
995  if(sys::runCommand(commandOutput, commandError, commandList) < 0)
996  {
997  if(commandOutput.size() < 1) return log<software_error,-1>({__FILE__, __LINE__});
998  else return log<software_error,-1>({__FILE__, __LINE__, commandOutput[0]});
999  }
1000 
1001  if(commandError.size() > 0)
1002  {
1003  for(size_t n=0; n< commandError.size(); ++n)
1004  {
1005  log<software_error>({__FILE__, __LINE__, "free stderr: " + commandError[n]});
1006  }
1007  }
1008 
1009  for (auto line: commandOutput)
1010  {
1011  if (parseRamUsage(line, ramUsage) == 0)
1012  {
1013  return 0;
1014  }
1015  }
1016  return -1;
1017 }
1018 
1019 int sysMonitor::parseRamUsage(std::string line, float& ramUsage)
1020 {
1021  if (line.length() <= 1)
1022  {
1023  return -1;
1024  }
1025  std::istringstream iss(line);
1026  std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},std::istream_iterator<std::string>{}};
1027  try
1028  {
1029  if (tokens.at(0).compare("Mem:") != 0)
1030  {
1031  return -1;
1032  }
1033  ramUsage = std::stof(tokens.at(2))/std::stof(tokens.at(1));
1034  if (ramUsage > 1 || ramUsage == 0)
1035  {
1036  ramUsage = -1;
1037  return -1;
1038  }
1039  return 0;
1040  }
1041  catch (const std::invalid_argument& e)
1042  {
1043  log<software_error>({__FILE__, __LINE__,"Invalid read occured when parsing RAM usage."});
1044  return -1;
1045  }
1046  catch (const std::out_of_range& e) {
1047  return -1;
1048  }
1049 }
1050 
1052 {
1053  std::vector<std::string> commandList{"chronyc", "-c", "tracking"};
1054 
1055  std::vector<std::string> commandOutput, commandError;
1056 
1057  if(sys::runCommand(commandOutput, commandError, commandList) < 0)
1058  {
1059  if(commandOutput.size() < 1) return log<software_error,-1>({__FILE__, __LINE__});
1060  else return log<software_error,-1>({__FILE__, __LINE__, commandOutput[0]});
1061  }
1062 
1063  if(commandError.size() > 0)
1064  {
1065  for(size_t n=0; n< commandError.size(); ++n)
1066  {
1067  log<software_error>({__FILE__, __LINE__, "chronyc stderr: " + commandError[n]});
1068  }
1069  }
1070 
1071  if(commandOutput.size() < 1)
1072  {
1073  log<software_error>({__FILE__,__LINE__, "no response from chronyc -c"});
1074  return -1;
1075  }
1076 
1077  std::vector<std::string> results;
1078  mx::ioutils::parseStringVector(results, commandOutput[0], ',');
1079 
1080  if(results.size() < 1)
1081  {
1082  log<software_error>({__FILE__,__LINE__, "wrong number of fields from chronyc -c"});
1083  return -1;
1084  }
1085 
1086  static std::string last_mac;
1087  static std::string last_ip;
1088  m_chronySourceMac = results[0];
1089  m_chronySourceIP = results[1];
1090  if(m_chronySourceMac == "7F7F0101" || m_chronySourceIP == "127.0.0.1")
1091  {
1092  m_chronySynch = "NO";
1093  log<text_log>("chrony is not synchronized", logPrio::LOG_WARNING);
1094  }
1095  else
1096  {
1097  m_chronySynch = "YES";
1098  }
1099 
1100  if(last_mac != m_chronySourceMac || last_ip != m_chronySourceIP)
1101  {
1102  log<text_log>("chrony is synchronizing to " + m_chronySourceMac + " / " + m_chronySourceIP);
1103  last_mac = m_chronySourceMac;
1104  last_ip = m_chronySourceIP;
1105  }
1106 
1107 
1108 
1109  m_chronySystemTime = std::stod(results[4]);
1110  m_chronyLastOffset = std::stod(results[5]);
1111  m_chronyRMSOffset = std::stod(results[6]);
1112  m_chronyFreq = std::stod(results[7]);
1113  m_chronyResidFreq = std::stod(results[8]);
1114  m_chronySkew = std::stod(results[9]);
1115  m_chronyRootDelay = std::stod(results[10]);
1116  m_chronyRootDispersion = std::stod(results[11]);
1117  m_chronyUpdateInt = std::stod(results[12]);
1118  m_chronyLeap = results[13];
1119 
1122 
1123  return 0;
1124 }
1125 
1127 {
1128  float min, max, mean;
1129 
1130  if(m_coreLoads.size() > 0)
1131  {
1132  min = m_coreLoads[0];
1133  max = m_coreLoads[0];
1134  mean = m_coreLoads[0];
1135  for(size_t n=1; n<m_coreLoads.size(); ++n)
1136  {
1137  if(m_coreLoads[n] < min) min = m_coreLoads[n];
1138  if(m_coreLoads[n] > max) max = m_coreLoads[n];
1139  mean += m_coreLoads[n];
1140  }
1141  mean /= m_coreLoads.size();
1142 
1143  updateIfChanged<float>(m_indiP_core_loads, {"min","max","mean"}, {min,max,mean});
1144  }
1145 
1146 
1147  if(m_coreTemps.size() > 0)
1148  {
1149  min = m_coreTemps[0];
1150  max = m_coreTemps[0];
1151  mean = m_coreTemps[0];
1152  for(size_t n=1; n<m_coreTemps.size(); ++n)
1153  {
1154  if(m_coreTemps[n] < min) min = m_coreTemps[n];
1155  if(m_coreTemps[n] > max) max = m_coreTemps[n];
1156  mean += m_coreTemps[n];
1157  }
1158  mean /= m_coreTemps.size();
1159 
1160  updateIfChanged<float>(m_indiP_core_temps, {"min","max","mean"}, {min,max,mean});
1161  }
1162 
1164 
1165  updateIfChanged<float>(m_indiP_usage, {"root_usage","boot_usage","data_usage","ram_usage"}, {m_rootUsage,m_bootUsage,m_dataUsage,m_ramUsage});
1166 
1167 
1170 
1171  updateIfChanged<double>(m_indiP_chronyStats, {"system_time", "last_offset", "rms_offset"}, {m_chronySystemTime, m_chronyLastOffset, m_chronyRMSOffset});
1172 
1173  if(m_setLatency)
1174  {
1175  updateSwitchIfChanged( m_indiP_setlat, "toggle", pcf::IndiElement::On, INDI_BUSY);
1176  }
1177  else
1178  {
1179  updateSwitchIfChanged( m_indiP_setlat, "toggle", pcf::IndiElement::Off, INDI_IDLE);
1180  }
1181 
1182  return 0;
1183 }
1184 
1185 inline
1187 {
1188  s->setlatThreadExec();
1189 }
1190 
1191 inline
1193 {
1194  m_setlatThreadID = syscall(SYS_gettid);
1195 
1196  //Wait fpr the thread starter to finish initializing this thread.
1197  while(m_setlatThreadInit == true && m_shutdown == 0)
1198  {
1199  sleep(1);
1200  }
1201 
1202  int fd = 0;
1203  while(m_shutdown == 0)
1204  {
1205  if(m_setLatency)
1206  {
1207  if(fd <= 0)
1208  {
1209  elevatedPrivileges ep(this);
1210 
1211  for(size_t cpu =0; cpu < m_coreLoads.size(); ++cpu) ///\todo this needs error checks
1212  {
1213  std::string cpuFile = "/sys/devices/system/cpu/cpu";
1214  cpuFile += std::to_string(cpu);
1215  cpuFile += "/cpufreq/scaling_governor";
1216  int wfd = open( cpuFile.c_str(), O_WRONLY);
1217  write(wfd,"performance",sizeof("performance"));
1218  close(wfd);
1219  }
1220  log<text_log>("set governor to performance", logPrio::LOG_NOTICE);
1221 
1222  fd = open("/dev/cpu_dma_latency", O_WRONLY);
1223 
1224  if(fd <=0) log<software_error>({__FILE__,__LINE__,"error opening cpu_dma_latency"});
1225  else
1226  {
1227  int l=0;
1228  if (write(fd, &l, sizeof(l)) != sizeof(l))
1229  {
1230  log<software_error>({__FILE__,__LINE__,"error writing to cpu_dma_latency"});
1231  }
1232  else
1233  {
1234  log<text_log>("set latency to 0", logPrio::LOG_NOTICE);
1235  }
1236  }
1237 
1238 
1239  }
1240  }
1241  else
1242  {
1243  if(fd != 0)
1244  {
1245  close(fd);
1246  fd = 0;
1247  log<text_log>("restored CPU latency to default", logPrio::LOG_NOTICE);
1248 
1249  elevatedPrivileges ep(this);
1250  for(size_t cpu =0; cpu < m_coreLoads.size(); ++cpu) ///\todo this needs error checks
1251  {
1252  std::string cpuFile = "/sys/devices/system/cpu/cpu";
1253  cpuFile += std::to_string(cpu);
1254  cpuFile += "/cpufreq/scaling_governor";
1255  int wfd = open( cpuFile.c_str(), O_WRONLY);
1256  write(wfd,"powersave",sizeof("powersave"));
1257  close(wfd);
1258  }
1259  log<text_log>("set governor to powersave", logPrio::LOG_NOTICE);
1260  }
1261  }
1262 
1263  sleep(1);
1264  }
1265 
1266  if(fd) close(fd);
1267 
1268 }
1269 
1270 INDI_NEWCALLBACK_DEFN(sysMonitor, m_indiP_setlat)(const pcf::IndiProperty &ipRecv)
1271 {
1272  if(ipRecv.getName() != m_indiP_setlat.getName())
1273  {
1274  log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1275  return -1;
1276  }
1277 
1278  if(!ipRecv.find("toggle")) return 0;
1279 
1280  if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
1281  {
1282  m_setLatency = false;
1283  }
1284 
1285  if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
1286  {
1287  m_setLatency = true;
1288  }
1289  return 0;
1290 }
1291 
1292 inline
1294 {
1296 }
1297 
1299 {
1300  return recordCoreLoads(true);
1301 }
1302 
1304 {
1305  return recordCoreTemps(true);
1306 }
1307 
1309 {
1310  return recordDriveTemps(true);
1311 }
1312 
1314 {
1315  return recordUsage(true);
1316 }
1317 
1319 {
1320  return recordChronyStatus(true);
1321 }
1322 
1324 {
1325  return recordChronyStats(true);
1326 }
1327 
1329 {
1330  static std::vector<float> old_coreLoads;
1331 
1332  if(old_coreLoads.size() != m_coreLoads.size())
1333  {
1334  old_coreLoads.resize(m_coreLoads.size(), -1e30);
1335  }
1336 
1337  bool write = false;
1338 
1339  for(size_t n = 0; n < m_coreLoads.size(); ++n)
1340  {
1341  if( m_coreLoads[n] != old_coreLoads[n]) write = true;
1342  }
1343 
1344  if(force || write)
1345  {
1346  telem<telem_coreloads>(m_coreLoads);
1347 
1348  for(size_t n = 0; n < m_coreLoads.size(); ++n)
1349  {
1350  old_coreLoads[n] = m_coreLoads[n];
1351  }
1352  }
1353 
1354  return 0;
1355 }
1356 
1358 {
1359  static std::vector<float> old_coreTemps;
1360 
1361  if(old_coreTemps.size() != m_coreTemps.size())
1362  {
1363  old_coreTemps.resize(m_coreTemps.size(), -1e30);
1364  }
1365 
1366  bool write = false;
1367 
1368  for(size_t n = 0; n < m_coreTemps.size(); ++n)
1369  {
1370  if( m_coreTemps[n] != old_coreTemps[n]) write = true;
1371  }
1372 
1373  if(force || write)
1374  {
1375  telem<telem_coretemps>(m_coreTemps);
1376  for(size_t n = 0; n < m_coreTemps.size(); ++n)
1377  {
1378  old_coreTemps[n] = m_coreTemps[n];
1379  }
1380  }
1381 
1382  return 0;
1383 }
1384 
1386 {
1387  static std::vector<std::string> old_diskNames;
1388  static std::vector<float> old_diskTemps;
1389 
1390  if(old_diskTemps.size() != m_diskTemps.size() || old_diskNames.size() != m_diskNames.size())
1391  {
1392  old_diskNames.resize(m_diskNames.size());
1393  old_diskTemps.resize(m_diskTemps.size(), -1e30);
1394  }
1395 
1396  bool write = false;
1397 
1398  for(size_t n = 0; n < m_diskTemps.size(); ++n)
1399  {
1400  if( m_diskTemps[n] != old_diskTemps[n] || m_diskNames[n] != old_diskNames[n]) write = true;
1401  }
1402 
1403  if(force || write)
1404  {
1405  telem<telem_drivetemps>({m_diskNames, m_diskTemps});
1406  for(size_t n = 0; n < m_diskTemps.size(); ++n)
1407  {
1408  old_diskNames[n] = m_diskNames[n];
1409  old_diskTemps[n] = m_diskTemps[n];
1410  }
1411  }
1412 
1413  return 0;
1414 }
1415 
1417 {
1418  static float old_ramUsage = 0;
1419  static float old_bootUsage = 0;
1420  static float old_rootUsage = 0;
1421  static float old_dataUsage = 0;
1422 
1423  if( old_ramUsage != m_ramUsage || old_bootUsage != m_bootUsage || old_rootUsage != m_rootUsage || old_dataUsage != m_dataUsage || force)
1424  {
1425  telem<telem_usage>({m_ramUsage, m_bootUsage, m_rootUsage, m_dataUsage});
1426 
1427  old_ramUsage = m_ramUsage;
1428  old_bootUsage = m_bootUsage;
1429  old_rootUsage = m_rootUsage;
1430  old_dataUsage = m_dataUsage;
1431  }
1432 
1433  return 0;
1434 }
1435 
1437 {
1438  static std::string old_chronySourceMac;
1439  static std::string old_chronySourceIP;
1440  static std::string old_chronySynch;
1441  static std::string old_chronyLeap;
1442 
1443 
1444  if( old_chronySourceMac != m_chronySourceMac || old_chronySourceIP != m_chronySourceIP || old_chronySynch != m_chronySynch || old_chronyLeap != m_chronyLeap || force)
1445  {
1446  telem<telem_chrony_status>({m_chronySourceMac, m_chronySourceIP, m_chronySynch, m_chronyLeap});
1447 
1448  old_chronySourceMac = m_chronySourceMac;
1449  old_chronySourceIP = m_chronySourceIP;
1450  old_chronySynch = m_chronySynch;
1451  old_chronyLeap = m_chronyLeap;
1452  }
1453 
1454  return 0;
1455 }
1456 
1458 {
1459  double old_chronySystemTime = 1e50; //to force an update the first time no matter what
1460  double old_chronyLastOffset = 0;
1461  double old_chronyRMSOffset = 0;
1462  double old_chronyFreq = 0;
1463  double old_chronyResidFreq = 0;
1464  double old_chronySkew = 0;
1465  double old_chronyRootDelay = 0;
1466  double old_chronyRootDispersion = 0;
1467  double old_chronyUpdateInt = 0;
1468 
1469  if( old_chronySystemTime == m_chronySystemTime || old_chronyLastOffset == m_chronyLastOffset ||
1470  old_chronyRMSOffset == m_chronyRMSOffset || old_chronyFreq == m_chronyFreq ||
1471  old_chronyResidFreq == m_chronyResidFreq || old_chronySkew == m_chronySkew ||
1472  old_chronyRootDelay == m_chronyRootDelay || old_chronyRootDispersion == m_chronyRootDispersion ||
1473  old_chronyUpdateInt == m_chronyUpdateInt || force )
1474  {
1475 
1478 
1479  old_chronySystemTime = m_chronySystemTime;
1480  old_chronyLastOffset = m_chronyLastOffset;
1481  old_chronyRMSOffset = m_chronyRMSOffset;
1482  old_chronyFreq = m_chronyFreq;
1483  old_chronyResidFreq = m_chronyResidFreq;
1484  old_chronySkew = m_chronySkew;
1485  old_chronyRootDelay = m_chronyRootDelay;
1486  old_chronyRootDispersion = m_chronyRootDispersion;
1487  old_chronyUpdateInt = m_chronyUpdateInt;
1488 
1489  }
1490  return 0;
1491 }
1492 
1493 } //namespace app
1494 } //namespace MagAOX
1495 
1496 #endif //sysMonitor_hpp
Internal class to manage setuid privilege escalation with RAII.
Definition: MagAOXApp.hpp:325
The base-class for MagAO-X applications.
Definition: MagAOXApp.hpp:75
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
Definition: MagAOXApp.hpp:2877
stateCodes::stateCodeT state()
Get the current state code.
Definition: MagAOXApp.hpp:2082
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int createStandardIndiToggleSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single toggle element.
Definition: MagAOXApp.hpp:2321
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
Definition: MagAOXApp.hpp:102
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
Definition: MagAOXApp.hpp:2901
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
Definition: MagAOXApp.hpp:1590
int threadStart(std::thread &thrd, bool &thrdInit, pid_t &tpid, pcf::IndiProperty &thProp, int thrdPrio, const std::string &cpuset, const std::string &thrdName, thisPtr *thrdThis, Function &&thrdStart)
Start a thread, using this class's privileges to set priority, etc.
Definition: MagAOXApp.hpp:1950
int m_criticalDiskTemp
User defined critical temperature for drives.
Definition: sysMonitor.hpp:50
std::string m_chronySourceMac
Definition: sysMonitor.hpp:241
pcf::IndiProperty m_indiP_core_temps
Indi variable for reporting CPU core temperature(s)
Definition: sysMonitor.hpp:53
int findRamUsage(float &)
Finds current RAM usage.
Definition: sysMonitor.hpp:989
int findDiskUsage(float &, float &, float &)
Finds usages of space for following directory paths: /; /data; /boot.
Definition: sysMonitor.hpp:897
pcf::IndiProperty m_indiP_chronyStatus
Definition: sysMonitor.hpp:255
void setlatThreadExec()
Execute the frame grabber main loop.
float m_bootUsage
Disk usage in /boot path as a value out of 100.
Definition: sysMonitor.hpp:66
int parseCPULoads(std::string, float &)
Parses string from system call to find CPU usage loads.
Definition: sysMonitor.hpp:738
int parseDiskTemperature(std::string &driveName, float &temp, const std::string &line)
Parses string from system call to find drive temperatures.
Definition: sysMonitor.hpp:811
int recordChronyStats(bool force=false)
float m_rootUsage
Disk usage in root path as a value out of 100.
Definition: sysMonitor.hpp:64
int recordDriveTemps(bool force=false)
int recordTelem(const telem_coreloads *)
int recordChronyStatus(bool force=false)
std::vector< std::string > m_diskNames
vector of names of the hard disks returned by hdd_temp
Definition: sysMonitor.hpp:61
virtual void setupConfig()
Setup the user-defined warning and critical values for core and drive temperatures.
Definition: sysMonitor.hpp:339
~sysMonitor() noexcept
D'tor, declared and defined for noexcept.
Definition: sysMonitor.hpp:84
virtual int appLogic()
Implementation of reading and logging each of the measured statistics.
Definition: sysMonitor.hpp:426
std::thread m_setlatThread
A separate thread for the actual setting of low latency.
Definition: sysMonitor.hpp:278
pcf::IndiProperty m_setlatThreadProp
The property to hold the setlat thread details.
Definition: sysMonitor.hpp:284
int m_warningDiskTemp
User defined warning temperature for drives.
Definition: sysMonitor.hpp:49
pid_t m_setlatThreadID
Set latency thread ID.
Definition: sysMonitor.hpp:282
pcf::IndiProperty m_indiP_setlat
Definition: sysMonitor.hpp:292
std::vector< float > m_coreLoads
List of current core load(s)
Definition: sysMonitor.hpp:58
int findCPUTemperatures(std::vector< float > &)
Finds all CPU core temperatures.
Definition: sysMonitor.hpp:545
std::vector< float > m_coreTemps
List of current core temperature(s)
Definition: sysMonitor.hpp:57
int parseCPUTemperatures(std::string, float &)
Parses string from system call to find CPU temperatures.
Definition: sysMonitor.hpp:578
int recordCoreLoads(bool force=false)
int updateVals()
Updates Indi property values of all system statistics.
virtual void loadConfig()
Load the warning and critical temperature values for core and drive temperatures.
Definition: sysMonitor.hpp:350
int findDiskTemperature(std::vector< std::string > &hdd_names, std::vector< float > &hdd_temps)
Finds all drive temperatures.
Definition: sysMonitor.hpp:768
INDI_NEWCALLBACK_DECL(sysMonitor, m_indiP_setlat)
int m_criticalCoreTemp
User defined critical temperature for CPU cores.
Definition: sysMonitor.hpp:48
virtual int appStartup()
Registers all new Indi properties for each of the reported values to publish.
Definition: sysMonitor.hpp:361
bool m_setlatThreadInit
Synchronizer to ensure set lat thread initializes before doing dangerous things.
Definition: sysMonitor.hpp:280
pcf::IndiProperty m_indiP_drive_temps
Indi variable for reporting drive temperature(s)
Definition: sysMonitor.hpp:54
int recordCoreTemps(bool force=false)
static void setlatThreadStart(sysMonitor *s)
Thread starter, called by threadStart on thread construction. Calls setlatThreadExec.
int m_warningCoreTemp
User defined warning temperature for CPU cores.
Definition: sysMonitor.hpp:47
float m_dataUsage
Disk usage in /data path as a value out of 100.
Definition: sysMonitor.hpp:65
int criticalCoreTemperature(std::vector< float > &)
Checks if any core temperatures are warning or critical levels.
Definition: sysMonitor.hpp:676
virtual int appShutdown()
Do any needed shutdown tasks; currently nothing in this app.
Definition: sysMonitor.hpp:529
std::vector< std::string > m_diskNameList
vector of names of the hard disks to monitor
Definition: sysMonitor.hpp:60
std::vector< float > m_diskTemps
vector of current disk temperature(s)
Definition: sysMonitor.hpp:62
pcf::IndiProperty m_indiP_usage
Indi variable for reporting drive usage of all paths.
Definition: sysMonitor.hpp:55
int criticalDiskTemperature(std::vector< float > &)
Checks if any drive temperatures are warning or critical levels.
Definition: sysMonitor.hpp:874
float m_ramUsage
RAM usage as a decimal value between 0 and 1.
Definition: sysMonitor.hpp:67
int m_setlatThreadPrio
Priority of the set latency thread, should normally be > 00.
Definition: sysMonitor.hpp:276
std::string m_chronySourceIP
Definition: sysMonitor.hpp:242
pcf::IndiProperty m_indiP_core_loads
Indi variable for reporting CPU core loads.
Definition: sysMonitor.hpp:52
sysMonitor()
Default c'tor.
Definition: sysMonitor.hpp:333
int findChronyStatus()
Finds current chronyd status.
int parseDiskUsage(std::string, float &, float &, float &)
Parses string from system call to find drive usage space.
Definition: sysMonitor.hpp:929
pcf::IndiProperty m_indiP_chronyStats
Definition: sysMonitor.hpp:256
int findCPULoads(std::vector< float > &)
Finds all CPU core usage loads.
Definition: sysMonitor.hpp:700
int parseRamUsage(std::string, float &)
Parses string from system call to find RAM usage.
int recordUsage(bool force=false)
#define REG_INDI_NEWPROP_NOCB(prop, propName, type)
Register a NEW INDI property with the class, with no callback.
Definition: indiMacros.hpp:247
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
Definition: indiMacros.hpp:207
@ READY
The device is ready for operation, but is not operating.
Definition: stateCodes.hpp:51
int runCommand(std::vector< std::string > &commandOutput, std::vector< std::string > &commandStderr, std::vector< std::string > &commandList)
Runs a command (with parameters) passed in using fork/exec.
Definition: runCommand.cpp:22
#define INDI_IDLE
Definition: indiUtils.hpp:28
#define INDI_BUSY
Definition: indiUtils.hpp:30
std::ostream & cout()
const pcf::IndiProperty & ipRecv
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
Definition: acesxeCtrl.hpp:687
Definition: dm.hpp:24
constexpr static logPrioT LOG_ALERT
This should only be used if some action is required by operators to keep the system safe.
Definition: logPriority.hpp:34
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
Definition: logPriority.hpp:43
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.
Definition: logPriority.hpp:46
A device which saves telemetry.
Definition: telemeter.hpp:52
int appShutdown()
Perform telemeter application shutdown.
Definition: telemeter.hpp:259
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
Definition: telemeter.hpp:208
int appLogic()
Perform telemeter application logic.
Definition: telemeter.hpp:253
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
Definition: telemeter.hpp:195
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Definition: telemeter.hpp:266
Software ERR log entry.
Log entry recording the statistics from chrony.
Log entry recording the status of chrony.
Log entry recording CPU loads.
Log entry recording CPU temperatures.
Log entry recording hdd temperatures.
Log entry recording hdd temperatures.
Definition: telem_usage.hpp:26