1 #include "otsdaq/CoreSupervisors/FESupervisor.h"
2 #include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
3 #include "otsdaq/FECore/FEVInterfacesManager.h"
4 #include "otsdaq/TablePlugins/ARTDAQTableBase/ARTDAQTableBase.h"
6 #include "artdaq/DAQdata/Globals.hh"
13 #include "artdaq-core/Utilities/ExceptionHandler.hh"
42 FESupervisor::FESupervisor(xdaq::ApplicationStub* stub)
45 , dp_socket_{dp_context_, zmq::socket_type::pub}
47 __SUP_COUT__ <<
"Constructing..." << __E__;
50 &FESupervisor::macroMakerSupervisorRequest,
51 "MacroMakerSupervisorRequest",
55 this, &FESupervisor::workLoopStatusRequest,
"WorkLoopStatusRequest", XDAQ_NS_URI);
58 &FESupervisor::frontEndCommunicationRequest,
62 std::string dataPublishingEndpoint;
65 dataPublishingEndpoint = getSupervisorProperty(
66 "data_publishing_endpoint");
68 catch(
const std::runtime_error& e)
70 __SUP_COUT__ <<
"Data publishing property 'data_publishing_endpoint' not set. "
71 "Defaulting to data publishing disabled."
76 dataPublishingEndpoint = __ENV__(
77 "DATA_PUBLISHING_ENDPOINT");
79 catch(
const std::runtime_error& e)
82 <<
"Data publishing environment variable 'DATA_PUBLISHING_ENDPOINT' "
83 "not set. Defaulting to data publishing disabled."
87 __SUP_COUT_INFO__ <<
"dataPublishingEndpoint = " << dataPublishingEndpoint << __E__;
89 if(dataPublishingEndpoint.size())
91 __SUP_COUT__ <<
"Initializing data publishing to endpoint '"
92 << dataPublishingEndpoint <<
"'..." << __E__;
94 initDataPublishing(dataPublishingEndpoint,
95 getSupervisorProperty(
"data_publishing_topic",
""));
100 CoreSupervisorBase::theStateMachineImplementation_.push_back(
102 CorePropertySupervisorBase::getContextTreeNode(),
103 CorePropertySupervisorBase::getSupervisorConfigurationPath()));
107 if(CorePropertySupervisorBase::allSupervisorInfo_.isMacroMakerMode())
109 __SUP_COUT_WARN__ <<
"Error caught constructing FE Interface Manager. In "
110 "Macro Maker mode, the input fhicl defines the "
111 "configuration tree, make sure you specified a valid "
118 catch(
const std::runtime_error& e)
120 __SUP_COUT_WARN__ << e.what() << __E__;
127 extractFEInterfacesManager();
129 __SUP_COUT__ <<
"Constructed." << __E__;
131 if(CorePropertySupervisorBase::allSupervisorInfo_.isMacroMakerMode())
133 __SUP_COUT_INFO__ <<
"Macro Maker mode, so configuring at startup!" << __E__;
134 if(!theFEInterfacesManager_)
136 __SUP_SS__ <<
"Missing FE Interface manager!" << __E__;
147 __SUP_COUT__ <<
"Configuring all state machine implementations..." << __E__;
148 __SUP_COUTV__(stateMachinesIterationDone_.size());
149 preStateMachineExecutionLoop();
150 __SUP_COUTV__(stateMachinesIterationDone_.size());
151 for(
unsigned int i = 0; i < theStateMachineImplementation_.size(); ++i)
153 __SUP_COUT__ <<
"Configuring state machine i " << i << __E__;
156 if(subIterationWorkStateMachineIndex_ != (
unsigned int)-1 &&
157 i != subIterationWorkStateMachineIndex_)
160 if(stateMachinesIterationDone_[i])
163 preStateMachineExecution(i);
164 theStateMachineImplementation_[i]->parentSupervisor_ =
167 theStateMachineImplementation_[i]->configure();
170 postStateMachineExecution(i);
172 postStateMachineExecutionLoop();
175 CorePropertySupervisorBase::indicateOtsAlive(0);
177 catch(
const std::runtime_error& e)
179 __SUP_SS__ <<
"Error was caught while configuring: " << e.what() << __E__;
180 __SUP_COUT_ERR__ <<
"\n" << ss.str();
186 <<
"Unknown error was caught while configuring. Please checked the logs."
192 catch(
const std::exception& e)
194 ss <<
"Exception message: " << e.what();
199 __SUP_COUT_ERR__ <<
"\n" << ss.str();
206 FESupervisor::~FESupervisor(
void)
208 __SUP_COUT__ <<
"Destroying..." << __E__;
222 artdaq::Globals::CleanUpGlobals();
224 __SUP_COUT__ <<
"Destructed." << __E__;
228 xoap::MessageReference FESupervisor::frontEndCommunicationRequest(
229 xoap::MessageReference message)
232 __SUP_COUT_INFO__ <<
"DIAG ms=" << StringMacros::nowEpochMs() <<
" tid=" << gettid()
233 <<
" frontEndCommunicationRequest received: "
234 << SOAPUtilities::translate(message) << __E__;
236 if(!theFEInterfacesManager_)
238 __SUP_SS__ <<
"No FE Interface Manager!" << __E__;
242 typeParameter.addParameter(
"type");
243 SOAPUtilities::receive(message, typeParameter);
245 std::string type = typeParameter.getValue(
"type");
255 rxParameters.addParameter(
"requester");
256 rxParameters.addParameter(
"targetInterfaceID");
262 rxParameters.addParameter(
"value");
263 SOAPUtilities::receive(message, rxParameters);
265 std::string requester = rxParameters.getValue(
"requester");
266 std::string targetInterfaceID = rxParameters.getValue(
"targetInterfaceID");
267 std::string value = rxParameters.getValue(
"value");
269 __SUP_COUTV__(requester);
270 __SUP_COUTV__(targetInterfaceID);
271 __SUP_COUTV__(value);
278 std::lock_guard<std::mutex> lock(
281 theFEInterfacesManager_
282 ->frontEndCommunicationReceiveBuffer_[targetInterfaceID][requester]
285 __SUP_COUT__ <<
"Number of target interface ID '" << targetInterfaceID
287 << theFEInterfacesManager_
288 ->frontEndCommunicationReceiveBuffer_[targetInterfaceID]
292 <<
"Number of source interface ID '" << requester <<
"' values received: "
293 << theFEInterfacesManager_
294 ->frontEndCommunicationReceiveBuffer_[targetInterfaceID][requester]
298 return SOAPUtilities::makeSOAPMessageReference(
"Received");
300 else if(type ==
"feMacro")
304 rxParameters.addParameter(
"feMacroName");
305 rxParameters.addParameter(
"inputArgs");
307 SOAPUtilities::receive(message, rxParameters);
309 std::string requester = rxParameters.getValue(
"requester");
310 std::string targetInterfaceID = rxParameters.getValue(
"targetInterfaceID");
311 std::string feMacroName = rxParameters.getValue(
"feMacroName");
312 std::string inputArgs = rxParameters.getValue(
"inputArgs");
314 __SUP_COUTV__(requester);
315 __SUP_COUTV__(targetInterfaceID);
316 __SUP_COUTV__(feMacroName);
317 __SUP_COUTV__(inputArgs);
319 std::string outputArgs;
322 __SUP_COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs()
323 <<
" runFEMacroByFE starting, macro='" << feMacroName
324 <<
"' target='" << targetInterfaceID <<
"'" << __E__;
326 requester, targetInterfaceID, feMacroName, inputArgs, outputArgs);
327 __SUP_COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs()
328 <<
" runFEMacroByFE done, macro='" << feMacroName <<
"'"
331 catch(std::runtime_error& e)
333 __SUP_SS__ <<
"In Supervisor with LID="
334 << getApplicationDescriptor()->getLocalId()
335 <<
" the FE Macro named '" << feMacroName <<
"' with target FE '"
336 << targetInterfaceID <<
"' failed. Here is the error:\n\n"
337 << e.what() << __E__;
342 __SUP_SS__ <<
"In Supervisor with LID="
343 << getApplicationDescriptor()->getLocalId()
344 <<
" the FE Macro named '" << feMacroName <<
"' with target FE '"
345 << targetInterfaceID <<
"' failed due to an unknown error."
351 catch(
const std::exception& e)
353 ss <<
"Exception message: " << e.what();
361 __SUP_COUTV__(outputArgs);
363 xoap::MessageReference replyMessage =
364 SOAPUtilities::makeSOAPMessageReference(
"feMacrosResponse");
366 txParameters.addParameter(
"requester", requester);
367 txParameters.addParameter(
"targetInterfaceID", targetInterfaceID);
368 txParameters.addParameter(
"feMacroName", feMacroName);
369 txParameters.addParameter(
"outputArgs", outputArgs);
370 SOAPUtilities::addParameters(replyMessage, txParameters);
372 __SUP_COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs()
373 <<
" Sending FE macro result: "
374 << SOAPUtilities::translate(replyMessage) << __E__;
378 else if(type ==
"feMacroMultiDimensionalStart" ||
379 type ==
"macroMultiDimensionalStart")
385 rxParameters.addParameter(
"macroString");
386 rxParameters.addParameter(
"macroName");
389 rxParameters.addParameter(
"feMacroName");
391 rxParameters.addParameter(
"enableSavingOutput");
392 rxParameters.addParameter(
"outputFilePath");
393 rxParameters.addParameter(
"outputFileRadix");
394 rxParameters.addParameter(
"inputArgs");
396 SOAPUtilities::receive(message, rxParameters);
398 std::string requester = rxParameters.getValue(
"requester");
399 std::string targetInterfaceID = rxParameters.getValue(
"targetInterfaceID");
400 std::string macroName, macroString;
403 macroName = rxParameters.getValue(
"macroName");
404 macroString = rxParameters.getValue(
"macroString");
405 __SUP_COUTV__(macroString);
408 macroName = rxParameters.getValue(
"feMacroName");
409 bool enableSavingOutput = rxParameters.getValue(
"enableSavingOutput") ==
"1";
410 std::string outputFilePath = rxParameters.getValue(
"outputFilePath");
411 std::string outputFileRadix = rxParameters.getValue(
"outputFileRadix");
412 std::string inputArgs = rxParameters.getValue(
"inputArgs");
414 __SUP_COUTV__(requester);
415 __SUP_COUTV__(targetInterfaceID);
416 __SUP_COUTV__(macroName);
417 __SUP_COUTV__(enableSavingOutput);
418 __SUP_COUTV__(outputFilePath);
419 __SUP_COUTV__(outputFileRadix);
420 __SUP_COUTV__(inputArgs);
435 catch(std::runtime_error& e)
437 __SUP_SS__ <<
"In Supervisor with LID="
438 << getApplicationDescriptor()->getLocalId()
439 <<
" the Macro named '" << macroName <<
"' with target FE '"
441 <<
"' failed to start multi-dimensional launch. "
442 <<
"Here is the error:\n\n"
443 << e.what() << __E__;
448 __SUP_SS__ <<
"In Supervisor with LID="
449 << getApplicationDescriptor()->getLocalId()
450 <<
" the Macro named '" << macroName <<
"' with target FE '"
452 <<
"' failed to start multi-dimensional launch "
453 <<
"due to an unknown error." << __E__;
458 catch(
const std::exception& e)
460 ss <<
"Exception message: " << e.what();
480 catch(std::runtime_error& e)
482 __SUP_SS__ <<
"In Supervisor with LID="
483 << getApplicationDescriptor()->getLocalId()
484 <<
" the FE Macro named '" << macroName <<
"' with target FE '"
486 <<
"' failed to start multi-dimensional launch. "
487 <<
"Here is the error:\n\n"
488 << e.what() << __E__;
493 __SUP_SS__ <<
"In Supervisor with LID="
494 << getApplicationDescriptor()->getLocalId()
495 <<
" the FE Macro named '" << macroName <<
"' with target FE '"
497 <<
"' failed to start multi-dimensional launch "
498 <<
"due to an unknown error." << __E__;
503 catch(
const std::exception& e)
505 ss <<
"Exception message: " << e.what();
514 xoap::MessageReference replyMessage =
515 SOAPUtilities::makeSOAPMessageReference(type +
"Done");
518 SOAPUtilities::addParameters(replyMessage, txParameters);
520 __SUP_COUT__ <<
"Sending FE macro result: "
521 << SOAPUtilities::translate(replyMessage) << __E__;
525 else if(type ==
"feMacroMultiDimensionalCheck" ||
526 type ==
"macroMultiDimensionalCheck")
530 rxParameters.addParameter(
"macroName");
532 rxParameters.addParameter(
"feMacroName");
533 rxParameters.addParameter(
"targetInterfaceID");
535 SOAPUtilities::receive(message, rxParameters);
537 std::string targetInterfaceID = rxParameters.getValue(
"targetInterfaceID");
538 std::string macroName;
540 macroName = rxParameters.getValue(
"macroName");
542 macroName = rxParameters.getValue(
"feMacroName");
553 catch(std::runtime_error& e)
555 __SUP_SS__ <<
"In Supervisor with LID="
556 << getApplicationDescriptor()->getLocalId()
557 <<
" the FE Macro named '" << macroName <<
"' with target FE '"
559 <<
"' failed to check multi-dimensional launch. "
560 <<
"Here is the error:\n\n"
561 << e.what() << __E__;
566 __SUP_SS__ <<
"In Supervisor with LID="
567 << getApplicationDescriptor()->getLocalId()
568 <<
" the FE Macro named '" << macroName <<
"' with target FE '"
570 <<
"' failed to check multi-dimensional launch "
571 <<
"due to an unknown error." << __E__;
576 catch(
const std::exception& e)
578 ss <<
"Exception message: " << e.what();
586 xoap::MessageReference replyMessage =
587 SOAPUtilities::makeSOAPMessageReference(type +
"Done");
589 txParameters.addParameter(
"Done", done ?
"1" :
"0");
590 SOAPUtilities::addParameters(replyMessage, txParameters);
598 __SUP_SS__ <<
"Unrecognized FE Communication type: " << type << __E__;
602 catch(
const std::runtime_error& e)
604 __SUP_SS__ <<
"Error encountered processing FE communication request: " << e.what()
606 __SUP_COUT_ERR__ << ss.str();
609 parameters.addParameter(
"Error", ss.str());
610 return SOAPUtilities::makeSOAPMessageReference(
611 supervisorClassNoNamespace_ +
"FailFECommunicationRequest", parameters);
615 __SUP_SS__ <<
"Unknown error encountered processing FE communication request."
621 catch(
const std::exception& e)
623 ss <<
"Exception message: " << e.what();
628 __SUP_COUT_ERR__ << ss.str();
631 parameters.addParameter(
"Error", ss.str());
632 return SOAPUtilities::makeSOAPMessageReference(
633 supervisorClassNoNamespace_ +
"FailFECommunicationRequest", parameters);
644 xoap::MessageReference message)
646 __SUP_COUT__ <<
"$$$$$$$$$$$$$$$$$" << __E__;
650 parameters.addParameter(
"Request");
652 __SUP_COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs() <<
" tid=" << gettid()
653 <<
" Received Macro Maker message: " << SOAPUtilities::translate(message)
656 SOAPUtilities::receive(message, parameters);
657 std::string
request = parameters.getValue(
"Request");
659 __SUP_COUT__ <<
"request: " <<
request << __E__;
675 if(theFEInterfacesManager_)
676 retParameters.addParameter(
679 std::to_string(getApplicationDescriptor()->getLocalId())));
681 retParameters.addParameter(
"FEList",
"");
684 if(theStateMachine_.getErrorMessage() !=
"")
685 retParameters.addParameter(
"frontEndError",
686 theStateMachine_.getErrorMessage());
688 return SOAPUtilities::makeSOAPMessageReference(
689 supervisorClassNoNamespace_ +
"Response", retParameters);
691 else if(
request ==
"UniversalWrite")
693 if(!theFEInterfacesManager_)
695 __SUP_SS__ <<
"No FE Interface Manager! Are you configured?" << __E__;
700 requestParameters.addParameter(
"InterfaceID");
701 requestParameters.addParameter(
"Address");
702 requestParameters.addParameter(
"Data");
703 SOAPUtilities::receive(message, requestParameters);
704 std::string interfaceID = requestParameters.getValue(
"InterfaceID");
705 std::string addressStr = requestParameters.getValue(
"Address");
706 std::string dataStr = requestParameters.getValue(
"Data");
708 __SUP_COUT__ <<
"Address: " << addressStr <<
" Data: " << dataStr
709 <<
" InterfaceID: " << interfaceID << __E__;
716 <<
"theFEInterfacesManager_->getInterfaceUniversalAddressSize(index) "
720 <<
"theFEInterfacesManager_->getInterfaceUniversalDataSize(index) "
730 __SUP_COUT__ <<
"Translating address: ";
732 std::string addressTmp;
735 char* address = &addressTmp[0];
737 if(addressStr.size() % 2)
738 addressStr =
"0" + addressStr;
740 for(; i < addressStr.size() &&
745 tmpHex[0] = addressStr[addressStr.size() - 1 - i - 1];
746 tmpHex[1] = addressStr[addressStr.size() - 1 - i];
747 sscanf(tmpHex,
"%hhX", (
unsigned char*)&address[i / 2]);
748 printf(
"%2.2X", (
unsigned char)address[i / 2]);
756 printf(
"%2.2X", (
unsigned char)address[i / 2]);
761 __SUP_COUT__ <<
"Translating data: ";
766 char* data = &dataTmp[0];
768 if(dataStr.size() % 2)
769 dataStr =
"0" + dataStr;
772 for(; i < dataStr.size() &&
777 tmpHex[0] = dataStr[dataStr.size() - 1 - i - 1];
778 tmpHex[1] = dataStr[dataStr.size() - 1 - i];
779 sscanf(tmpHex,
"%hhX", (
unsigned char*)&data[i / 2]);
780 printf(
"%2.2X", (
unsigned char)data[i / 2]);
788 printf(
"%2.2X", (
unsigned char)data[i / 2]);
800 theFEInterfacesManager_->
universalWrite(interfaceID, address, data);
805 return SOAPUtilities::makeSOAPMessageReference(
806 supervisorClassNoNamespace_ +
"DataWritten", retParameters);
808 else if(
request ==
"UniversalRead")
810 if(!theFEInterfacesManager_)
812 __SUP_SS__ <<
"No FE Interface Manager! Are you configured?" << __E__;
818 requestParameters.addParameter(
"InterfaceID");
819 requestParameters.addParameter(
"Address");
820 SOAPUtilities::receive(message, requestParameters);
821 std::string interfaceID = requestParameters.getValue(
"InterfaceID");
822 std::string addressStr = requestParameters.getValue(
"Address");
824 __SUP_COUT__ <<
"Address: " << addressStr <<
" InterfaceID: " << interfaceID
833 <<
"theFEInterfacesManager_->getInterfaceUniversalAddressSize(index) "
837 <<
"theFEInterfacesManager_->getInterfaceUniversalDataSize(index) "
844 __SUP_COUT__ <<
"Translating address: ";
846 std::string addressTmp;
849 char* address = &addressTmp[0];
851 if(addressStr.size() % 2)
852 addressStr =
"0" + addressStr;
855 for(; i < addressStr.size() &&
860 tmpHex[0] = addressStr[addressStr.size() - 1 - i - 1];
861 tmpHex[1] = addressStr[addressStr.size() - 1 - i];
862 sscanf(tmpHex,
"%hhX", (
unsigned char*)&address[i / 2]);
863 printf(
"%2.2X", (
unsigned char)address[i / 2]);
871 printf(
"%2.2X", (
unsigned char)address[i / 2]);
876 unsigned int dataSz =
879 dataStr.resize(dataSz);
880 char* data = &dataStr[0];
888 theFEInterfacesManager_->
universalRead(interfaceID, address, data);
890 catch(
const std::runtime_error& e)
894 __SUP_COUT_ERR__ <<
"Exception caught during read: " << e.what() << __E__;
895 retParameters.addParameter(
"dataResult",
"Time Out Error");
896 return SOAPUtilities::makeSOAPMessageReference(
897 supervisorClassNoNamespace_ +
"aa", retParameters);
903 __SUP_COUT_ERR__ <<
"Exception caught during read." << __E__;
904 retParameters.addParameter(
"dataResult",
"Time Out Error");
905 return SOAPUtilities::makeSOAPMessageReference(
906 supervisorClassNoNamespace_ +
"aa", retParameters);
912 std::string str8(data);
914 __SUP_COUT__ <<
"decResult[" << dataSz
915 <<
" bytes]: " << *((
unsigned long long*)(&str8[0]))
919 std::string hexResultStr;
920 hexResultStr.reserve(dataSz * 2 + 1);
921 char* hexResult = &hexResultStr[0];
925 for(
unsigned int i = 0; i < dataSz; ++i)
927 sprintf(&hexResult[i * 2],
"%2.2X", (
unsigned char)data[dataSz - 1 - i]);
930 __SUP_COUT__ <<
"hexResult[" << strlen(hexResult)
931 <<
" nibbles]: " << std::string(hexResult) << __E__;
933 retParameters.addParameter(
"dataResult", hexResult);
934 return SOAPUtilities::makeSOAPMessageReference(
935 supervisorClassNoNamespace_ +
"aa", retParameters);
937 else if(
request ==
"GetInterfaceMacros")
939 if(theFEInterfacesManager_)
941 __SUP_COUT__ <<
"Getting FE Macros from FE Interface Manager..." << __E__;
942 retParameters.addParameter(
945 CorePropertySupervisorBase::getSupervisorUID(),
946 std::to_string(CoreSupervisorBase::getSupervisorLID())));
950 __SUP_COUT__ <<
"No FE Macros because there is no FE Interface Manager..."
952 retParameters.addParameter(
"FEMacros",
"");
955 return SOAPUtilities::makeSOAPMessageReference(
956 supervisorClassNoNamespace_ +
"Response", retParameters);
958 else if(
request ==
"RunInterfaceMacro")
960 if(!theFEInterfacesManager_)
962 __SUP_SS__ <<
"Missing FE Interface Manager! Are you configured?"
969 requestParameters.addParameter(
"feMacroName");
970 requestParameters.addParameter(
"inputArgs");
971 requestParameters.addParameter(
"outputArgs");
972 requestParameters.addParameter(
"InterfaceID");
973 requestParameters.addParameter(
"userPermissions");
974 requestParameters.addParameter(
"AsyncSupported");
975 SOAPUtilities::receive(message, requestParameters);
976 std::string interfaceID = requestParameters.getValue(
"InterfaceID");
977 std::string feMacroName = requestParameters.getValue(
"feMacroName");
978 std::string inputArgs = requestParameters.getValue(
"inputArgs");
979 std::string outputArgs = requestParameters.getValue(
"outputArgs");
980 std::string userPermissions = requestParameters.getValue(
"userPermissions");
981 bool asyncSupported = requestParameters.getValue(
"AsyncSupported") ==
"1";
986 __COUTV__(userPermissions);
987 std::map<std::string, WebUsers::permissionLevel_t> userPermissionLevelsMap;
989 userPermissions, userPermissionLevelsMap);
999 auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
1000 if(FEMacroIt == fe->getMapOfFEMacroFunctions().end())
1002 __SUP_SS__ <<
"FE Macro '" << feMacroName <<
"' of interfaceID '"
1003 << interfaceID <<
"' was not found!" << __E__;
1008 __COUTV__(FEMacro.requiredUserPermissions_);
1009 std::map<std::string, WebUsers::permissionLevel_t>
1010 FERequiredUserPermissionsMap;
1012 FEMacro.requiredUserPermissions_, FERequiredUserPermissionsMap);
1016 userPermissionLevelsMap, FERequiredUserPermissionsMap))
1018 __SUP_SS__ <<
"Invalid user permission for FE Macro '" << feMacroName
1019 <<
"' of interfaceID '" << interfaceID <<
"'!\n\n"
1020 <<
"Must have access level of at least '"
1022 <<
".' Users permissions level is only '" << userPermissions
1030 auto task = std::make_shared<AsyncMacroTask>();
1032 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1033 task->taskID = ++asyncMacroTaskIDCounter_;
1034 if(asyncMacroTaskIDCounter_ == 0)
1035 task->taskID = ++asyncMacroTaskIDCounter_;
1036 task->interfaceID = interfaceID;
1037 task->startTime = time(0);
1038 asyncMacroTasks_.push_back(task);
1047 outputArgs]()
mutable {
1049 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1050 task->threadID = std::this_thread::get_id();
1056 ->clearFEMacroPercentDone(std::this_thread::get_id());
1064 __COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs()
1065 <<
" async FE Macro thread starting runFEMacro, taskID="
1066 << task->taskID << __E__;
1068 interfaceID, localFEMacro, inputArgs, outputArgs);
1069 __COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs()
1070 <<
" async FE Macro thread finished runFEMacro, taskID="
1071 << task->taskID << __E__;
1075 ->clearFEMacroPercentDone(std::this_thread::get_id());
1081 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1082 task->outputArgs = outputArgs;
1083 task->doneTime = time(0);
1087 catch(
const std::exception& e)
1092 ->clearFEMacroPercentDone(std::this_thread::get_id());
1097 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1099 "In Supervisor with LID=" +
1100 std::to_string(getApplicationDescriptor()->getLocalId()) +
1101 " the FE Macro named '" + interfaceID +
1102 "' failed. Here is the error:\n\n" + e.what();
1103 task->doneTime = time(0);
1111 ->clearFEMacroPercentDone(std::this_thread::get_id());
1116 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1118 "In Supervisor with LID=" +
1119 std::to_string(getApplicationDescriptor()->getLocalId()) +
1120 " the FE Macro named '" + interfaceID +
1121 "' failed due to an unknown error.";
1122 task->doneTime = time(0);
1127 __SUP_COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs()
1128 <<
" Launched async FE Macro '" << feMacroName
1129 <<
"' for interfaceID '" << interfaceID
1130 <<
"' with taskID=" << task->taskID << __E__;
1134 size_t sleepUs = 100;
1135 for(
int i = 0; i < 10; ++i)
1139 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1142 if(!task->error.empty())
1144 std::string errorCopy = task->error;
1145 for(
size_t j = 0; j < asyncMacroTasks_.size(); ++j)
1146 if(asyncMacroTasks_[j]->taskID == task->taskID)
1148 asyncMacroTasks_.erase(
1149 asyncMacroTasks_.begin() + j);
1152 __SUP_SS__ << errorCopy;
1156 <<
"DIAG ms=" << StringMacros::nowEpochMs()
1157 <<
" async macro finished within quick-wait,"
1158 <<
" returning synchronously, taskID=" << task->taskID
1160 retParameters.addParameter(
"outputArgs",
1162 for(
size_t j = 0; j < asyncMacroTasks_.size(); ++j)
1163 if(asyncMacroTasks_[j]->taskID == task->taskID)
1165 asyncMacroTasks_.erase(asyncMacroTasks_.begin() +
1169 return SOAPUtilities::makeSOAPMessageReference(
1170 supervisorClassNoNamespace_ +
"Response",
1180 __SUP_COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs()
1181 <<
" async macro NOT done within quick-wait,"
1182 <<
" returning NotDoneTaskID=" << task->taskID << __E__;
1183 retParameters.addParameter(
"NotDoneTaskID", std::to_string(task->taskID));
1184 return SOAPUtilities::makeSOAPMessageReference(
1185 supervisorClassNoNamespace_ +
"Response", retParameters);
1193 interfaceID, FEMacro, inputArgs, outputArgs);
1195 catch(std::runtime_error& e)
1197 __SUP_SS__ <<
"In Supervisor with LID="
1198 << getApplicationDescriptor()->getLocalId()
1199 <<
" the FE Macro named '" << feMacroName
1200 <<
"' with target FE '" << interfaceID
1201 <<
"' failed. Here is the error:\n\n"
1202 << e.what() << __E__;
1205 catch(std::exception& e)
1207 __SUP_SS__ <<
"In Supervisor with LID="
1208 << getApplicationDescriptor()->getLocalId()
1209 <<
" the FE Macro named '" << feMacroName
1210 <<
"' with target FE '" << interfaceID
1211 <<
"' failed. Here is the error:\n\n"
1212 << e.what() << __E__;
1217 __SUP_SS__ <<
"In Supervisor with LID="
1218 << getApplicationDescriptor()->getLocalId()
1219 <<
" the FE Macro named '" << feMacroName
1220 <<
"' with target FE '" << interfaceID
1221 <<
"' failed due to an unknown error." << __E__;
1226 catch(
const std::exception& e)
1228 ss <<
"Exception message: " << e.what();
1236 retParameters.addParameter(
"outputArgs", outputArgs);
1237 return SOAPUtilities::makeSOAPMessageReference(
1238 supervisorClassNoNamespace_ +
"Response", retParameters);
1241 else if(
request ==
"RunMacroMakerMacro")
1243 if(!theFEInterfacesManager_)
1245 __SUP_SS__ <<
"Missing FE Interface Manager! Are you configured?"
1252 requestParameters.addParameter(
"macroName");
1253 requestParameters.addParameter(
"macroString");
1254 requestParameters.addParameter(
"inputArgs");
1255 requestParameters.addParameter(
"outputArgs");
1256 requestParameters.addParameter(
"InterfaceID");
1257 requestParameters.addParameter(
"AsyncSupported");
1258 SOAPUtilities::receive(message, requestParameters);
1259 std::string interfaceID = requestParameters.getValue(
"InterfaceID");
1260 std::string macroName = requestParameters.getValue(
"macroName");
1261 std::string macroString = requestParameters.getValue(
"macroString");
1262 std::string inputArgs = requestParameters.getValue(
"inputArgs");
1263 std::string outputArgs = requestParameters.getValue(
"outputArgs");
1264 bool asyncSupported = requestParameters.getValue(
"AsyncSupported") ==
"1";
1269 auto task = std::make_shared<AsyncMacroTask>();
1271 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1272 task->taskID = ++asyncMacroTaskIDCounter_;
1273 if(asyncMacroTaskIDCounter_ == 0)
1274 task->taskID = ++asyncMacroTaskIDCounter_;
1275 task->interfaceID = interfaceID;
1276 task->startTime = time(0);
1277 asyncMacroTasks_.push_back(task);
1286 outputArgs]()
mutable {
1288 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1289 task->threadID = std::this_thread::get_id();
1294 ->clearFEMacroPercentDone(std::this_thread::get_id());
1303 interfaceID, macroString, inputArgs, outputArgs);
1307 ->clearFEMacroPercentDone(std::this_thread::get_id());
1313 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1314 task->outputArgs = outputArgs;
1315 task->doneTime = time(0);
1319 catch(
const std::exception& e)
1324 ->clearFEMacroPercentDone(std::this_thread::get_id());
1329 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1331 "In Supervisor with LID=" +
1332 std::to_string(getApplicationDescriptor()->getLocalId()) +
1333 " the MacroMaker Macro named '" + macroName +
1334 "' with target FE '" + interfaceID +
1335 "' failed. Here is the error:\n\n" + e.what();
1336 task->doneTime = time(0);
1344 ->clearFEMacroPercentDone(std::this_thread::get_id());
1349 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1351 "In Supervisor with LID=" +
1352 std::to_string(getApplicationDescriptor()->getLocalId()) +
1353 " the MacroMaker Macro named '" + macroName +
1354 "' with target FE '" + interfaceID +
1355 "' failed due to an unknown error.";
1356 task->doneTime = time(0);
1361 __SUP_COUT__ <<
"Launched async MacroMaker Macro '" << macroName
1362 <<
"' for interfaceID '" << interfaceID
1363 <<
"' with taskID=" << task->taskID << __E__;
1367 size_t sleepUs = 100;
1368 for(
int i = 0; i < 10; ++i)
1372 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1375 if(!task->error.empty())
1377 std::string errorCopy = task->error;
1378 for(
size_t j = 0; j < asyncMacroTasks_.size(); ++j)
1379 if(asyncMacroTasks_[j]->taskID == task->taskID)
1381 asyncMacroTasks_.erase(
1382 asyncMacroTasks_.begin() + j);
1385 __SUP_SS__ << errorCopy;
1389 <<
"DIAG ms=" << StringMacros::nowEpochMs()
1390 <<
" async macro finished within quick-wait,"
1391 <<
" returning synchronously, taskID=" << task->taskID
1393 retParameters.addParameter(
"outputArgs",
1395 for(
size_t j = 0; j < asyncMacroTasks_.size(); ++j)
1396 if(asyncMacroTasks_[j]->taskID == task->taskID)
1398 asyncMacroTasks_.erase(asyncMacroTasks_.begin() +
1402 return SOAPUtilities::makeSOAPMessageReference(
1403 supervisorClassNoNamespace_ +
"Response",
1413 __SUP_COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs()
1414 <<
" async macro NOT done within quick-wait,"
1415 <<
" returning NotDoneTaskID=" << task->taskID << __E__;
1416 retParameters.addParameter(
"NotDoneTaskID", std::to_string(task->taskID));
1417 return SOAPUtilities::makeSOAPMessageReference(
1418 supervisorClassNoNamespace_ +
"Response", retParameters);
1426 interfaceID, macroString, inputArgs, outputArgs);
1428 catch(std::runtime_error& e)
1430 __SUP_SS__ <<
"In Supervisor with LID="
1431 << getApplicationDescriptor()->getLocalId()
1432 <<
" the MacroMaker Macro named '" << macroName
1433 <<
"' with target FE '" << interfaceID
1434 <<
"' failed. Here is the error:\n\n"
1435 << e.what() << __E__;
1440 __SUP_SS__ <<
"In Supervisor with LID="
1441 << getApplicationDescriptor()->getLocalId()
1442 <<
" the MacroMaker Macro named '" << macroName
1443 <<
"' with target FE '" << interfaceID
1444 <<
"' failed due to an unknown error." << __E__;
1449 catch(
const std::exception& e)
1451 ss <<
"Exception message: " << e.what();
1459 retParameters.addParameter(
"outputArgs", outputArgs);
1460 return SOAPUtilities::makeSOAPMessageReference(
1461 supervisorClassNoNamespace_ +
"Response", retParameters);
1464 else if(
request ==
"CheckMacro")
1467 requestParameters.addParameter(
"TaskID");
1468 SOAPUtilities::receive(message, requestParameters);
1469 uint64_t taskID = std::stoull(requestParameters.getValue(
"TaskID"));
1471 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1474 time_t now = time(0);
1475 for(
size_t i = 0; i < asyncMacroTasks_.size();)
1477 auto& t = asyncMacroTasks_[i];
1478 if(t->done && t->doneTime > 0 && (now - t->doneTime) > 5 * 60)
1479 asyncMacroTasks_.erase(asyncMacroTasks_.begin() + i);
1485 std::shared_ptr<AsyncMacroTask> foundTask;
1486 for(
auto& t : asyncMacroTasks_)
1488 if(t->taskID == taskID)
1497 __SUP_SS__ <<
"Async macro task with ID=" << taskID
1498 <<
" was not found. Perhaps it completed more than 5 "
1506 if(!foundTask->error.empty())
1508 std::string errorCopy = foundTask->error;
1510 for(
size_t i = 0; i < asyncMacroTasks_.size(); ++i)
1512 if(asyncMacroTasks_[i]->taskID == taskID)
1514 asyncMacroTasks_.erase(asyncMacroTasks_.begin() + i);
1518 __SUP_SS__ << errorCopy;
1522 __SUP_COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs()
1523 <<
" CheckMacro found task DONE (doneTime="
1524 << foundTask->doneTime <<
"), taskID=" << taskID << __E__;
1525 retParameters.addParameter(
"outputArgs", foundTask->outputArgs);
1528 for(
size_t i = 0; i < asyncMacroTasks_.size(); ++i)
1530 if(asyncMacroTasks_[i]->taskID == taskID)
1532 asyncMacroTasks_.erase(asyncMacroTasks_.begin() + i);
1537 return SOAPUtilities::makeSOAPMessageReference(
1538 supervisorClassNoNamespace_ +
"Response", retParameters);
1543 if(theFEInterfacesManager_ && foundTask->threadID != std::thread::id())
1547 int progress = theFEInterfacesManager_
1549 ->getFEMacroPercentDone(foundTask->threadID);
1551 retParameters.addParameter(
"Progress",
1552 std::to_string(progress));
1558 __SUP_COUT__ <<
"DIAG ms=" << StringMacros::nowEpochMs()
1559 <<
" CheckMacro found task still RUNNING, taskID=" << taskID
1561 retParameters.addParameter(
"NotDoneTaskID", std::to_string(taskID));
1562 return SOAPUtilities::makeSOAPMessageReference(
1563 supervisorClassNoNamespace_ +
"Response", retParameters);
1568 __SUP_SS__ <<
"Unrecognized request received! '" <<
request <<
"'" << __E__;
1572 catch(
const std::runtime_error& e)
1574 __SUP_SS__ <<
"Error occurred handling request: " << e.what() << __E__;
1575 __SUP_COUT_ERR__ << ss.str();
1576 retParameters.addParameter(
"Error", ss.str());
1580 __SUP_SS__ <<
"Error occurred handling request." << __E__;
1585 catch(
const std::exception& e)
1587 ss <<
"Exception message: " << e.what();
1592 __SUP_COUT_ERR__ << ss.str();
1593 retParameters.addParameter(
"Error", ss.str());
1596 return SOAPUtilities::makeSOAPMessageReference(
1597 supervisorClassNoNamespace_ +
"FailRequest", retParameters);
1602 xoap::MessageReference FESupervisor::workLoopStatusRequest(
1603 xoap::MessageReference )
1605 if(!theFEInterfacesManager_)
1607 __SUP_SS__ <<
"Invalid request for front-end workloop status from Supervisor "
1608 "without a FEVInterfacesManager."
1613 return SOAPUtilities::makeSOAPMessageReference(
1615 ? CoreSupervisorBase::WORK_LOOP_DONE
1616 : CoreSupervisorBase::WORK_LOOP_WORKING));
1629 theFEInterfacesManager_ = 0;
1631 for(
unsigned int i = 0; i < theStateMachineImplementation_.size(); ++i)
1635 theFEInterfacesManager_ =
1637 if(!theFEInterfacesManager_)
1640 __SUP_SS__ <<
"Dynamic cast failure!" << __E__;
1643 __SUP_COUT__ <<
"State Machine " << i <<
" WAS of type FEVInterfacesManager"
1650 __SUP_COUT__ <<
"State Machine " << i
1651 <<
" was NOT of type FEVInterfacesManager" << __E__;
1655 __SUP_COUT__ <<
"theFEInterfacesManager pointer = " << theFEInterfacesManager_
1658 return theFEInterfacesManager_;
1662 void FESupervisor::transitionConfiguring(toolbox::Event::Reference )
1664 __SUP_COUT__ <<
"transitionConfiguring" << __E__;
1665 CoreSupervisorBase::configureInit();
1670 __COUTV__(CorePropertySupervisorBase::getSupervisorConfigurationPath());
1673 CorePropertySupervisorBase::getSupervisorTableNode();
1675 std::string metric_string =
"";
1676 bool metricStringSetup =
true;
1679 std::ostringstream oss;
1680 std::string tabString =
"";
1681 std::string commentsString =
"";
1683 oss, tabString, commentsString,
"" , feSupervisorNode);
1684 metric_string = oss.str();
1688 metricStringSetup =
false;
1694 __SUP_COUT__ <<
"Metric manager is not instantiated! Attempting to fix."
1696 metricMan = std::make_unique<artdaq::MetricManager>();
1698 std::string metricNamePreamble =
1699 feSupervisorNode.
getNode(
"/SlowControlsMetricManagerChannelNamePreamble")
1701 __SUP_COUTV__(metricNamePreamble);
1704 fhicl::ParameterSet metric_pset = fhicl::ParameterSet::make(metric_string);
1706 __SUP_COUTV__(metricNamePreamble);
1709 metricMan->initialize(metric_pset.get<fhicl::ParameterSet>(
"metrics"),
1710 metricNamePreamble);
1714 if(metricStringSetup)
1717 __SUP_COUT__ <<
"Ignore metric manager initialize error because metric "
1718 "string is not setup."
1721 __SUP_COUT__ <<
"transitionConfiguring metric manager(" << metricMan
1722 <<
") initialized = " << metricMan->Initialized() << __E__;
1724 catch(
const std::runtime_error& e)
1726 __SS__ <<
"Error loading metrics in FESupervisor::transitionConfiguring(): "
1727 << e.what() << __E__;
1728 __SUP_COUT_ERR__ << ss.str();
1732 theStateMachine_.setErrorMessage(ss.str());
1733 throw toolbox::fsm::exception::Exception(
1734 "Transition Error" ,
1736 "FESupervisor::transitionConfiguring" ,
1743 __SS__ <<
"Error loading metrics in FESupervisor::transitionConfiguring()"
1749 catch(
const std::exception& e)
1751 ss <<
"Exception message: " << e.what();
1756 __SUP_COUT_ERR__ << ss.str();
1760 theStateMachine_.setErrorMessage(ss.str());
1761 throw toolbox::fsm::exception::Exception(
1762 "Transition Error" ,
1764 "FESupervisor::transitionConfiguring" ,
1770 CoreSupervisorBase::transitionConfiguringFSMs();
1772 __SUP_COUT__ <<
"transitionConfiguring done." << __E__;
1778 __SUP_COUT__ <<
"transitionHalting" << __E__;
1779 TLOG_DEBUG(7) <<
"transitionHalting";
1783 const int timeoutSeconds = 30;
1784 const time_t deadline = time(0) + timeoutSeconds;
1785 bool hasOutstanding =
true;
1786 while(hasOutstanding && time(0) < deadline)
1789 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1790 hasOutstanding =
false;
1791 for(
const auto& t : asyncMacroTasks_)
1795 hasOutstanding =
true;
1802 __SUP_COUT__ <<
"Waiting for outstanding async macro tasks to complete "
1809 __SUP_COUT_WARN__ <<
"Timed out waiting for async macro tasks; "
1810 "proceeding with halt."
1812 std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1813 asyncMacroTasks_.clear();
1821 if(metricMan && metricMan->Initialized())
1823 TLOG_DEBUG(7) <<
"Metric manager(" << metricMan <<
") shutting down..."
1827 TLOG_DEBUG(7) <<
"Metric manager shutdown." << __E__;
1830 __SUP_COUT__ <<
"Metric manager(" << metricMan <<
") already shutdown."
1833 metricMan.reset(
nullptr);
1837 __SS__ <<
"Error shutting down metrics in FESupervisor::transitionHalting()"
1843 catch(
const std::exception& e)
1845 ss <<
"Exception message: " << e.what();
1850 __SUP_COUT_ERR__ << ss.str();
1854 theStateMachine_.setErrorMessage(ss.str());
1855 throw toolbox::fsm::exception::Exception(
1856 "Transition Error" ,
1858 "FESupervisor::transitionHalting" ,
1864 __SUP_COUT__ <<
"transitionHalting done." << __E__;
1869 const std::string& topic)
1871 if(dp_isInitialized_)
1878 dp_endpoint_ = endpoint;
1884 dp_socket_.bind(dp_endpoint_);
1886 catch(
const zmq::error_t& e)
1888 __SUP_SS__ <<
"initDataPublishing() - bind to zmq '" + dp_endpoint_ +
1889 "' failed: " + e.what()
1894 dp_isInitialized_ =
true;
1900 if(dp_isInitialized_)
1904 dp_socket_.set(zmq::sockopt::linger, 0);
1907 catch(
const zmq::error_t&)
1913 if(alsoCloseContext)
1914 dp_context_.close();
1916 catch(
const zmq::error_t&)
1920 dp_isInitialized_ =
false;
1934 if(!dp_isInitialized_)
1936 __SUP_SS__ <<
"publishData() called before zmq init()" << __E__;
1942 auto rc_topic = dp_socket_.send(zmq::buffer(dp_topic_), zmq::send_flags::sndmore);
1945 __SUP_SS__ <<
"publishData() - failed to send zmq topic" << __E__;
1951 if(dataPtr ==
nullptr && dataSize > 0)
1953 __SUP_SS__ <<
"FESupervisor::publishData() - dataPtr is nullptr but dataSize is "
1954 << dataSize << __E__;
1958 dp_socket_.send(zmq::buffer(dataPtr, dataSize), zmq::send_flags::none);
1961 __SUP_SS__ <<
"publishData() - failed to send zmq payload" << __E__;
static void insertMetricsBlock(std::ostream &out, std::string &tabStr, std::string &commentStr, const std::string &parentPath, ConfigurationTree daqNode)
insertMetricsBlock
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
T getValueWithDefault(const T &defaultValue) const
static void extractPermissionsMapFromString(const std::string &permissionsString, std::map< std::string, WebUsers::permissionLevel_t > &permissionsMap)
static bool doPermissionsGrantAccess(std::map< std::string, WebUsers::permissionLevel_t > &permissionLevelsMap, std::map< std::string, WebUsers::permissionLevel_t > &permissionThresholdsMap)
virtual void transitionHalting(toolbox::Event::Reference event)
virtual void request(const std::string &requestType, cgicc::Cgicc &cgiIn, HttpXmlDocument &xmlOut, const WebUsers::RequestUserInfo &userInfo)
void publishData(const char *dataPtr, size_t dataSize)
virtual void transitionHalting(toolbox::Event::Reference event) override
void initDataPublishing(const std::string &endpoint, const std::string &topic="test")
void closeDataPublishing(bool alsoCloseContext=true)
xoap::MessageReference macroMakerSupervisorRequest(xoap::MessageReference message)
const FEVInterface & getFEInterface(const std::string &interfaceID) const
getFEInterface
std::string getFEMacrosString(const std::string &supervisorName, const std::string &supervisorLid)
used by MacroMaker
FEVInterface * getFEInterfaceP(const std::string &interfaceID)
getFEInterfaceP
void runFEMacro(const std::string &interfaceID, const FEVInterface::frontEndMacroStruct_t &feMacro, const std::string &inputArgs, std::string &outputArgs)
used by MacroMaker and FE calling indirectly
unsigned int getInterfaceUniversalAddressSize(const std::string &interfaceID)
used by MacroMaker
void startFEMacroMultiDimensional(const std::string &requester, const std::string &interfaceID, const std::string &feMacroName, const bool enableSavingOutput, const std::string &outputFilePath, const std::string &outputFileRadix, const std::string &inputArgs)
used by iterator calling (i.e. FESupervisor)
void universalWrite(const std::string &interfaceID, char *address, char *writeValue)
used by MacroMaker
bool allFEWorkloopsAreDone(void)
used by Iterator, e.g.
void runFEMacroByFE(const std::string &callingInterfaceID, const std::string &interfaceID, const std::string &feMacroName, const std::string &inputArgs, std::string &outputArgs)
used by FE calling (i.e. FESupervisor)
unsigned int getInterfaceUniversalDataSize(const std::string &interfaceID)
used by MacroMaker
void universalRead(const std::string &interfaceID, char *address, char *returnValue)
used by MacroMaker
void startMacroMultiDimensional(const std::string &requester, const std::string &interfaceID, const std::string ¯oName, const std::string ¯oString, const bool enableSavingOutput, const std::string &outputFilePath, const std::string &outputFileRadix, const std::string &inputArgs)
used by iterator calling (i.e. FESupervisor)
bool checkMacroMultiDimensional(const std::string &interfaceID, const std::string ¯oName)
used by iterator calling (i.e. FESupervisor)
std::mutex frontEndCommunicationReceiveMutex_
FE communication helpers.
void runMacro(const std::string &interfaceID, const std::string ¯oObjectString, const std::string &inputArgs, std::string &outputArgs)
used by MacroMaker
std::string getFEListString(const std::string &supervisorLid)
used by MacroMaker
defines used also by OtsConfigurationWizardSupervisor
< members fully define a front-end macro function
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")