Allow to log statistics samples as a event operation
[anna.git] / example / diameter / launcher / Launcher.cpp
index 120fabc..116c325 100644 (file)
@@ -11,6 +11,7 @@
 #include <iostream>     // std::cout
 #include <math.h> // ceil
 #include <climits>
+#include <unistd.h> // chdir
 
 // Project
 #include <anna/timex/Engine.hpp>
@@ -33,8 +34,8 @@
 #include <TestCase.hpp>
 
 
-#define SIGUSR2_TASKS_INPUT_FILENAME "./sigusr2.in"
-#define SIGUSR2_TASKS_OUTPUT_FILENAME "./sigusr2.out"
+#define SIGUSR2_TASKS_INPUT_FILENAME "sigusr2.in"
+#define SIGUSR2_TASKS_OUTPUT_FILENAME "sigusr2.out"
 
 
 const char *ServicesDTD = "\
@@ -59,40 +60,54 @@ const char *ServicesDTD = "\
 -->\n\
 \n\
 <!ELEMENT node EMPTY>\n\
-<!ATTLIST node originHost CDATA #REQUIRED applicationId CDATA #REQUIRED originRealm CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>\n\
+<!ATTLIST node originHost CDATA #REQUIRED applicationId CDATA #REQUIRED originRealm CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED cea CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>\n\
 <!--\n\
    Node record\n\
 \n\
    originHost:                              Node identifier as diameter application host name.\n\
    applicationId:                           The Application-Id provided must exists as a registered 'stack id'.\n\
    originRealm:                             Origin-Realm (domain-name internally used by default).\n\
+\n\
+\n\
+   - Diameter clients:\n\
+\n\
+   entity:                                  Target diameter entity (comma-separated '<address>:<port>' format).\n\
+                                            For example: 10.20.30.40:3868,10.20.30.41:3868. If missing, no entity will be enabled.\n\
+   entityServerSessions:                    Diameter entity server sessions (0: diameter entity disabled). Default value of 1.\n\
    cer:                                     User defined CER path file to be encoded to establish diameter connections.\n\
                                             If missing, will be harcoded.\n\
    dwr:                                     User defined DWR path file to be encoded for diameter protocol keep alive.\n\
                                             If missing, will be harcoded.\n\
-   allowedInactivityTime:                   Milliseconds for the maximum allowed inactivity time on server sessions born over the\n\
-                                            local server before being reset. If missing, default value of 90000 will be assigned.\n\
    tcpConnectDelay:                         Milliseconds to wait TCP connect to any server. If missing, default value of 200 will\n\
                                             be assigned\n\
-   answersTimeout:                          Milliseconds to wait pending application answers from diameter peers. If missing,\n\
-                                            default value of 10000 will be assigned.\n\
    ceaTimeout:                              Milliseconds to wait CEA from diameter server. If missing, default value of 'answersTimeout'\n\
                                             will be assigned.\n\
    watchdogPeriod:                          Milliseconds for watchdog timer (Tw) for diameter keep-alive procedure. If missing, default\n\
                                             value of 30000 will be assigned.\n\
-   entity:                                  Target diameter entity (comma-separated '<address>:<port>' format).\n\
-                                            For example: 10.20.30.40:3868,10.20.30.41:3868. If missing, no entity will be enabled.\n\
-   entityServerSessions:                    Diameter entity server sessions (0: diameter entity disabled). Default value of 1.\n\
-   diameterServer:                          Diameter own server address in '<address>:<port>' format. For example: 10.20.30.40:3868.\n\
-                                            If missing, no local server will be enabled.\n\
-   diameterServerSessions:                  Diameter own server available connections (0: diameter server disabled). Default value of 1.\n\
-                                            Negative value implies no limit accepting incoming connections.\n\
    balance:                                 Balance over entity servers instead of doing standard behaviour (first primary, secondary\n\
                                             if fails, etc.). Default value 'no'.\n\
    sessionBasedModelsClientSocketSelection: By default, round-robin will be applied for IEC model (SMS/MMS), and Session-Id Low Part\n\
                                             will be analyzed for ECUR/SCUR model (data, voice and content). You could change ECUR/SCUR\n\
                                             analysis behaviour providing 'SessionIdHighPart', 'SessionIdOptionalPart' (atoi applied;\n\
                                             usually subscriber id data, i.e. MSISDN or IMSI) and 'RoundRobin' (also 'SessionIdLowPart').\n\
