37 #if defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
38 #include <sys/prctl.h>
121 if (
this != &daemon) {
183 #if defined(G_APPEND_LOG)
193 m_log <<
"GammaLib daemon start up" << std::endl;
196 #if defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
197 prctl(PR_SET_NAME,
"gammalibd");
211 if ((pid != 0) && (pid !=
m_pid)) {
213 m_log <<
"Another daemon with PID " << (int)(pid) <<
" is running, ";
214 m_log <<
"exit this daemon" << std::endl;
228 catch (
const std::exception &except) {
230 m_log <<
"Exception catched by daemon" << std::endl;
231 m_log << except.what() << std::endl;
244 for (
int i = 0; i < ncycle; ++i) {
253 m_log <<
"Terminated event loop" << std::endl;
295 #pragma omp critical(GDaemon_alive)
300 lock.l_type = F_RDLCK;
301 lock.l_whence = SEEK_SET;
304 lock.l_pid = getpid();
305 int fd = open(filename.
url().c_str(), O_RDONLY);
309 fcntl(fd, F_SETLKW, &lock);
312 FILE* fptr = fopen(filename.
url().c_str(),
"r");
320 fgets(line, n-1, fptr);
329 heartbeat.
utc(std::string(line));
330 if ((now - heartbeat) < 2.0 *
double(
m_heartbeat)) {
334 catch (
const std::exception &except) {
341 lock.l_type = F_UNLCK;
342 fcntl(fd, F_SETLK, &lock);
371 result.append(
"=== GDaemon ===");
456 FILE* fptr = fopen(lockfile.
url().c_str(),
"w");
460 fprintf(fptr,
"%d\n", (
int)(
m_pid));
467 m_log <<
"Created lock file \"" << lockfile.
url();
468 m_log <<
"\"" << std::endl;
493 std::remove(lockfile.
url().c_str());
497 m_log <<
"Removed lock file \"" << lockfile.
url();
498 m_log <<
"\"" << std::endl;
522 FILE* fptr = fopen(filename.
url().c_str(),
"w");
526 fprintf(fptr,
"%s\n", now.
utc().c_str());
555 FILE* fptr = fopen(lockfile.
url().c_str(),
"r");
563 fgets(line, n-1, fptr);
593 #pragma omp critical(GDaemon_update_statistics)
598 lock.l_type = F_RDLCK;
599 lock.l_whence = SEEK_SET;
602 lock.l_pid = getpid();
603 int fd = open(filename.
url().c_str(), O_RDONLY);
608 m_log <<
"Update high-level statistics" << std::endl;
611 fcntl(fd, F_SETLKW, &lock);
617 GCsv statistics(filename,
",");
628 xml.
load(filename_work);
634 xml.
save(filename_copy);
650 xml.
save(filename_work);
653 std::remove(filename_copy.
url().c_str());
656 std::remove(filename.
url().c_str());
661 catch (
const std::exception &except) {
663 m_log <<
"Exception catched by daemon" << std::endl;
664 m_log << except.what() << std::endl;
668 lock.l_type = F_UNLCK;
669 fcntl(fd, F_SETLK, &lock);
696 if (country.length() == 2) {
702 #pragma omp critical(GDaemon_update_host_country)
707 FILE* fptr = fopen(filename.
url().c_str(),
"w");
709 fprintf(fptr,
"%s\n", country.c_str());
753 if (!filename_work.
exists() && !filename_copy.
exists()) {
759 else if (!filename_work.
exists() && filename_copy.
exists()) {
762 xml_copy.
load(filename_copy);
763 xml_copy.
save(filename_work);
765 m_log <<
"No \"statistics.xml\" file found, use copy ";
766 m_log <<
"\"statistics.xml~\"" << std::endl;
768 catch (
const std::exception &except) {
770 m_log <<
"No \"statistics.xml\" file found and corrupt ";
771 m_log <<
"\"statistics.xml~\" file encountered, secure ";
772 m_log <<
"it and create new XML file" << std::endl;
775 std::string newcopy = filename_work.
url() +
"." + now.
utc() +
"~";
776 std::rename(filename_copy.
url().c_str(), newcopy.c_str());
783 else if (filename_work.
exists() && filename_copy.
exists()) {
786 bool integrity_work =
true;
787 bool integrity_copy =
true;
791 xml_work.
load(filename_work);
792 integrity_work =
true;
794 catch (
const std::exception &except) {
795 integrity_work =
false;
798 xml_copy.
load(filename_copy);
799 integrity_copy =
true;
801 catch (
const std::exception &except) {
802 integrity_copy =
false;
808 if (integrity_copy && !integrity_work) {
810 m_log <<
"Corrupt \"statistics.xml\" file encountered, ";
811 m_log <<
"use copy \"statistics.xml~\"" << std::endl;
812 xml_copy.
save(filename_work);
818 else if (!integrity_copy && !integrity_work) {
820 m_log <<
"Corrupt \"statistics.xml\" and \"statistics.xml~\" ";
821 m_log <<
"files encountered, secure them and create new ";
822 m_log <<
"file" << std::endl;
825 std::string newwork = filename_work.
url() +
"." + now.
utc();
826 std::string newcopy = filename_work.
url() +
"." + now.
utc() +
"~";
827 std::rename(filename_work.
url().c_str(), newwork.c_str());
828 std::rename(filename_copy.
url().c_str(), newcopy.c_str());
836 else if (integrity_copy && integrity_work) {
838 m_log <<
"Unexpected \"statistics.xml\" file encountered, ";
839 m_log <<
"secure file and use copy \"statistics.xml~\"";
843 std::string newwork = filename_work.
url() +
"." + now.
utc();
844 std::rename(filename_work.
url().c_str(), newwork.c_str());
845 xml_copy.
save(filename_work);
851 std::remove(filename_copy.
url().c_str());
893 data->
append(
"countries");
899 m_log <<
"Created high-level statistics XML file \"";
900 m_log << filename.
url() <<
"\"" << std::endl;
934 static_cast<GXmlText*
>((*modified)[0])->text(now.
utc());
940 if (statistics.
nrows() > 1) {
941 start = statistics.
string(1,0);
949 std::string current_start =
static_cast<GXmlText*
>((*start_node)[0])->text();
950 if (current_start.empty() || (start < current_start)) {
951 static_cast<GXmlText*
>((*start_node)[0])->text(start);
958 std::string current_stop =
static_cast<GXmlText*
>((*stop_node)[0])->text();
959 if (current_stop.empty() || (stop > current_stop)) {
960 static_cast<GXmlText*
>((*stop_node)[0])->text(stop);
984 if (header->
elements(
"countries") == 0) {
985 header->
append(
"countries");
990 for (
int i = 1; i < statistics.
nrows(); ++i) {
993 std::string country = statistics.
string(i,2);
996 if (country.empty()) {
1001 int ncountries = countries->
elements(
"country");
1002 if (ncountries == 0) {
1008 for (
int k = 0; k < ncountries; ++k) {
1009 if (countries->
element(
"country", k)->
value() == country) {
1041 if (data->
elements(
"countries") == 0) {
1042 data->
append(
"countries");
1047 for (
int i = 1; i < statistics.
nrows(); ++i) {
1050 std::string country = statistics.
string(i,2);
1051 double wall = statistics.
real(i,5);
1052 double cpu = statistics.
real(i,6);
1053 double gCO2e = statistics.
real(i,7);
1056 if (country.empty()) {
1057 country =
"unknown";
1064 int ncountries = countries->
elements();
1065 if (ncountries == 0) {
1066 country_element = countries->
append(country);
1069 for (
int k = 0; k < ncountries; ++k) {
1071 if (element->
name() == country) {
1072 country_element = element;
1076 if (country_element == NULL) {
1077 country_element = countries->
append(country);
1122 if (data->
elements(
"versions") == 0) {
1123 data->
append(
"versions");
1128 for (
int i = 1; i < statistics.
nrows(); ++i) {
1131 std::string version = statistics.
string(i,4);
1132 double wall = statistics.
real(i,5);
1133 double cpu = statistics.
real(i,6);
1134 double gCO2e = statistics.
real(i,7);
1137 if (version.empty()) {
1138 version =
"unknown";
1145 int nversion = versions->
elements();
1146 if (nversion == 0) {
1147 version_element = versions->
append(version);
1150 for (
int k = 0; k < nversion; ++k) {
1152 if (element->
name() == version) {
1153 version_element = element;
1157 if (version_element == NULL) {
1158 version_element = versions->
append(version);
1203 if (data->
elements(
"daily") == 0) {
1209 for (
int i = 1; i < statistics.
nrows(); ++i) {
1212 std::string date = statistics.
string(i,0).substr(0,10);
1213 std::string country = statistics.
string(i,2);
1214 std::string tool = statistics.
string(i,3);
1215 std::string version = statistics.
string(i,4);
1216 double wall = statistics.
real(i,5);
1217 double cpu = statistics.
real(i,6);
1218 double gCO2e = statistics.
real(i,7);
1229 int ndates = daily->
elements(
"date");
1231 date_node = daily->
append(
"date");
1235 for (
int k = 0; k < ndates; ++k) {
1238 date_node = element;
1242 if (date_node == NULL) {
1243 date_node = daily->
append(
"date");
1251 if (date_node->
elements(
"tools") == 0) {
1252 tools = date_node->
append(
"tools");
1255 tools = date_node->
element(
"tools",0);
1264 tool_element = tools->
append(tool);
1267 for (
int k = 0; k < ntools; ++k) {
1269 if (element->
name() == tool) {
1270 tool_element = element;
1274 if (tool_element == NULL) {
1275 tool_element = tools->
append(tool);
1283 tool_element->
attribute(
"version", version);
1286 tool_element->
attribute(
"country", country);
Abstract XML node base class.
void update_countries_data(GXml &xml, const GCsv &statistics)
Update countries in high-level statistics data.
void update_host_country(void)
Update host country.
void open(const GFilename &filename, const bool &clobber=false)
Open log file.
void now(void)
Set time to current time.
void save(const GFilename &filename) const
Save XML document into file.
void update_dates(GXml &xml, const GCsv &statistics)
Update dates in high-level statistics header.
void write_heartbeat(void)
Write heartbeat file.
void create_lock_file(void)
Create the lock file.
XML class interface definition.
std::string value(void) const
Return string value.
void init_members(void)
Initialise class members.
void chatter(const GChatter &chatter)
Set chattiness.
Comma-separated values table class.
virtual int elements(void) const
Return number of GXMLElement children of node.
virtual GDaemon * clone(void) const
Clone Daemon.
int m_period
Wake-up period in seconds.
void load(const GFilename &filename)
Load XML document from file.
void update_daily(GXml &xml, const GCsv &statistics)
Update daily statistics.
void update_countries_header(GXml &xml, const GCsv &statistics)
Update countries in high-level statistics header.
const std::string & name(void) const
Return XML element name.
pid_t lock_pid(void) const
Returns process ID in lock file.
GFilename lock_filename(void) const
Returns name of daemon lock file.
void update_statistics(void)
Update application statistics.
std::string string(const int &row, const int &col) const
Get string value.
void create_xml(const GFilename &filename)
Create high-level statistics XML file.
void update_versions_data(GXml &xml, const GCsv &statistics)
Update versions in high-level statistics data.
void delete_lock_file(void)
Delete daemon lock file.
bool is_empty(void) const
Signals if document has no child nodes.
GXmlElement * element(const int &index)
Return pointer to child element.
bool alive(void) const
Check if daemon is alive.
const GXmlAttribute * attribute(const int &index) const
Return attribute.
bool has_attribute(const std::string &name) const
Check if element has a given attribute.
void date(const bool &flag)
Set date flag that controls date prefixing.
int m_heartbeat
Heartbeat period in seconds.
bool exists(void) const
Checks whether file exists.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print Daemon.
void close(void)
Close log file.
void flush(const bool &force=false)
Flush string buffer into log file.
void free_members(void)
Delete class members.
const int & nrows(void) const
Return number of rows.
GFilename gamma_filename(const std::string &name)
Returns filename in .gamma directory.
void copy_members(const GDaemon &daemon)
Copy class members.
GDaemon(void)
Void constructor.
virtual ~GDaemon(void)
Destructor.
double real(const int &row, const int &col) const
Get double precision value.
std::string url(void) const
Return Uniform Resource Locator (URL)
GChatter m_chatter
Chattiness of logger.
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
std::string host_country(const bool &force_query=false)
Return two-digit host country code.
virtual bool is_empty(void) const
Signals if node has no child nodes.
virtual void clear(void)
Clear Daemon.
int toint(const std::string &arg)
Convert string into integer value.
GDaemon & operator=(const GDaemon &daemon)
Assignment operator.
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
void recover_valid_xml(void)
Recovers a valid XML file.
void start(void)
Starts the daemon.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
GFilename heartbeat_filename(void) const
Returns name of daemon heartbeat file.
Abstract XML node base class interface definition.
std::string utc(const int &precision=0) const
Return time as string in UTC time system.
Time class interface definition.
GXmlNode * append(const GXmlNode &node)
Append child node to XML document root.
Comma-separated values table class definition.
double todouble(const std::string &arg)
Convert string into double precision value.
void clear(void)
Clear object.
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.