$treeview $search $mathjax $extrastylesheet
otsdaq_utilities
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-utilities/Console/ConsoleSupervisor.h" 00002 #include <xdaq/NamespaceURI.h> 00003 #include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h" 00004 #include "otsdaq-core/Macros/CoutMacros.h" 00005 #include "otsdaq-core/MessageFacility/MessageFacility.h" 00006 #include "otsdaq-core/NetworkUtilities/ReceiverSocket.h" 00007 #include "otsdaq-core/XmlUtilities/HttpXmlDocument.h" 00008 00009 #include <dirent.h> //for DIR 00010 #include <sys/stat.h> //for mkdir 00011 #include <fstream> 00012 #include <iostream> 00013 #include <string> 00014 #include <thread> //for std::thread 00015 00016 using namespace ots; 00017 00018 // UDP Message Format: 00019 // UDPMESSAGE|TIMESTAMP|SEQNUM|HOSTNAME|HOSTADDR|SEVERITY|CATEGORY|APPLICATION|PID|ITERATION|MODULE|(FILE|LINE)|MESSAGE 00020 // FILE and LINE are only printed for s67+ 00021 00022 XDAQ_INSTANTIATOR_IMPL(ConsoleSupervisor) 00023 00024 #define USER_CONSOLE_PREF_PATH \ 00025 std::string(getenv("SERVICE_DATA_PATH")) + "/ConsolePreferences/" 00026 #define USERS_PREFERENCES_FILETYPE "pref" 00027 00028 #define QUIET_CFG_FILE \ 00029 std::string(getenv("USER_DATA")) + \ 00030 "/MessageFacilityConfigurations/" \ 00031 "QuietForwarder.cfg" 00032 00033 #define CONSOLE_SPECIAL_ERROR std::string("||0|||Error|Console|-1||ConsoleSupervisor|") 00034 #define CONSOLE_SPECIAL_WARNING \ 00035 std::string("||0|||Warning|Console|-1||ConsoleSupervisor|") 00036 00037 #undef __MF_SUBJECT__ 00038 #define __MF_SUBJECT__ "Console" 00039 00040 //======================================================================================================================== 00041 ConsoleSupervisor::ConsoleSupervisor(xdaq::ApplicationStub* stub) 00042 : CoreSupervisorBase(stub), writePointer_(0), messageCount_(0) 00043 { 00044 __SUP_COUT__ << "Constructor started." << __E__; 00045 00046 INIT_MF("ConsoleSupervisor"); 00047 00048 // attempt to make directory structure (just in case) 00049 mkdir(((std::string)USER_CONSOLE_PREF_PATH).c_str(), 0755); 00050 00051 init(); 00052 00053 __SUP_COUT__ << "Constructor complete." << __E__; 00054 } 00055 00056 //======================================================================================================================== 00057 ConsoleSupervisor::~ConsoleSupervisor(void) { destroy(); } 00058 //======================================================================================================================== 00059 void ConsoleSupervisor::init(void) 00060 { 00061 // start mf msg listener 00062 std::thread( 00063 [](ConsoleSupervisor* cs) { 00064 ConsoleSupervisor::messageFacilityReceiverWorkLoop(cs); 00065 }, 00066 this) 00067 .detach(); 00068 } // end init() 00069 00070 //======================================================================================================================== 00071 void ConsoleSupervisor::destroy(void) 00072 { 00073 // called by destructor 00074 } // end destroy() 00075 00076 //======================================================================================================================== 00077 // messageFacilityReceiverWorkLoop ~~ 00078 // Thread for printing Message Facility messages without decorations 00079 // Note: Uses std::mutex to avoid conflict with reading thread. 00080 void ConsoleSupervisor::messageFacilityReceiverWorkLoop(ConsoleSupervisor* cs) 00081 { 00082 __COUT__ << std::endl; 00083 00084 std::string configFile = QUIET_CFG_FILE; 00085 FILE* fp = fopen(configFile.c_str(), "r"); 00086 if(!fp) 00087 { 00088 __SS__ << "File with port info could not be loaded: " << QUIET_CFG_FILE 00089 << std::endl; 00090 __COUT__ << "\n" << ss.str(); 00091 __SS_THROW__; 00092 } 00093 char tmp[100]; 00094 fgets(tmp, 100, fp); // receive port (ignore) 00095 fgets(tmp, 100, fp); // destination port *** used here *** 00096 int myport; 00097 sscanf(tmp, "%*s %d", &myport); 00098 00099 fgets(tmp, 100, fp); // destination ip *** used here *** 00100 char myip[100]; 00101 sscanf(tmp, "%*s %s", myip); 00102 fclose(fp); 00103 00104 ReceiverSocket rsock(myip, myport); // Take Port from Configuration 00105 try 00106 { 00107 rsock.initialize(); 00108 } 00109 catch(...) 00110 { 00111 // lockout the messages array for the remainder of the scope 00112 // this guarantees the reading thread can safely access the messages 00113 std::lock_guard<std::mutex> lock(cs->messageMutex_); 00114 00115 // NOTE: if we do not want this to be fatal, do not throw here, just print out 00116 00117 if(1) // generate special message and throw for failed socket 00118 { 00119 __SS__ << "FATAL Console error. Could not initialize socket on port " 00120 << myport 00121 << ". Perhaps the port is already in use? Check for multiple stale " 00122 "instances of otsdaq processes, or notify admins." 00123 << " Multiple instances of otsdaq on the same node should be " 00124 "possible, but port numbers must be unique." 00125 << std::endl; 00126 __SS_THROW__; 00127 } 00128 00129 // generate special message to indicate failed socket 00130 __SS__ << "FATAL Console error. Could not initialize socket on port " << myport 00131 << ". Perhaps it is already in use? Exiting Console receive loop." 00132 << std::endl; 00133 __COUT__ << ss.str(); 00134 00135 cs->messages_[cs->writePointer_].set(CONSOLE_SPECIAL_ERROR + ss.str(), 00136 cs->messageCount_++); 00137 00138 if(++cs->writePointer_ == cs->messages_.size()) // handle wrap-around 00139 cs->writePointer_ = 0; 00140 00141 return; 00142 } 00143 00144 std::string buffer; 00145 int i = 0; 00146 int heartbeatCount = 0; 00147 int selfGeneratedMessageCount = 0; 00148 00149 std::map<unsigned int, unsigned int> 00150 sourceLastSequenceID; // map from sourceID to 00151 // lastSequenceID to 00152 // identify missed messages 00153 long long newSourceId; 00154 unsigned int newSequenceId; 00155 00156 while(1) 00157 { 00158 // if receive succeeds display message 00159 00160 if(rsock.receive( 00161 buffer, 1 /*timeoutSeconds*/, 0 /*timeoutUSeconds*/, false /*verbose*/) != 00162 -1) 00163 { 00164 if(i != 200) 00165 { 00166 __COUT__ << "Console has first message." << std::endl; 00167 i = 200; // mark so things are good for all time. (this indicates things 00168 // are configured to be sent here) 00169 00170 __MOUT__ << "DEBUG messages look like this." << std::endl; 00171 __MOUT_INFO__ << "INFO messages look like this." << std::endl; 00172 __MOUT_WARN__ << "WARNING messages look like this." << std::endl; 00173 __MOUT_ERR__ << "ERROR messages look like this." << std::endl; 00174 00175 // //to debug special packets 00176 // __SS__ << "???"; 00177 // cs->messages_[cs->writePointer_].set(CONSOLE_SPECIAL_ERROR 00178 //+ ss.str(), 00179 // cs->messageCount_++); 00180 // 00181 // if(++cs->writePointer_ == cs->messages_.size()) //handle 00182 // wrap-around cs->writePointer_ = 0; 00183 } 00184 00185 if(selfGeneratedMessageCount) 00186 --selfGeneratedMessageCount; // decrement internal message count 00187 else 00188 heartbeatCount = 00189 0; // reset heartbeat if external messages are coming through 00190 00191 //__COUT__ << buffer << std::endl; 00192 00193 // lockout the messages array for the remainder of the scope 00194 // this guarantees the reading thread can safely access the messages 00195 std::lock_guard<std::mutex> lock(cs->messageMutex_); 00196 00197 cs->messages_[cs->writePointer_].set(buffer, cs->messageCount_++); 00198 00199 // check if sequence ID is out of order 00200 newSourceId = cs->messages_[cs->writePointer_].getSourceIDAsNumber(); 00201 newSequenceId = cs->messages_[cs->writePointer_].getSequenceIDAsNumber(); 00202 00203 //__COUT__ << "newSourceId: " << newSourceId << std::endl; 00204 //__COUT__ << "newSequenceId: " << newSequenceId << std::endl; 00205 00206 if(newSourceId != -1 && 00207 sourceLastSequenceID.find(newSourceId) != 00208 sourceLastSequenceID.end() && // ensure not first packet received 00209 ((newSequenceId == 0 && sourceLastSequenceID[newSourceId] != 00210 (unsigned int)-1) || // wrap around case 00211 newSequenceId != 00212 sourceLastSequenceID[newSourceId] + 1)) // normal sequence case 00213 { 00214 // missed some messages! 00215 __SS__ << "Missed packets from " 00216 << cs->messages_[cs->writePointer_].getSource() 00217 << "! Sequence IDs " << sourceLastSequenceID[newSourceId] << " to " 00218 << newSequenceId << "." << std::endl; 00219 std::cout << ss.str(); 00220 00221 if(++cs->writePointer_ == cs->messages_.size()) // handle wrap-around 00222 cs->writePointer_ = 0; 00223 00224 // generate special message to indicate missed packets 00225 cs->messages_[cs->writePointer_].set(CONSOLE_SPECIAL_WARNING + ss.str(), 00226 cs->messageCount_++); 00227 } 00228 00229 // save the new last sequence ID 00230 sourceLastSequenceID[newSourceId] = newSequenceId; 00231 00232 if(++cs->writePointer_ == cs->messages_.size()) // handle wrap-around 00233 cs->writePointer_ = 0; 00234 } 00235 else 00236 { 00237 if(i < 120) // if nothing received for 120 seconds, then something is wrong 00238 // with Console configuration 00239 ++i; 00240 00241 sleep(1); // sleep one second, if timeout 00242 00243 // every 60 heartbeatCount (2 seconds each = 1 sleep and 1 timeout) print a 00244 // heartbeat message 00245 if(i != 200 || // show first message, if not already a message 00246 (heartbeatCount < 60 * 5 && 00247 heartbeatCount % 60 == 59)) // every ~2 min for first 5 messages 00248 { 00249 ++selfGeneratedMessageCount; // increment internal message count 00250 __MOUT__ << "Console is alive and waiting... (if no messages, next " 00251 "heartbeat is in approximately two minutes)" 00252 << std::endl; 00253 } 00254 else if(heartbeatCount % (60 * 30) == 59) // approx every hour 00255 { 00256 ++selfGeneratedMessageCount; // increment internal message count 00257 __MOUT__ << "Console is alive and waiting a long time... (if no " 00258 "messages, next heartbeat is in approximately one hour)" 00259 << std::endl; 00260 } 00261 00262 ++heartbeatCount; 00263 } 00264 00265 // if nothing received for 2 minutes seconds, then something is wrong with Console 00266 // configuration after 5 seconds there is a self-send. Which will at least 00267 // confirm configuration. OR if 5 generated messages and never cleared.. then 00268 // the forwarding is not working. 00269 if(i == 120 || selfGeneratedMessageCount == 5) 00270 { 00271 __COUT__ << "No messages received at Console Supervisor. Exiting Console " 00272 "messageFacilityReceiverWorkLoop" 00273 << std::endl; 00274 break; // assume something wrong, and break loop 00275 } 00276 } 00277 00278 } // end messageFacilityReceiverWorkLoop() 00279 00280 //======================================================================================================================== 00281 void ConsoleSupervisor::defaultPage(xgi::Input* in, xgi::Output* out) 00282 { 00283 __SUP_COUT__ << "ApplicationDescriptor LID=" 00284 << getApplicationDescriptor()->getLocalId() << std::endl; 00285 *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame " 00286 "src='/WebPath/html/Console.html?urn=" 00287 << getApplicationDescriptor()->getLocalId() << "'></frameset></html>"; 00288 } // end defaultPage() 00289 00290 //======================================================================================================================== 00291 // forceSupervisorPropertyValues 00292 // override to force supervisor property values (and ignore user settings) 00293 void ConsoleSupervisor::forceSupervisorPropertyValues() 00294 { 00295 CorePropertySupervisorBase::setSupervisorProperty( 00296 CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes, 00297 "GetConsoleMsgs"); 00298 // CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NeedUsernameRequestTypes, 00299 // "SaveUserPreferences | LoadUserPreferences"); 00300 } // end forceSupervisorPropertyValues() 00301 00302 //======================================================================================================================== 00303 // Request 00304 // Handles Web Interface requests to Console supervisor. 00305 // Does not refresh cookie for automatic update checks. 00306 void ConsoleSupervisor::request(const std::string& requestType, 00307 cgicc::Cgicc& cgiIn, 00308 HttpXmlDocument& xmlOut, 00309 const WebUsers::RequestUserInfo& userInfo) 00310 { 00311 //__SUP_COUT__ << "requestType " << requestType << std::endl; 00312 00313 // Commands: 00314 // GetConsoleMsgs 00315 // SaveUserPreferences 00316 // LoadUserPreferences 00317 00318 // Note: to report to logbook admin status use 00319 // xmlOut.addTextElementToData(XML_ADMIN_STATUS,refreshTempStr_); 00320 00321 if(requestType == "GetConsoleMsgs") 00322 { 00323 // lindex of -1 means first time and user just gets update lcount and lindex 00324 std::string lastUpdateCountStr = CgiDataUtilities::postData(cgiIn, "lcount"); 00325 std::string lastUpdateIndexStr = CgiDataUtilities::postData(cgiIn, "lindex"); 00326 00327 if(lastUpdateCountStr == "" || lastUpdateIndexStr == "") 00328 { 00329 __SUP_COUT_ERR__ << "Invalid Parameters! lastUpdateCount=" 00330 << lastUpdateCountStr 00331 << ", lastUpdateIndex=" << lastUpdateIndexStr << std::endl; 00332 xmlOut.addTextElementToData("Error", 00333 "Error - Invalid parameters for GetConsoleMsgs."); 00334 return; 00335 } 00336 00337 clock_t lastUpdateCount; 00338 sscanf(lastUpdateCountStr.c_str(), "%ld", &lastUpdateCount); 00339 00340 unsigned int lastUpdateIndex; 00341 sscanf(lastUpdateIndexStr.c_str(), "%u", &lastUpdateIndex); 00342 // __SUP_COUT__ << "lastUpdateCount=" << lastUpdateCount << 00343 // ", lastUpdateIndex=" << lastUpdateIndex << std::endl; 00344 00345 insertMessageRefresh(&xmlOut, lastUpdateCount, lastUpdateIndex); 00346 } 00347 else if(requestType == "SaveUserPreferences") 00348 { 00349 int colorIndex = CgiDataUtilities::postDataAsInt(cgiIn, "colorIndex"); 00350 int showSideBar = CgiDataUtilities::postDataAsInt(cgiIn, "showSideBar"); 00351 int noWrap = CgiDataUtilities::postDataAsInt(cgiIn, "noWrap"); 00352 int messageOnly = CgiDataUtilities::postDataAsInt(cgiIn, "messageOnly"); 00353 int hideLineNumers = CgiDataUtilities::postDataAsInt(cgiIn, "hideLineNumers"); 00354 00355 __SUP_COUT__ << "requestType " << requestType << std::endl; 00356 __SUP_COUT__ << "colorIndex: " << colorIndex << std::endl; 00357 __SUP_COUT__ << "showSideBar: " << showSideBar << std::endl; 00358 __SUP_COUT__ << "noWrap: " << noWrap << std::endl; 00359 __SUP_COUT__ << "messageOnly: " << messageOnly << std::endl; 00360 __SUP_COUT__ << "hideLineNumers: " << hideLineNumers << std::endl; 00361 00362 if(userInfo.username_ == "") // should never happen? 00363 { 00364 __SUP_COUT_ERR__ << "Invalid user found! user=" << userInfo.username_ 00365 << std::endl; 00366 xmlOut.addTextElementToData("Error", 00367 "Error - InvauserInfo.username_user found."); 00368 return; 00369 } 00370 00371 std::string fn = (std::string)USER_CONSOLE_PREF_PATH + userInfo.username_ + "." + 00372 (std::string)USERS_PREFERENCES_FILETYPE; 00373 00374 __SUP_COUT__ << "Save preferences: " << fn << std::endl; 00375 FILE* fp = fopen(fn.c_str(), "w"); 00376 if(!fp) 00377 { 00378 __SS__; 00379 __THROW__(ss.str() + "Could not open file: " + fn); 00380 } 00381 fprintf(fp, "colorIndex %d\n", colorIndex); 00382 fprintf(fp, "showSideBar %d\n", showSideBar); 00383 fprintf(fp, "noWrap %d\n", noWrap); 00384 fprintf(fp, "messageOnly %d\n", messageOnly); 00385 fprintf(fp, "hideLineNumers %d\n", hideLineNumers); 00386 fclose(fp); 00387 } 00388 else if(requestType == "LoadUserPreferences") 00389 { 00390 __SUP_COUT__ << "requestType " << requestType << std::endl; 00391 00392 unsigned int colorIndex, showSideBar, noWrap, messageOnly, hideLineNumers; 00393 00394 if(userInfo.username_ == "") // should never happen? 00395 { 00396 __SUP_COUT_ERR__ << "Invalid user found! user=" << userInfo.username_ 00397 << std::endl; 00398 xmlOut.addTextElementToData("Error", "Error - Invalid user found."); 00399 return; 00400 } 00401 00402 std::string fn = (std::string)USER_CONSOLE_PREF_PATH + userInfo.username_ + "." + 00403 (std::string)USERS_PREFERENCES_FILETYPE; 00404 00405 __SUP_COUT__ << "Load preferences: " << fn << std::endl; 00406 00407 FILE* fp = fopen(fn.c_str(), "r"); 00408 if(!fp) 00409 { 00410 // return defaults 00411 __SUP_COUT__ << "Returning defaults." << std::endl; 00412 xmlOut.addTextElementToData("colorIndex", "0"); 00413 xmlOut.addTextElementToData("showSideBar", "0"); 00414 xmlOut.addTextElementToData("noWrap", "1"); 00415 xmlOut.addTextElementToData("messageOnly", "0"); 00416 xmlOut.addTextElementToData("hideLineNumers", "1"); 00417 return; 00418 } 00419 fscanf(fp, "%*s %u", &colorIndex); 00420 fscanf(fp, "%*s %u", &showSideBar); 00421 fscanf(fp, "%*s %u", &noWrap); 00422 fscanf(fp, "%*s %u", &messageOnly); 00423 fscanf(fp, "%*s %u", &hideLineNumers); 00424 fclose(fp); 00425 __SUP_COUT__ << "colorIndex: " << colorIndex << std::endl; 00426 __SUP_COUT__ << "showSideBar: " << showSideBar << std::endl; 00427 __SUP_COUT__ << "noWrap: " << noWrap << std::endl; 00428 __SUP_COUT__ << "messageOnly: " << messageOnly << std::endl; 00429 __SUP_COUT__ << "hideLineNumers: " << hideLineNumers << std::endl; 00430 00431 char tmpStr[20]; 00432 sprintf(tmpStr, "%u", colorIndex); 00433 xmlOut.addTextElementToData("colorIndex", tmpStr); 00434 sprintf(tmpStr, "%u", showSideBar); 00435 xmlOut.addTextElementToData("showSideBar", tmpStr); 00436 sprintf(tmpStr, "%u", noWrap); 00437 xmlOut.addTextElementToData("noWrap", tmpStr); 00438 sprintf(tmpStr, "%u", messageOnly); 00439 xmlOut.addTextElementToData("messageOnly", tmpStr); 00440 sprintf(tmpStr, "%u", hideLineNumers); 00441 xmlOut.addTextElementToData("hideLineNumers", tmpStr); 00442 } 00443 else 00444 { 00445 __SUP_SS__ << "requestType Request, " << requestType << ", not recognized." 00446 << __E__; 00447 __SUP_SS_THROW__; 00448 } 00449 } // end request() 00450 00451 //======================================================================================================================== 00452 // ConsoleSupervisor::insertMessageRefresh() 00453 // if lastUpdateClock is current, return nothing 00454 // else return new messages 00455 // (note: lastUpdateIndex==(unsigned int)-1 first time and returns as much as possible// 00456 // nothing but lastUpdateClock) 00457 // 00458 // format of xml: 00459 // 00460 // <last_update_count/> 00461 // <last_update_index/> 00462 // <messages> 00463 // <message_FIELDNAME*/> 00464 //"Level" 00465 //"Label" 00466 //"Source" 00467 //"Msg" 00468 //"Time" 00469 //"Count" 00470 // </messages> 00471 // 00472 // NOTE: Uses std::mutex to avoid conflict with writing thread. (this is the reading 00473 // thread) 00474 void ConsoleSupervisor::insertMessageRefresh(HttpXmlDocument* xmlOut, 00475 const time_t lastUpdateCount, 00476 const unsigned int lastUpdateIndex) 00477 { 00478 //__SUP_COUT__ << std::endl; 00479 00480 // validate lastUpdateIndex 00481 if(lastUpdateIndex > messages_.size() && lastUpdateIndex != (unsigned int)-1) 00482 { 00483 __SS__ << "Invalid lastUpdateIndex: " << lastUpdateIndex 00484 << " messagesArray size = " << messages_.size() << std::endl; 00485 __SS_THROW__; 00486 } 00487 00488 // lockout the messages array for the remainder of the scope 00489 // this guarantees the reading thread can safely access the messages 00490 std::lock_guard<std::mutex> lock(messageMutex_); 00491 00492 // newest available read pointer is defined as always one behind writePointer_ 00493 refreshReadPointer_ = (writePointer_ + messages_.size() - 1) % messages_.size(); 00494 00495 sprintf(refreshTempStr_, "%lu", messages_[refreshReadPointer_].getCount()); 00496 xmlOut->addTextElementToData("last_update_count", refreshTempStr_); 00497 sprintf(refreshTempStr_, "%u", refreshReadPointer_); 00498 xmlOut->addTextElementToData("last_update_index", refreshTempStr_); 00499 00500 if(!messages_[refreshReadPointer_].getTime()) // if no data, then no data 00501 return; 00502 00503 // else, send all messages since last_update_count, from 00504 // last_update_index(refreshReadPointer_) on 00505 if(lastUpdateIndex != (unsigned int)-1 && // if not first time, and index-count are 00506 // valid then start at next message 00507 messages_[lastUpdateIndex].getCount() == lastUpdateCount) 00508 refreshReadPointer_ = (lastUpdateIndex + 1) % messages_.size(); 00509 else if(messages_[writePointer_] 00510 .getTime()) // check that writePointer_ message has 00511 // been initialized, therefore has wrapped 00512 // around at least once already 00513 { 00514 // This means we have had many messages and that some were missed since last 00515 // update (give as many messages as we can!) 00516 xmlOut->addTextElementToData("message_overflow", "1"); 00517 __SUP_COUT__ << "Overflow was detected!" << std::endl; 00518 refreshReadPointer_ = (writePointer_ + 1) % messages_.size(); 00519 } 00520 else // user does not have valid index, and writePointer_ has not wrapped around, so 00521 // give all new messages 00522 refreshReadPointer_ = 0; 00523 00524 // __SUP_COUT__ << "refreshReadPointer_: " << refreshReadPointer_ << std::endl; 00525 // __SUP_COUT__ << "lastUpdateCount: " << lastUpdateCount << std::endl; 00526 // __SUP_COUT__ << "writePointer_: " << writePointer_ << std::endl; 00527 00528 // return anything from refreshReadPointer_ to writePointer_ 00529 // all should have a clock greater than lastUpdateClock 00530 00531 refreshParent_ = xmlOut->addTextElementToData("messages", ""); 00532 00533 bool requestOutOfSync = false; 00534 std::string requestOutOfSyncMsg; 00535 // output oldest to new (from refreshReadPointer_ to writePointer_-1, inclusive) 00536 for(/*refreshReadPointer_=<first index to read>*/; 00537 refreshReadPointer_ != writePointer_; 00538 refreshReadPointer_ = (refreshReadPointer_ + 1) % messages_.size()) 00539 { 00540 if(messages_[refreshReadPointer_].getCount() < lastUpdateCount) 00541 { 00542 if(!requestOutOfSync) // record out of sync message once only 00543 { 00544 requestOutOfSync = true; 00545 __SS__ << "Request is out of sync! Message count should be more recent " 00546 "than update clock! " 00547 << messages_[refreshReadPointer_].getCount() << " < " 00548 << lastUpdateCount << std::endl; 00549 requestOutOfSyncMsg = ss.str(); 00550 } 00551 // assume these messages are new (due to a system restart) 00552 // continue; 00553 } 00554 00555 // for all fields, give value 00556 for(refreshIndex_ = 0; 00557 refreshIndex_ < messages_[refreshReadPointer_].fields.size(); 00558 ++refreshIndex_) 00559 xmlOut->addTextElementToParent( 00560 "message_" + 00561 messages_[refreshReadPointer_].fields[refreshIndex_].fieldName, 00562 messages_[refreshReadPointer_].getField(refreshIndex_), 00563 refreshParent_); 00564 00565 // give timestamp also 00566 sprintf(refreshTempStr_, "%lu", messages_[refreshReadPointer_].getTime()); 00567 xmlOut->addTextElementToParent("message_Time", refreshTempStr_, refreshParent_); 00568 // give clock also 00569 sprintf(refreshTempStr_, "%lu", messages_[refreshReadPointer_].getCount()); 00570 xmlOut->addTextElementToParent("message_Count", refreshTempStr_, refreshParent_); 00571 } 00572 00573 if(requestOutOfSync) // if request was out of sync, show message 00574 __SUP_COUT__ << requestOutOfSyncMsg; 00575 }