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