+\n\
+\n\
+   - Diameter servers:\n\
+\n\
+   diameterServer:                          Diameter own server address in '<address>:<port>' format. For example: 10.20.30.40:3868.\n\
+                                            If missing, no local server will be enabled.\n\
+   diameterServerSessions:                  Diameter own server available connections (0: diameter server disabled). Default value of 1.\n\
+                                            Negative value implies no limit accepting incoming connections.\n\
+   cea:                                     User defined CEA path file to be encoded to answer client CERs.\n\
+                                            If missing, will be harcoded.\n\
+   allowedInactivityTime:                   Milliseconds for the maximum allowed inactivity time on server sessions born over the\n\
+                                            local server before being reset. If missing, default value of 90000 will be assigned.\n\
+\n\
+\n\
+   - General:\n\
+\n\
+   answersTimeout:                          Milliseconds to wait pending application answers from diameter peers. If missing,\n\
+                                            default value of 10000 will be assigned.\n\
    retries:                                 Expired responses will cause a number of request retransmissions. Disabled by default (0 retries).\n\
    log:                                     Process log file (operations result, traffic log, etc.). By default '<originHost>.launcher.log'.\n\
                                             Empty string or \"null\" name, to disable. Warning: there is no rotation for log files\n\
@@ -100,10 +115,10 @@ const char *ServicesDTD = "\
    splitLog:                                Splits log file (appends to log filename, extensions with the type of event: see help on\n\
                                             startup information-level traces). No log files for code/decode and load operations are created.\n\
                                             Default value 'no'.\n\
-   detailedLog:                             Insert detailed information at log files. Should be disabled on automatic tests. Useful on\n\
-                                            'balance' mode to know messages flow along the sockets. Default value 'no'.\n\
+   detailedLog:                             Insert detailed information at log files (timestamps, communication resources, etc.). Useful\n\
+                                            to analyze the messages flow along the sockets (specially on 'balance' mode). Default 'no'.\n\
    dumpLog:                                 Write to disk every incoming/outcoming message named as:\n\
-                                               '<originHost>.<hop by hop>.<end to end>.<message code>.<request|answer>.<type of event>.xml'\n\
+                                               '<unix ms timestamp>.<originHost>.<hop by hop>.<end to end>.<message code>.<request|answer>.<type of event>.xml'\n\
                                             Default value 'no'.\n\
    burstLog:                                Burst operations log file. By default '<originHost>.launcher.burst'. Empty string or \"null\" name, to disable.\n\
                                             Warning: there is no rotation for log files (use logrotate or whatever). Output: dot (.) for each\n\
@@ -129,6 +144,13 @@ Launcher::Launcher() : anna::comm::Application("launcher", "DiameterLauncher", "
 }
 
 
