otsdaq_utilities  v2_04_01
ConsoleSupervisor.cc
1 #include "otsdaq-utilities/Console/ConsoleSupervisor.h"
2 #include <xdaq/NamespaceURI.h>
3 #include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h"
4 #include "otsdaq-core/Macros/CoutMacros.h"
5 #include "otsdaq-core/MessageFacility/MessageFacility.h"
6 #include "otsdaq-core/NetworkUtilities/ReceiverSocket.h"
7 #include "otsdaq-core/XmlUtilities/HttpXmlDocument.h"
8 
9 #include <dirent.h> //for DIR
10 #include <sys/stat.h> //for mkdir
11 #include <fstream>
12 #include <iostream>
13 #include <string>
14 #include <thread> //for std::thread
15 
16 using namespace ots;
17 
18 // UDP Message Format:
19 // UDPMESSAGE|TIMESTAMP|SEQNUM|HOSTNAME|HOSTADDR|SEVERITY|CATEGORY|APPLICATION|PID|ITERATION|MODULE|(FILE|LINE)|MESSAGE
20 // FILE and LINE are only printed for s67+
21 
22 XDAQ_INSTANTIATOR_IMPL(ConsoleSupervisor)
23 
24 #define USER_CONSOLE_PREF_PATH \
25  std::string(__ENV__("SERVICE_DATA_PATH")) + "/ConsolePreferences/"
26 #define USERS_PREFERENCES_FILETYPE "pref"
27 
28 #define QUIET_CFG_FILE \
29  std::string(__ENV__("USER_DATA")) + \
30  "/MessageFacilityConfigurations/" \
31  "QuietForwarder.cfg"
32 
33 #define CONSOLE_SPECIAL_ERROR std::string("||0|||Error|Console|-1||ConsoleSupervisor|")
34 #define CONSOLE_SPECIAL_WARNING \
35  std::string("||0|||Warning|Console|-1||ConsoleSupervisor|")
36 
37 #undef __MF_SUBJECT__
38 #define __MF_SUBJECT__ "Console"
39 
40 //========================================================================================================================
41 ConsoleSupervisor::ConsoleSupervisor(xdaq::ApplicationStub* stub)
42  : CoreSupervisorBase(stub), writePointer_(0), messageCount_(0)
43 {
44  __SUP_COUT__ << "Constructor started." << __E__;
45 
46  INIT_MF("ConsoleSupervisor");
47 
48  // attempt to make directory structure (just in case)
49  mkdir(((std::string)USER_CONSOLE_PREF_PATH).c_str(), 0755);
50 
51  init();
52 
53  __SUP_COUT__ << "Constructor complete." << __E__;
54 }
55 
56 //========================================================================================================================
57 ConsoleSupervisor::~ConsoleSupervisor(void) { destroy(); }
58 //========================================================================================================================
59 void ConsoleSupervisor::init(void)
60 {
61  // start mf msg listener
62  std::thread(
63  [](ConsoleSupervisor* cs) {
64  ConsoleSupervisor::messageFacilityReceiverWorkLoop(cs);
65  },
66  this)
67  .detach();
68 } // end init()
69 
70 //========================================================================================================================
71 void ConsoleSupervisor::destroy(void)
72 {
73  // called by destructor
74 } // end destroy()
75 
76 //========================================================================================================================
77 // messageFacilityReceiverWorkLoop ~~
78 // Thread for printing Message Facility messages without decorations
79 // Note: Uses std::mutex to avoid conflict with reading thread.
80 void ConsoleSupervisor::messageFacilityReceiverWorkLoop(ConsoleSupervisor* cs) try
81 {
82  __COUT__ << std::endl;
83 
84  std::string configFile = QUIET_CFG_FILE;
85  FILE* fp = fopen(configFile.c_str(), "r");
86  if(!fp)
87  {
88  __SS__ << "File with port info could not be loaded: " << QUIET_CFG_FILE
89  << std::endl;
90  __COUT__ << "\n" << ss.str();
91  __SS_THROW__;
92  }
93  char tmp[100];
94  fgets(tmp, 100, fp); // receive port (ignore)
95  fgets(tmp, 100, fp); // destination port *** used here ***
96  int myport;
97  sscanf(tmp, "%*s %d", &myport);
98 
99  fgets(tmp, 100, fp); // destination ip *** used here ***
100  char myip[100];
101  sscanf(tmp, "%*s %s", myip);
102  fclose(fp);
103 
104  ReceiverSocket rsock(myip, myport); // Take Port from Configuration
105  try
106  {
107  rsock.initialize();
108  }
109  catch(...)
110  {
111  // lockout the messages array for the remainder of the scope
112  // this guarantees the reading thread can safely access the messages
113  std::lock_guard<std::mutex> lock(cs->messageMutex_);
114 
115  // NOTE: if we do not want this to be fatal, do not throw here, just print out
116 
117  if(1) // generate special message and throw for failed socket
118  {
119  __SS__ << "FATAL Console error. Could not initialize socket on port "
120  << myport
121  << ". Perhaps the port is already in use? Check for multiple stale "
122  "instances of otsdaq processes, or notify admins."
123  << " Multiple instances of otsdaq on the same node should be "
124  "possible, but port numbers must be unique."
125  << std::endl;
126  __SS_THROW__;
127  }
128 
129  // generate special message to indicate failed socket
130  __SS__ << "FATAL Console error. Could not initialize socket on port " << myport
131  << ". Perhaps it is already in use? Exiting Console receive loop."
132  << std::endl;
133  __COUT__ << ss.str();
134 
135  cs->messages_[cs->writePointer_].set(CONSOLE_SPECIAL_ERROR + ss.str(),
136  cs->messageCount_++);
137 
138  if(++cs->writePointer_ == cs->messages_.size()) // handle wrap-around
139  cs->writePointer_ = 0;
140 
141  return;
142  }
143 
144  std::string buffer;
145  int i = 0;
146  int heartbeatCount = 0;
147  int selfGeneratedMessageCount = 0;
148 
149  std::map<unsigned int, unsigned int>
150  sourceLastSequenceID; // map from sourceID to
151  // lastSequenceID to
152  // identify missed messages
153  long long newSourceId;
154  unsigned int newSequenceId;
155 
156  while(1)
157  {
158  // if receive succeeds display message
159 
160  if(rsock.receive(
161  buffer, 1 /*timeoutSeconds*/, 0 /*timeoutUSeconds*/, false /*verbose*/) !=
162  -1)
163  {
164  if(i != 200)
165  {
166  __COUT__ << "Console has first message." << std::endl;
167  i = 200; // mark so things are good for all time. (this indicates things
168  // are configured to be sent here)
169 
170  __MOUT__ << "DEBUG messages look like this." << std::endl;
171  __MOUT_INFO__ << "INFO messages look like this." << std::endl;
172  __MOUT_WARN__ << "WARNING messages look like this." << std::endl;
173  __MOUT_ERR__ << "ERROR messages look like this." << std::endl;
174 
175  // //to debug special packets
176  // __SS__ << "???";
177  // cs->messages_[cs->writePointer_].set(CONSOLE_SPECIAL_ERROR
178  //+ ss.str(),
179  // cs->messageCount_++);
180  //
181  // if(++cs->writePointer_ == cs->messages_.size()) //handle
182  // wrap-around cs->writePointer_ = 0;
183  }
184 
185  if(selfGeneratedMessageCount)
186  --selfGeneratedMessageCount; // decrement internal message count
187  else // reset heartbeat if external messages are coming through
188  heartbeatCount = 0;
189 
190  //__COUT__ << buffer << std::endl;
191 
192  // lockout the messages array for the remainder of the scope
193  // this guarantees the reading thread can safely access the messages
194  std::lock_guard<std::mutex> lock(cs->messageMutex_);
195 
196  cs->messages_[cs->writePointer_].set(buffer, cs->messageCount_++);
197 
198  // check if sequence ID is out of order
199  newSourceId = cs->messages_[cs->writePointer_].getSourceIDAsNumber();
200  newSequenceId = cs->messages_[cs->writePointer_].getSequenceIDAsNumber();
201 
202  //__COUT__ << "newSourceId: " << newSourceId << std::endl;
203  //__COUT__ << "newSequenceId: " << newSequenceId << std::endl;
204 
205  if(newSourceId != -1 &&
206  sourceLastSequenceID.find(newSourceId) !=
207  sourceLastSequenceID.end() && // ensure not first packet received
208  ((newSequenceId == 0 && sourceLastSequenceID[newSourceId] !=
209  (unsigned int)-1) || // wrap around case
210  newSequenceId !=
211  sourceLastSequenceID[newSourceId] + 1)) // normal sequence case
212  {
213  // missed some messages!
214  __SS__ << "Missed packets from "
215  << cs->messages_[cs->writePointer_].getSource()
216  << "! Sequence IDs " << sourceLastSequenceID[newSourceId] << " to "
217  << newSequenceId << "." << std::endl;
218  std::cout << ss.str();
219 
220  if(++cs->writePointer_ == cs->messages_.size()) // handle wrap-around
221  cs->writePointer_ = 0;
222 
223  // generate special message to indicate missed packets
224  cs->messages_[cs->writePointer_].set(CONSOLE_SPECIAL_WARNING + ss.str(),
225  cs->messageCount_++);
226  }
227 
228  // save the new last sequence ID
229  sourceLastSequenceID[newSourceId] = newSequenceId;
230 
231  if(++cs->writePointer_ == cs->messages_.size()) // handle wrap-around
232  cs->writePointer_ = 0;
233  }
234  else
235  {
236  if(i < 120) // if nothing received for 120 seconds, then something is wrong
237  // with Console configuration
238  ++i;
239 
240  sleep(1); // sleep one second, if timeout
241 
242  // every 60 heartbeatCount (2 seconds each = 1 sleep and 1 timeout) print a
243  // heartbeat message
244  if(i != 200 || // show first message, if not already a message
245  //(heartbeatCount < 60 * 5 &&
246  heartbeatCount % 60 == 59 //)
247  ) // every ~2 min for first 5 messages
248  {
249  ++selfGeneratedMessageCount; // increment internal message count
250  __MOUT__ << "Console is alive and waiting... (if no messages, next "
251  "heartbeat is in approximately two minutes)"
252  << std::endl;
253  }
254  else if(heartbeatCount % (60 * 30) == 59) // approx every hour
255  {
256  ++selfGeneratedMessageCount; // increment internal message count
257  __MOUT__ << "Console is alive and waiting a long time... (if no "
258  "messages, next heartbeat is in approximately one hour)"
259  << std::endl;
260  }
261 
262  ++heartbeatCount;
263  }
264 
265  // if nothing received for 2 minutes seconds, then something is wrong with Console
266  // configuration after 5 seconds there is a self-send. Which will at least
267  // confirm configuration. OR if 5 generated messages and never cleared.. then
268  // the forwarding is not working.
269  if(i == 120 || selfGeneratedMessageCount == 5)
270  {
271  __COUTV__(i);
272  __COUTV__(selfGeneratedMessageCount);
273  __COUT__ << "No messages received at Console Supervisor. Exiting Console "
274  "messageFacilityReceiverWorkLoop"
275  << std::endl;
276  break; // assume something wrong, and break loop
277  }
278  }
279 
280 } // end messageFacilityReceiverWorkLoop()
281 catch(const std::runtime_error& e)
282 {
283  __COUT_ERR__ << "Error caught at Console Supervisor thread: " << e.what() << __E__;
284 }
285 catch(...)
286 {
287  __COUT_ERR__ << "Unknown error caught at Console Supervisor thread." << __E__;
288 }
289 
290 //========================================================================================================================
291 void ConsoleSupervisor::defaultPage(xgi::Input* in, xgi::Output* out)
292 {
293  __SUP_COUT__ << "ApplicationDescriptor LID="
294  << getApplicationDescriptor()->getLocalId() << std::endl;
295  *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame "
296  "src='/WebPath/html/Console.html?urn="
297  << getApplicationDescriptor()->getLocalId() << "'></frameset></html>";
298 } // end defaultPage()
299 
300 //========================================================================================================================
301 // forceSupervisorPropertyValues
302 // override to force supervisor property values (and ignore user settings)
303 void ConsoleSupervisor::forceSupervisorPropertyValues()
304 {
305  CorePropertySupervisorBase::setSupervisorProperty(
306  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes,
307  "GetConsoleMsgs");
308  // CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NeedUsernameRequestTypes,
309  // "SaveUserPreferences | LoadUserPreferences");
310 } // end forceSupervisorPropertyValues()
311 
312 //========================================================================================================================
313 // Request
314 // Handles Web Interface requests to Console supervisor.
315 // Does not refresh cookie for automatic update checks.
316 void ConsoleSupervisor::request(const std::string& requestType,
317  cgicc::Cgicc& cgiIn,
318  HttpXmlDocument& xmlOut,
319  const WebUsers::RequestUserInfo& userInfo)
320 {
321  //__SUP_COUT__ << "requestType " << requestType << std::endl;
322 
323  // Commands:
324  // GetConsoleMsgs
325  // SaveUserPreferences
326  // LoadUserPreferences
327 
328  // Note: to report to logbook admin status use
329  // xmlOut.addTextElementToData(XML_ADMIN_STATUS,refreshTempStr_);
330 
331  if(requestType == "GetConsoleMsgs")
332  {
333  // lindex of -1 means first time and user just gets update lcount and lindex
334  std::string lastUpdateCountStr = CgiDataUtilities::postData(cgiIn, "lcount");
335  std::string lastUpdateIndexStr = CgiDataUtilities::postData(cgiIn, "lindex");
336 
337  if(lastUpdateCountStr == "" || lastUpdateIndexStr == "")
338  {
339  __SUP_COUT_ERR__ << "Invalid Parameters! lastUpdateCount="
340  << lastUpdateCountStr
341  << ", lastUpdateIndex=" << lastUpdateIndexStr << std::endl;
342  xmlOut.addTextElementToData("Error",
343  "Error - Invalid parameters for GetConsoleMsgs.");
344  return;
345  }
346 
347  clock_t lastUpdateCount;
348  sscanf(lastUpdateCountStr.c_str(), "%ld", &lastUpdateCount);
349 
350  unsigned int lastUpdateIndex;
351  sscanf(lastUpdateIndexStr.c_str(), "%u", &lastUpdateIndex);
352  // __SUP_COUT__ << "lastUpdateCount=" << lastUpdateCount <<
353  // ", lastUpdateIndex=" << lastUpdateIndex << std::endl;
354 
355  insertMessageRefresh(&xmlOut, lastUpdateCount, lastUpdateIndex);
356  }
357  else if(requestType == "SaveUserPreferences")
358  {
359  int colorIndex = CgiDataUtilities::postDataAsInt(cgiIn, "colorIndex");
360  int showSideBar = CgiDataUtilities::postDataAsInt(cgiIn, "showSideBar");
361  int noWrap = CgiDataUtilities::postDataAsInt(cgiIn, "noWrap");
362  int messageOnly = CgiDataUtilities::postDataAsInt(cgiIn, "messageOnly");
363  int hideLineNumers = CgiDataUtilities::postDataAsInt(cgiIn, "hideLineNumers");
364 
365  __SUP_COUT__ << "requestType " << requestType << std::endl;
366  __SUP_COUT__ << "colorIndex: " << colorIndex << std::endl;
367  __SUP_COUT__ << "showSideBar: " << showSideBar << std::endl;
368  __SUP_COUT__ << "noWrap: " << noWrap << std::endl;
369  __SUP_COUT__ << "messageOnly: " << messageOnly << std::endl;
370  __SUP_COUT__ << "hideLineNumers: " << hideLineNumers << std::endl;
371 
372  if(userInfo.username_ == "") // should never happen?
373  {
374  __SUP_COUT_ERR__ << "Invalid user found! user=" << userInfo.username_
375  << std::endl;
376  xmlOut.addTextElementToData("Error",
377  "Error - InvauserInfo.username_user found.");
378  return;
379  }
380 
381  std::string fn = (std::string)USER_CONSOLE_PREF_PATH + userInfo.username_ + "." +
382  (std::string)USERS_PREFERENCES_FILETYPE;
383 
384  __SUP_COUT__ << "Save preferences: " << fn << std::endl;
385  FILE* fp = fopen(fn.c_str(), "w");
386  if(!fp)
387  {
388  __SS__;
389  __THROW__(ss.str() + "Could not open file: " + fn);
390  }
391  fprintf(fp, "colorIndex %d\n", colorIndex);
392  fprintf(fp, "showSideBar %d\n", showSideBar);
393  fprintf(fp, "noWrap %d\n", noWrap);
394  fprintf(fp, "messageOnly %d\n", messageOnly);
395  fprintf(fp, "hideLineNumers %d\n", hideLineNumers);
396  fclose(fp);
397  }
398  else if(requestType == "LoadUserPreferences")
399  {
400  __SUP_COUT__ << "requestType " << requestType << std::endl;
401 
402  unsigned int colorIndex, showSideBar, noWrap, messageOnly, hideLineNumers;
403 
404  if(userInfo.username_ == "") // should never happen?
405  {
406  __SUP_COUT_ERR__ << "Invalid user found! user=" << userInfo.username_
407  << std::endl;
408  xmlOut.addTextElementToData("Error", "Error - Invalid user found.");
409  return;
410  }
411 
412  std::string fn = (std::string)USER_CONSOLE_PREF_PATH + userInfo.username_ + "." +
413  (std::string)USERS_PREFERENCES_FILETYPE;
414 
415  __SUP_COUT__ << "Load preferences: " << fn << std::endl;
416 
417  FILE* fp = fopen(fn.c_str(), "r");
418  if(!fp)
419  {
420  // return defaults
421  __SUP_COUT__ << "Returning defaults." << std::endl;
422  xmlOut.addTextElementToData("colorIndex", "0");
423  xmlOut.addTextElementToData("showSideBar", "0");
424  xmlOut.addTextElementToData("noWrap", "1");
425  xmlOut.addTextElementToData("messageOnly", "0");
426  xmlOut.addTextElementToData("hideLineNumers", "1");
427  return;
428  }
429  fscanf(fp, "%*s %u", &colorIndex);
430  fscanf(fp, "%*s %u", &showSideBar);
431  fscanf(fp, "%*s %u", &noWrap);
432  fscanf(fp, "%*s %u", &messageOnly);
433  fscanf(fp, "%*s %u", &hideLineNumers);
434  fclose(fp);
435  __SUP_COUT__ << "colorIndex: " << colorIndex << std::endl;
436  __SUP_COUT__ << "showSideBar: " << showSideBar << std::endl;
437  __SUP_COUT__ << "noWrap: " << noWrap << std::endl;
438  __SUP_COUT__ << "messageOnly: " << messageOnly << std::endl;
439  __SUP_COUT__ << "hideLineNumers: " << hideLineNumers << std::endl;
440 
441  char tmpStr[20];
442  sprintf(tmpStr, "%u", colorIndex);
443  xmlOut.addTextElementToData("colorIndex", tmpStr);
444  sprintf(tmpStr, "%u", showSideBar);
445  xmlOut.addTextElementToData("showSideBar", tmpStr);
446  sprintf(tmpStr, "%u", noWrap);
447  xmlOut.addTextElementToData("noWrap", tmpStr);
448  sprintf(tmpStr, "%u", messageOnly);
449  xmlOut.addTextElementToData("messageOnly", tmpStr);
450  sprintf(tmpStr, "%u", hideLineNumers);
451  xmlOut.addTextElementToData("hideLineNumers", tmpStr);
452  }
453  else
454  {
455  __SUP_SS__ << "requestType Request, " << requestType << ", not recognized."
456  << __E__;
457  __SUP_SS_THROW__;
458  }
459 } // end request()
460 
461 //========================================================================================================================
462 // ConsoleSupervisor::insertMessageRefresh()
463 // if lastUpdateClock is current, return nothing
464 // else return new messages
465 // (note: lastUpdateIndex==(unsigned int)-1 first time and returns as much as possible//
466 // nothing but lastUpdateClock)
467 //
468 // format of xml:
469 //
470 // <last_update_count/>
471 // <last_update_index/>
472 // <messages>
473 // <message_FIELDNAME*/>
474 //"Level"
475 //"Label"
476 //"Source"
477 //"Msg"
478 //"Time"
479 //"Count"
480 // </messages>
481 //
482 // NOTE: Uses std::mutex to avoid conflict with writing thread. (this is the reading
483 // thread)
484 void ConsoleSupervisor::insertMessageRefresh(HttpXmlDocument* xmlOut,
485  const time_t lastUpdateCount,
486  const unsigned int lastUpdateIndex)
487 {
488  //__SUP_COUT__ << std::endl;
489 
490  // validate lastUpdateIndex
491  if(lastUpdateIndex > messages_.size() && lastUpdateIndex != (unsigned int)-1)
492  {
493  __SS__ << "Invalid lastUpdateIndex: " << lastUpdateIndex
494  << " messagesArray size = " << messages_.size() << std::endl;
495  __SS_THROW__;
496  }
497 
498  // lockout the messages array for the remainder of the scope
499  // this guarantees the reading thread can safely access the messages
500  std::lock_guard<std::mutex> lock(messageMutex_);
501 
502  // newest available read pointer is defined as always one behind writePointer_
503  refreshReadPointer_ = (writePointer_ + messages_.size() - 1) % messages_.size();
504 
505  sprintf(refreshTempStr_, "%lu", messages_[refreshReadPointer_].getCount());
506  xmlOut->addTextElementToData("last_update_count", refreshTempStr_);
507  sprintf(refreshTempStr_, "%u", refreshReadPointer_);
508  xmlOut->addTextElementToData("last_update_index", refreshTempStr_);
509 
510  if(!messages_[refreshReadPointer_].getTime()) // if no data, then no data
511  return;
512 
513  // else, send all messages since last_update_count, from
514  // last_update_index(refreshReadPointer_) on
515  if(lastUpdateIndex != (unsigned int)-1 && // if not first time, and index-count are
516  // valid then start at next message
517  messages_[lastUpdateIndex].getCount() == lastUpdateCount)
518  refreshReadPointer_ = (lastUpdateIndex + 1) % messages_.size();
519  else if(messages_[writePointer_]
520  .getTime()) // check that writePointer_ message has
521  // been initialized, therefore has wrapped
522  // around at least once already
523  {
524  // This means we have had many messages and that some were missed since last
525  // update (give as many messages as we can!)
526  xmlOut->addTextElementToData("message_overflow", "1");
527  __SUP_COUT__ << "Overflow was detected!" << std::endl;
528  refreshReadPointer_ = (writePointer_ + 1) % messages_.size();
529  }
530  else // user does not have valid index, and writePointer_ has not wrapped around, so
531  // give all new messages
532  refreshReadPointer_ = 0;
533 
534  // __SUP_COUT__ << "refreshReadPointer_: " << refreshReadPointer_ << std::endl;
535  // __SUP_COUT__ << "lastUpdateCount: " << lastUpdateCount << std::endl;
536  // __SUP_COUT__ << "writePointer_: " << writePointer_ << std::endl;
537 
538  // return anything from refreshReadPointer_ to writePointer_
539  // all should have a clock greater than lastUpdateClock
540 
541  refreshParent_ = xmlOut->addTextElementToData("messages", "");
542 
543  bool requestOutOfSync = false;
544  std::string requestOutOfSyncMsg;
545  // output oldest to new (from refreshReadPointer_ to writePointer_-1, inclusive)
546  for(/*refreshReadPointer_=<first index to read>*/;
547  refreshReadPointer_ != writePointer_;
548  refreshReadPointer_ = (refreshReadPointer_ + 1) % messages_.size())
549  {
550  if(messages_[refreshReadPointer_].getCount() < lastUpdateCount)
551  {
552  if(!requestOutOfSync) // record out of sync message once only
553  {
554  requestOutOfSync = true;
555  __SS__ << "Request is out of sync! Message count should be more recent "
556  "than update clock! "
557  << messages_[refreshReadPointer_].getCount() << " < "
558  << lastUpdateCount << std::endl;
559  requestOutOfSyncMsg = ss.str();
560  }
561  // assume these messages are new (due to a system restart)
562  // continue;
563  }
564 
565  // for all fields, give value
566  for(refreshIndex_ = 0;
567  refreshIndex_ < messages_[refreshReadPointer_].fields.size();
568  ++refreshIndex_)
569  xmlOut->addTextElementToParent(
570  "message_" +
571  messages_[refreshReadPointer_].fields[refreshIndex_].fieldName,
572  messages_[refreshReadPointer_].getField(refreshIndex_),
573  refreshParent_);
574 
575  // give timestamp also
576  sprintf(refreshTempStr_, "%lu", messages_[refreshReadPointer_].getTime());
577  xmlOut->addTextElementToParent("message_Time", refreshTempStr_, refreshParent_);
578  // give clock also
579  sprintf(refreshTempStr_, "%lu", messages_[refreshReadPointer_].getCount());
580  xmlOut->addTextElementToParent("message_Count", refreshTempStr_, refreshParent_);
581  }
582 
583  if(requestOutOfSync) // if request was out of sync, show message
584  __SUP_COUT__ << requestOutOfSyncMsg;
585 }