+std::string Launcher::getSignalUSR2InputFile() const throw() {
+  return (a_initialWorkingDirectory + "/" + SIGUSR2_TASKS_INPUT_FILENAME);
+}
+
+std::string Launcher::getSignalUSR2OutputFile() const throw() {
+  return (a_initialWorkingDirectory + "/" + SIGUSR2_TASKS_OUTPUT_FILENAME);
+}
 
 
 void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOperation) throw(anna::RuntimeException) {
@@ -140,7 +162,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
   const anna::xml::Attribute *id, *dictionary;
 
   // <!ATTLIST node originHost CDATA #REQUIRED applicationId CDATA #REQUIRED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>
-  const anna::xml::Attribute *originHost, *appId, *originRealm, *cer, *dwr, *allowedInactivityTime, *tcpConnectDelay,
+  const anna::xml::Attribute *originHost, *appId, *originRealm, *cer, *dwr, *cea, *allowedInactivityTime, *tcpConnectDelay,
   *answersTimeout, *ceaTimeout, *watchdogPeriod, *entity, *entityServerSessions,
   *diameterServer, *diameterServerSessions, *balance, *sessionBasedModelsClientSocketSelection,
   *retries, *log, *splitLog, *detailedLog, *dumpLog, *burstLog;
@@ -203,7 +225,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
       const anna::xml::Attribute *vm_attr = (*it)->getAttribute("validationMode", false /* no exception */);
       const anna::xml::Attribute *vd_attr = (*it)->getAttribute("validationDepth", false /* no exception */);
       const anna::xml::Attribute *fm_attr = (*it)->getAttribute("fixMode", false /* no exception */);
-      const anna::xml::Attribute *if_attr = (*it)->getAttribute("ignoreFlags", false /* no exception */);
+      const anna::xml::Attribute *if_attr = (*it)->getAttribute("ignoreFlagsOnValidation", false /* no exception */);
 
       std::string vm_value = vm_attr ? vm_attr->getValue() : "AfterDecoding";
       std::string vd_value = vd_attr ? vd_attr->getValue() : "FirstError";
@@ -256,6 +278,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
       originRealm = (*it)->getAttribute("originRealm", false /* no exception */);
       cer = (*it)->getAttribute("cer", false /* no exception */);
       dwr = (*it)->getAttribute("dwr", false /* no exception */);
+      cea = (*it)->getAttribute("cea", false /* no exception */);
       allowedInactivityTime = (*it)->getAttribute("allowedInactivityTime", false /* no exception */);
       tcpConnectDelay = (*it)->getAttribute("tcpConnectDelay", false /* no exception */);
       answersTimeout = (*it)->getAttribute("answersTimeout", false /* no exception */);
@@ -322,6 +345,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
       // Assignments:
       commEngine->setMaxConnectionDelay(tcpConnectDelayMs);
       commEngine->setWatchdogPeriod(watchdogPeriodMs);
+      a_workingNode->setRequestRetransmissions(retransmissions);
 
       // Realm information:
       commEngine->setOriginHost(originHost->getValue());
@@ -342,7 +366,6 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
 
           // Register one entity for this engine:
           a_workingNode->createEntity(entity->getValue(), ceaTimeoutMs, answersTimeoutMs);
-          a_workingNode->setRequestRetransmissions(retransmissions);
           a_workingNode->getEntity()->setSessionBasedModelsType(sessionBasedModelsType);
           a_workingNode->getEntity()->setBalance(balance ? (balance->getValue() == "yes") : false); // for sendings
           if (eventOperation) a_workingNode->getEntity()->bind();
@@ -351,8 +374,11 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
 
       // Diameter Server:
       if(diameterServer) {
+        // Server CEA
+        std::string ceaPathfile = cea ? cea->getValue() : "";
+
         int sessions = diameterServerSessions ? diameterServerSessions->getIntegerValue() : 1;
-        a_workingNode->startDiameterServer(diameterServer->getValue(), sessions, allowedInactivityTimeMs);
+        a_workingNode->startDiameterServer(diameterServer->getValue(), sessions, allowedInactivityTimeMs, answersTimeoutMs, ceaPathfile);
       }
 
       // Logs:
@@ -566,6 +592,13 @@ throw(anna::RuntimeException) {
 
   // Start time:
   a_start_time.setNow();
+
+  // Initial working directory:
+  char cwd[1024];
+  if (getcwd(cwd, sizeof(cwd)) == NULL)
+    throw anna::RuntimeException("Cannot retrieve initial working directory !!", ANNA_FILE_LOCATION);
+  a_initialWorkingDirectory = cwd;
+
   // Statistics:
   anna::statistics::Engine::instantiate().enable();
 
@@ -712,34 +745,11 @@ throw(anna::RuntimeException) {
     a_timeEngine->activate(a_counterRecorderClock); // start clock
   }
 
-  // Log statistics concepts
-  if(cl.exists("logStatisticSamples")) {
-    std::string list = cl.getValue("logStatisticSamples");
-    anna::statistics::Engine &statEngine = anna::statistics::Engine::instantiate();
-
-    if(list == "all") {
-      if(statEngine.enableSampleLog(/* -1: all concepts */))
-        LOGDEBUG(anna::Logger::debug("Sample log activation for all statistic concepts", ANNA_FILE_LOCATION));
-    } else {
-      anna::Tokenizer lst;
-      lst.apply(cl.getValue("logStatisticSamples"), ",");
-
-      if(lst.size() >= 1) {
-        anna::Tokenizer::const_iterator tok_min(lst.begin());
-        anna::Tokenizer::const_iterator tok_max(lst.end());
-        anna::Tokenizer::const_iterator tok_iter;
-        int conceptId;
-
-        for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
-          conceptId = atoi(anna::Tokenizer::data(tok_iter));
-
-          if(statEngine.enableSampleLog(conceptId))
-            LOGDEBUG(anna::Logger::debug(anna::functions::asString("Sample log activation for statistic concept id = %d", conceptId), ANNA_FILE_LOCATION));
-        }
-      }
-    }
-  }
-
+  /////////////////////////////
+  // Log statistics concepts //
+  /////////////////////////////
+  if(cl.exists("logStatisticSamples"))
+    logStatisticsSamples(cl.getValue("logStatisticSamples"));
 
   // Start client connections //////////////////////////////////////////////////////////////////////////////////
   MyDiameterEntity *entity;
@@ -801,11 +811,15 @@ void Launcher::resetCounters() throw() {
 }
 
 void Launcher::signalUSR2() throw(anna::RuntimeException) {
+
+  std::string inputFile = getSignalUSR2InputFile();
+  std::string outputFile = getSignalUSR2OutputFile();
+
   LOGNOTICE(
   std::string msg = "Captured signal SIGUSR2. Reading tasks at '";
-  msg += SIGUSR2_TASKS_INPUT_FILENAME;
+  msg += inputFile;
   msg += "' (results will be written at '";
-  msg += SIGUSR2_TASKS_OUTPUT_FILENAME;
+  msg += outputFile;
   msg += "')";
   anna::Logger::notice(msg, ANNA_FILE_LOCATION);
   );
@@ -813,13 +827,18 @@ void Launcher::signalUSR2() throw(anna::RuntimeException) {
   // Operation:
   std::string line;
   std::string response_content;
-  std::ifstream in_file(SIGUSR2_TASKS_INPUT_FILENAME);
-  std::ofstream out_file(SIGUSR2_TASKS_OUTPUT_FILENAME);
+  std::ifstream in_file(inputFile);
+  std::ofstream out_file(outputFile);
 
   if(!in_file.is_open()) throw RuntimeException("Unable to read tasks", ANNA_FILE_LOCATION);
   if(!out_file.is_open()) throw RuntimeException("Unable to write tasks", ANNA_FILE_LOCATION);
 
   while(getline(in_file, line)) {
+
+    // Ignore comments and blank lines:
+    if (line[0] == '#')  continue;
+    if (std::string::npos == line.find_first_not_of(" \t")) continue;
+
     LOGDEBUG(
         std::string msg = "Processing line: ";
     msg += line;
@@ -994,6 +1013,16 @@ std::string Launcher::help() const throw() {
   result += "\n                                     This operation applies over all the registered host nodes";
   result += "\n                                      except if one specific working node has been set.";
   result += "\nforceCountersRecord                  Forces dump to file the current counters of the process.";
+  result += "\nlog-statistics-samples|<list>        Log statistics samples for the provided comma-separated concept id";
+  result += "\n                                      list, over './sample.<concept id>.csv' files. For example: \"1,2\"";
+  result += "\n                                      will log concepts 1 and 2. Reserved words \"all\"/\"none\" activates/";
+  result += "\n                                      deactivates all registered statistics concept identifiers. That ids";
+  result += "\n                                      are shown at context dump.";
+  result += "\nchange-dir[|directory]               Changes the execution point which could be fine to ease some";
+  result += "\n                                     file system interaction tasks. Be care about some requirements";
+  result += "\n                                     (for example if you have a user defined counters directory as";
+  result += "\n                                     relative path this must exists from the new execution directory).";
+  result += "\n                                     If nothing provided, initial working directory will be restored.";
   result += "\nshow-oam                             Dumps current counters of the process. This is also done at";
   result += "\n                                      process context dump.";
   result += "\nshow-stats                           Dumps statistics of the process. This is also done at process";
@@ -1148,6 +1177,9 @@ std::string Launcher::help() const throw() {
   result += "\n                              sendxml2e|<source_file>[|<step number>]";
   result += "\n                                                         Sends xml source file (pathfile) to entity (it would be a";
   result += "\n                                                          'forward' event if it came through local server endpoint).";
+  result += "\n                                                         Take into account that the xml message is encoded just on";
+  result += "\n                                                          call. The xml file is not longer needed neither interpreted";
+  result += "\n                                                          in case of modification, after calling this command.";
   result += "\n                                                         The step number should be provided for answers to indicate";
   result += "\n                                                          the 'wait for request' corresponding step. If you miss this";
   result += "\n                                                          reference, the sequence information (hop-by-hop, end-to-end)";
@@ -1155,6 +1187,8 @@ std::string Launcher::help() const throw() {
   result += "\n                                                          the difficulty of predicting these information). Be sure to";
   result += "\n                                                          refer to a 'wait for request' step. Conditions like 'regexp'";
   result += "\n                                                          (as we will see later) are not verified.";
+  result += "\n                                                         In the case of requests, the step number is used to force the";
+  result += "\n                                                          copy of Session-Id value from the referred step.";
   result += "\n";
   result += "\n                              sendxml2c|<source_file>[|<step number>]";
   result += "\n                                                         Sends xml source file (pathfile) to client (it would be a";
@@ -1347,7 +1381,7 @@ std::string Launcher::help() const throw() {
   result += "\n                                 steps margin, which could be useful to 'freeze' a test in the middle of its execution.";
   result += "\n                                 You could also provide -1 to make it non-interactive resuming it from the current step.";
   result += "\n";
-  result += "\n   test|reset|<soft/hard>[|id]   Reset the test case for id provided, all the tests when missing. It could be hard/soft:";
+  result += "\n   test|reset|<[soft]/hard>[|id] Reset the test case for id provided, all the tests when missing. It could be hard/soft:";
   result += "\n                                 - hard: you probably may need to stop the load rate before. This operation initializes";
   result += "\n                                         all test cases regardless their states.";
   result += "\n                                 - soft: only for finished cases (those with 'Success' or 'Failed' states). It does not";
@@ -1366,7 +1400,7 @@ std::string Launcher::help() const throw() {
   result += "\n                                 enabled because the programmed test cases dumps could be heavy (anyway you could enable the";
   result += "\n                                 dumps separately, for any of the possible states: Initialized, InProgress, Failed, Success).";
   result += "\n";
-  result += "\n   test|report|<initialized/in-progress/failed/success/all/none>[|[yes]|no]";
+  result += "\n   test|report|<initialized/in-progress/failed/success/[all]/none>[|[yes]|no]";
   result += "\n";
   result += "\n                                 Enables/disables report generation for a certain test case state: initialized, in-progress,";
   result += "\n                                 failed or success (also 'all' and 'none' reserved words could be used). This applies to report";
@@ -1404,13 +1438,13 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\nThe alternative using SIGUSR2 signal requires the creation of the task(s) file which will be read at";
   result += "\n signal event:";
-  result += "\n   echo \"<<operation>\" > "; result += SIGUSR2_TASKS_INPUT_FILENAME;
+  result += "\n   echo \"<<operation>\" > "; result += getSignalUSR2InputFile();
   result += "\n    then";
   result += "\n   kill -12 <pid>";
   result += "\n    or";
   result += "\n   kill -s SIGUSR2 <pid>";
   result += "\n    and then see the results:";
-  result += "\n   cat "; result += SIGUSR2_TASKS_OUTPUT_FILENAME;
+  result += "\n   cat "; result += getSignalUSR2OutputFile();
   result += "\n";
   result += "\n   (this file is ended with EOF final line, useful managing huge batch files to ensure the job completion)";
   result += "\n";
@@ -1424,13 +1458,45 @@ std::string Launcher::help() const throw() {
   return result;
 }
 
+
+void Launcher::logStatisticsSamples(const std::string &conceptsList) throw() {
+  anna::statistics::Engine &statEngine = anna::statistics::Engine::instantiate();
+
+  if(conceptsList == "all") {
+    if(statEngine.enableSampleLog(/* -1: all concepts */))
+      LOGDEBUG(anna::Logger::debug("Sample log activation for all statistic concepts", ANNA_FILE_LOCATION));
+  }
+  else if(conceptsList == "none") {
+      if(statEngine.disableSampleLog(/* -1: all concepts */))
+        LOGDEBUG(anna::Logger::debug("Sample log deactivation for all statistic concepts", ANNA_FILE_LOCATION));
+  } else {
+    anna::Tokenizer lst;
+    lst.apply(conceptsList, ",");
+
+    if(lst.size() >= 1) {
+      anna::Tokenizer::const_iterator tok_min(lst.begin());
+      anna::Tokenizer::const_iterator tok_max(lst.end());
+      anna::Tokenizer::const_iterator tok_iter;
+      int conceptId;
+
+      for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
+        conceptId = atoi(anna::Tokenizer::data(tok_iter));
+
+        if(statEngine.enableSampleLog(conceptId))
+          LOGDEBUG(anna::Logger::debug(anna::functions::asString("Sample log activation for statistic concept id = %d", conceptId), ANNA_FILE_LOCATION));
+      }
+    }
+  }
+}
+
+
 void Launcher::eventOperation(const std::string &operation, std::string &response_content) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tm("Launcher", "eventOperation", ANNA_FILE_LOCATION));
   if (operation == "") return; // ignore
-  LOGDEBUG(anna::Logger::debug(operation, ANNA_FILE_LOCATION));
+  LOGDEBUG(anna::Logger::debug(anna::functions::asString("Operation: %s", operation.c_str()), ANNA_FILE_LOCATION));
 
   // Default response:
-  response_content = "Operation processed with exception (see traces): ";
+  response_content = "Operation processed with exception: ";
   response_content += operation;
   std::string opt_response_content = ""; // aditional response content
   anna::DataBlock db_aux(true);
@@ -1520,7 +1586,10 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   // Check the number of parameters:
   bool wrongBody = false;
 
+  if((opType == "change-dir") && (numParams > 1)) wrongBody = true;
+  if((opType == "log-statistics-samples") && (numParams != 1)) wrongBody = true;
   if((opType == "node") && (numParams > 1)) wrongBody = true;
+
   if((opType == "node_auto") && (numParams > 0)) wrongBody = true;
 
   if(((opType == "code") || (opType == "decode")) && (numParams != 2)) wrongBody = true;
@@ -1549,6 +1618,24 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     return;
   }
 
+  if(opType == "log-statistics-samples") {
+    logStatisticsSamples(param1);
+    response_content = anna::functions::asString("Log statistics samples for '%s' concepts", param1.c_str());
+    return;
+  }
+
+  // Change execution directory:
+  if(opType == "change-dir") {
+    if (param1 == "") param1 = a_initialWorkingDirectory;
+    if (chdir(param1.c_str()) == 0)
+      response_content = "New execution directory configured: ";
+    else
+      response_content = "Cannot assign provided execution directory: ";
+
+    response_content += param1;
+    return;
+  }
+
   if(opType == "services") {
     std::string servicesFile = ((numParams == 1) ? param1 : "services.xml");
     try {
@@ -1782,13 +1869,13 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     // test|next[|<sync-amount>]                Forces the execution of the next test case(s) without waiting for test manager tick ...
     // test|ip-limit[|amount]                   In-progress limit of test cases. No new test cases will be launched over this value ...
     // test|repeats|<amount>                    Restarts the whole programmed test list when finished the amount number of times ...
-    // test|report|<initialized/in-progress/failed/success/all/none>[|[yes]|no]
+    // test|report|<initialized/in-progress/failed/success/[all]/none>[|[yes]|no]
     //                                          Enables/disables report generation for a certain test case state: initialized, in-progress ...
     // test|report-hex[|[yes]|no]               Reports could include the diameter messages in hexadecimal format. Disabled by default.
     // test|goto|<id>                           Updates current test pointer position.
     // test|look[|id]                           Show programmed test case for id provided, current when missing ...
     // test|interact|amount|id                  Makes interactive a specific test case id. The amount is the margin of execution steps ...
-    // test|reset|<soft/hard>[|id]              Reset the test case for id provided, all the tests when missing ...
+    // test|reset|<[soft]/hard>[|id]            Reset the test case for id provided, all the tests when missing ...
     // test|clear                               Clears all the programmed test cases.
     // test|summary                             Test manager general report (number of test cases, counts by state ...
 
@@ -1856,6 +1943,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       if (numParams > 3)
         throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
 
+      if(param2 == "") param2 = "all";
       if(param3 == "") param3 = "yes";
       bool enable = (param3 == "yes");
 
@@ -1964,7 +2052,8 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       if (numParams > 3)
         throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
 
-      if (param2 != "soft" && param2 != "hard")
+      if(param2 == "") param2 = "soft";
+     if (param2 != "soft" && param2 != "hard")
         throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
 
       int id = ((param3 != "") ? atoi(param3.c_str()) : -1);
@@ -1981,7 +2070,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       else {
         if (id == -1) {
           bool anyReset = testManager.resetPool((param2 == "hard") ? true:false);
-          opt_response_content = "reset have been sent to all programmed tests: "; opt_response_content += anyReset ? "some/all have been reset" : "nothing was reset";
+          opt_response_content = param2; opt_response_content += " reset have been sent to all programmed tests: "; opt_response_content += anyReset ? "some/all have been reset" : "nothing was reset";
         }
         else {
           opt_response_content = "cannot found test id (";
@@ -2034,13 +2123,11 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
           throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
         if(param3 == "") throw anna::RuntimeException(anna::functions::asString("Missing xml file for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION);
         codecMsg.loadXML(param3);
-        if (codecMsg.isRequest()) {
-          if (param4 != "")
-            throw anna::RuntimeException("Step number is provided with answers (to resolve the corresponding 'wait for request' step), but NOT with requests", ANNA_FILE_LOCATION);
-        }
-        else {
-          if (param4 == "") LOGWARNING(anna::Logger::warning("Step number has not been provided. Take into account that this answer message will be sent 'as is' and sequence information could be wrong at the remote peer", ANNA_FILE_LOCATION));
-        }
+        LOGWARNING(
+          if (!codecMsg.isRequest() && (param4 == ""))
+            anna::Logger::warning("Step number has not been provided. Take into account that this answer message will be sent 'as is' and sequence information could be wrong at the remote peer", ANNA_FILE_LOCATION);
+        );
+
         updateOperatedOriginHostWithMessage(codecMsg);
         int stepNumber = ((param4 != "") ? atoi(param4.c_str()):-1);
 
@@ -2079,10 +2166,13 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
         }
       }
       else if (param2 == "sh-command") {
-        if (numParams > 4)
-          throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        // Allow pipes in command:
+        //if (numParams > 4)
+        //  throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
         if(param3 == "") throw anna::RuntimeException("Missing script/executable command-line for 'sh-command' in test id operation", ANNA_FILE_LOCATION);
-        testManager.getTestCase(id)->addCommand(param3); // creates / reuses
+        std::string token = "|sh-command|";
+        std::string command = operation.substr(operation.find(token) + token.size());
+        testManager.getTestCase(id)->addCommand(command); // creates / reuses
       }
       else {
         throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
@@ -2194,12 +2284,17 @@ throw() {
   anna::comm::Application::asXML(result);
   // Timming:
   result->createAttribute("StartTime", a_start_time.asString());
+  result->createAttribute("InitialWorkingDirectory", a_initialWorkingDirectory);
   result->createAttribute("SecondsLifeTime", anna::time::functions::lapsedMilliseconds() / 1000);
   // Diameter:
   for (origin_hosts_it it = a_originHosts.begin(); it != a_originHosts.end(); it++) {
     it->second->asXML(result);
   }
 
+  // Registered codec engines:
+  anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
+  em.asXML(result);
+
   // OAM & statistics:
   oamAsXML(result);
   statsAsXML(result);