| 1 |
|
|---|
| 2 | #include "Event.h"
|
|---|
| 3 | #include "Time.h"
|
|---|
| 4 | #include "StateMachineDim.h"
|
|---|
| 5 | #include "ServiceList.h"
|
|---|
| 6 | #include <fstream>
|
|---|
| 7 |
|
|---|
| 8 | #include <boost/bind.hpp>
|
|---|
| 9 |
|
|---|
| 10 | //****************************************************************
|
|---|
| 11 | /** @class DataLogger
|
|---|
| 12 | *
|
|---|
| 13 | * @brief Logs all message and infos between the services
|
|---|
| 14 | *
|
|---|
| 15 | * This is the main logging class facility.
|
|---|
| 16 | * It derives from StateMachineDim and DimInfoHandler. the first parent is here to enforce
|
|---|
| 17 | * a state machine behaviour, while the second one is meant to make the dataLogger receive
|
|---|
| 18 | * dim services to which it subscribed from.
|
|---|
| 19 | * The possible states and transitions of the machine are:
|
|---|
| 20 | * \dot
|
|---|
| 21 | * digraph datalogger {
|
|---|
| 22 | * node [shape=record, fontname=Helvetica, fontsize=10];
|
|---|
| 23 | * e [label="Error" color="red"];
|
|---|
| 24 | * r [label="Ready"]
|
|---|
| 25 | * d [label="DailyOpen"]
|
|---|
| 26 | * w [label="WaitingRun"]
|
|---|
| 27 | * l [label="Logging"]
|
|---|
| 28 | * b [label="BadDailyconfig" color="red"]
|
|---|
| 29 | * c [label="BadRunConfig" color="red"]
|
|---|
| 30 | *
|
|---|
| 31 | * e -> r
|
|---|
| 32 | * r -> e
|
|---|
| 33 | * r -> d
|
|---|
| 34 | * r -> b
|
|---|
| 35 | * d -> w
|
|---|
| 36 | * d -> r
|
|---|
| 37 | * w -> r
|
|---|
| 38 | * l -> r
|
|---|
| 39 | * l -> w
|
|---|
| 40 | * b -> d
|
|---|
| 41 | * w -> c
|
|---|
| 42 | * w -> l
|
|---|
| 43 | * b -> r
|
|---|
| 44 | * c -> r
|
|---|
| 45 | * c -> l
|
|---|
| 46 | * }
|
|---|
| 47 | * \enddot
|
|---|
| 48 | *
|
|---|
| 49 | * @todo
|
|---|
| 50 | * - A lot
|
|---|
| 51 | ****************************************************************/
|
|---|
| 52 | class DataLogger : public StateMachineDim, DimInfoHandler
|
|---|
| 53 | {
|
|---|
| 54 | public:
|
|---|
| 55 | /// The list of existing states specific to the DataLogger
|
|---|
| 56 | enum
|
|---|
| 57 | {
|
|---|
| 58 | kSM_DailyOpen = 20, ///< Daily file openned and writing
|
|---|
| 59 | kSM_WaitingRun = 30, ///< waiting for the run number to open the run file
|
|---|
| 60 | kSM_Logging = 40, ///< both files openned and writing
|
|---|
| 61 | kSM_BadDailyConfig = 0x101, ///< the folder specified for daily logging does not exist or has bad permissions
|
|---|
| 62 | kSM_BadRunConfig = 0x102, ///< the folder specified for the run logging does not exist or has wrong permissions or no run number
|
|---|
| 63 | } localstates_t;
|
|---|
| 64 |
|
|---|
| 65 | DataLogger();
|
|---|
| 66 | ~DataLogger();
|
|---|
| 67 |
|
|---|
| 68 | private:
|
|---|
| 69 | //Define all the data structure specific to the DataLogger here
|
|---|
| 70 | std::ofstream fDailyFile; /// ofstream for the dailyfile
|
|---|
| 71 | std::ofstream fRunFile; /// ofstream for the run-specific file
|
|---|
| 72 | std::string fDailyFileName; /// base path of the dailyfile
|
|---|
| 73 | std::string fRunFileName; ///base path of the run file
|
|---|
| 74 | int runNumber; ///run number (-1 means no run number specified)
|
|---|
| 75 |
|
|---|
| 76 | ///Define all the static names
|
|---|
| 77 | static const char* configDay;
|
|---|
| 78 | static const char* configRun;
|
|---|
| 79 | static const char* configRunNumber;
|
|---|
| 80 | static const char* configLog;
|
|---|
| 81 | static const char* transStart;
|
|---|
| 82 | static const char* transStop;
|
|---|
| 83 | static const char* transStartRun;
|
|---|
| 84 | static const char* transStopRun;
|
|---|
| 85 | static const char* transReset;
|
|---|
| 86 | static const char* transWait;
|
|---|
| 87 | static const char* runNumberInfo; ///< This is the name of the dimInfo received to specify the run number. It must be updated once the final name will be defined
|
|---|
| 88 |
|
|---|
| 89 | int Execute(); ///Inherited from state machine impl
|
|---|
| 90 |
|
|---|
| 91 | int Transition(const Event& evt); ///Inherited from state machine impl
|
|---|
| 92 |
|
|---|
| 93 | int Configure(const Event& evt); ///Inherited from state machine impl
|
|---|
| 94 |
|
|---|
| 95 | //overloading of DIM's infoHandler function
|
|---|
| 96 | void infoHandler(); ///Inherited from DimInfoHandler
|
|---|
| 97 |
|
|---|
| 98 | ServiceList fServiceList;///for obtaining the name of the existing services
|
|---|
| 99 |
|
|---|
| 100 | std::map<std::string, std::vector<DimStampedInfo> > fServiceSubscriptions; ///All the services to which we've subscribed to. Sorted by server name
|
|---|
| 101 |
|
|---|
| 102 | //internal methods
|
|---|
| 103 | void LogPlease(DimInfo* I); ///Logging method for the services info received
|
|---|
| 104 | std::string ToString(const char *format, const void *data, int size); ///Convertion from raw format to human-readable string
|
|---|
| 105 | //configure methods
|
|---|
| 106 | int ConfigureDailyFileName(const Event& evt); ///Configuration of the daily file path
|
|---|
| 107 | int ConfigureRunFileName(const Event& evt); ///Configuration fo the file name
|
|---|
| 108 | //TODO this will be given by an info, not a command.
|
|---|
| 109 | int ConfigureRunNumber(const Event& evt); ///DEPREC - configuration of the run number
|
|---|
| 110 | int LogMessagePlease(const Event& evt); ///logging method for the messages
|
|---|
| 111 | void CheckForServicesUpdate(); ///checks with fServiceList whether or not the services got updated
|
|---|
| 112 | void CheckForRunNumber(DimInfo* I); ///checks whether or not the current info being treated is a run number
|
|---|
| 113 | //transitions methods
|
|---|
| 114 | int StartPlease(); /// start transition
|
|---|
| 115 | int StopPlease(); ///stop transition
|
|---|
| 116 | int StartRunPlease(); ///from waiting to logging transition
|
|---|
| 117 | int StopRunPlease(); /// from logging to waiting transition
|
|---|
| 118 | int ResetPlease(); ///reset transition
|
|---|
| 119 | int DailyToWaitRunPlease(); ///from dailyOpen to waiting transition
|
|---|
| 120 |
|
|---|
| 121 | void InitServiceSubscription(); ///first subscription to the dim services.
|
|---|
| 122 |
|
|---|
| 123 |
|
|---|
| 124 |
|
|---|
| 125 | }; //DataLogger
|
|---|
| 126 |
|
|---|
| 127 | //static members initialization
|
|---|
| 128 | //since I do not check the transition/config names any longer, indeed maybe these could be hard-coded... but who knows what will happen in the future ?
|
|---|
| 129 | const char* DataLogger::configDay = "CONFIG_DAY";
|
|---|
| 130 | const char* DataLogger::configRun = "CONFIG_RUN";
|
|---|
| 131 | const char* DataLogger::configRunNumber = "CONFIG_RUN_NUMBER";
|
|---|
| 132 | const char* DataLogger::configLog = "LOG";
|
|---|
| 133 | const char* DataLogger::transStart = "START";
|
|---|
| 134 | const char* DataLogger::transStop = "STOP";
|
|---|
| 135 | const char* DataLogger::transStartRun = "START_RUN";
|
|---|
| 136 | const char* DataLogger::transStopRun = "STOP_RUN";
|
|---|
| 137 | const char* DataLogger::transReset = "RESET";
|
|---|
| 138 | const char* DataLogger::transWait = "WAIT_RUN_NUMBER";
|
|---|
| 139 | const char* DataLogger::runNumberInfo = "RUN_NUMBER";
|
|---|
| 140 |
|
|---|
| 141 | /****************************************************************
|
|---|
| 142 | *
|
|---|
| 143 | * DATA LOGGER CONSTRUCTOR
|
|---|
| 144 | *
|
|---|
| 145 | ****************************************************************/
|
|---|
| 146 | //! Default constructor
|
|---|
| 147 | DataLogger::DataLogger() : StateMachineDim(std::cout, "DATA_LOGGER")
|
|---|
| 148 | {
|
|---|
| 149 | //initialize member data
|
|---|
| 150 | fDailyFileName = "";
|
|---|
| 151 | fRunFileName = "";
|
|---|
| 152 | runNumber = -1;
|
|---|
| 153 | //Give a name to this machine's specific states
|
|---|
| 154 | AddStateName(kSM_DailyOpen, "Daily_File_Openened");
|
|---|
| 155 | AddStateName(kSM_WaitingRun, "Waiting_Run_Number");
|
|---|
| 156 | AddStateName(kSM_Logging, "Logging data");
|
|---|
| 157 | AddStateName(kSM_BadDailyConfig, "Folder_For_Daily_Logging_Badly_Configured");
|
|---|
| 158 | AddStateName(kSM_BadRunConfig, "Folder_For_Run_Logging_Badly Configured");
|
|---|
| 159 |
|
|---|
| 160 | /*Add the possible transitions for this machine*/
|
|---|
| 161 | AddTransition(kSM_DailyOpen, transStart, kSM_Ready, kSM_BadDailyConfig) //start the daily logging. daily file location must be specified already
|
|---|
| 162 | ->AssignFunction(boost::bind(&DataLogger::StartPlease, this));
|
|---|
| 163 | AddTransition(kSM_Ready, transStop, kSM_DailyOpen, kSM_WaitingRun, kSM_Logging) //stop the data logging
|
|---|
| 164 | ->AssignFunction(boost::bind(&DataLogger::StopPlease, this));
|
|---|
| 165 | AddTransition(kSM_Logging, transStartRun, kSM_WaitingRun, kSM_BadRunConfig) //start the run logging. run file location must be specified already.
|
|---|
| 166 | ->AssignFunction(boost::bind(&DataLogger::StartRunPlease, this));
|
|---|
| 167 | AddTransition(kSM_WaitingRun, transStopRun, kSM_Logging)
|
|---|
| 168 | ->AssignFunction(boost::bind(&DataLogger::StopRunPlease, this));
|
|---|
| 169 | AddTransition(kSM_Ready, transReset, kSM_Error, kSM_BadDailyConfig, kSM_BadRunConfig, kSM_Error) //transition to exit error states. dunno if required or not, would close the daily file if already openned.
|
|---|
| 170 | ->AssignFunction(boost::bind(&DataLogger::ResetPlease, this));
|
|---|
| 171 | AddTransition(kSM_WaitingRun, transWait, kSM_DailyOpen)
|
|---|
| 172 | ->AssignFunction(boost::bind(&DataLogger::DailyToWaitRunPlease, this));
|
|---|
| 173 | /*Add the possible configurations for this machine*/
|
|---|
| 174 | AddConfiguration(configDay, kSM_Ready, kSM_BadDailyConfig) //configure the daily file location. cannot be done before the file is actually opened
|
|---|
| 175 | ->AssignFunction(boost::bind(&DataLogger::ConfigureDailyFileName, this, _1));
|
|---|
| 176 | AddConfiguration(configRun, kSM_Ready, kSM_BadDailyConfig, kSM_DailyOpen, kSM_WaitingRun, kSM_BadRunConfig) //configure the run file location. cannot be done before the file is actually opened, and not in a dailly related error.
|
|---|
| 177 | ->AssignFunction(boost::bind(&DataLogger::ConfigureRunFileName, this, _1));
|
|---|
| 178 | /*wait for Dim to finish initializing*/
|
|---|
| 179 | /*just a sleep for now. */
|
|---|
| 180 | /*TODO: add a better way to wait: poll DIM for something I guess. Maybe get the configuration from conf server ? */
|
|---|
| 181 |
|
|---|
| 182 | usleep(1000000); //10ms
|
|---|
| 183 |
|
|---|
| 184 | //Provide a logging command
|
|---|
| 185 | //I get the feeling that I should be going through the EventImp
|
|---|
| 186 | //instead of DimCommand directly, mainly because the commandHandler
|
|---|
| 187 | //is already done in StateMachineImp.cc
|
|---|
| 188 | //Thus I'll simply add a configuration, which I will treat as the logging command
|
|---|
| 189 | AddConfiguration(configRun, kSM_DailyOpen, kSM_Logging, kSM_WaitingRun, kSM_BadRunConfig)
|
|---|
| 190 | ->AssignFunction(boost::bind(&DataLogger::LogMessagePlease, this, _1));
|
|---|
| 191 |
|
|---|
| 192 | InitServiceSubscription();
|
|---|
| 193 |
|
|---|
| 194 | //All configuration done, callback funtions set, go to ready state and thus prevent the run loop from being executed
|
|---|
| 195 | SetReady();
|
|---|
| 196 | }
|
|---|
| 197 | //! Initialization of the subscription to the services.
|
|---|
| 198 | void DataLogger::InitServiceSubscription()
|
|---|
| 199 | {
|
|---|
| 200 | //assign myself as the info handler
|
|---|
| 201 | fServiceList.SetHandler(this);
|
|---|
| 202 |
|
|---|
| 203 | //crawl through the list of services and subscribe to all of them
|
|---|
| 204 | //TODO I still haven't figured out how the update of services shouldbe performed
|
|---|
| 205 | //TODO: I don't think that the reference would work in this case because what is returned is a temporary. but should try anyway in case this works...
|
|---|
| 206 | const std::vector<std::string> serverList = fServiceList.GetServerList();
|
|---|
| 207 | for (unsigned int i=0;i<serverList.size();i++)
|
|---|
| 208 | {//get the service list associated with each server
|
|---|
| 209 | if (strstr(serverList[i].c_str(), "DIS_DNS") || strstr(serverList[i].c_str(), "DATA_LOGGER"))
|
|---|
| 210 | continue;
|
|---|
| 211 | for (std::vector<std::string>::const_iterator j=fServiceList.begin(serverList[i]); j != fServiceList.end(serverList[i]); j++)
|
|---|
| 212 | {//and subscribe to each service !
|
|---|
| 213 | fServiceSubscriptions[serverList[i]].push_back(DimStampedInfo(j->c_str(), const_cast<char*>(""), this));
|
|---|
| 214 | }
|
|---|
| 215 | }
|
|---|
| 216 | }
|
|---|
| 217 | //! destructor
|
|---|
| 218 | DataLogger::~DataLogger()
|
|---|
| 219 | {
|
|---|
| 220 | if (fDailyFile.is_open())
|
|---|
| 221 | fDailyFile.close();
|
|---|
| 222 | if (fRunFile.is_open())
|
|---|
| 223 | fRunFile.close();
|
|---|
| 224 | ;
|
|---|
| 225 | }
|
|---|
| 226 | /****************************************************************
|
|---|
| 227 | *
|
|---|
| 228 | * DATA LOGGER'S EXECUTE
|
|---|
| 229 | *
|
|---|
| 230 | ****************************************************************/
|
|---|
| 231 | //! Execute
|
|---|
| 232 | //! Shouldn't be run as we use callbacks instead
|
|---|
| 233 | int DataLogger::Execute()
|
|---|
| 234 | {
|
|---|
| 235 | //due to the callback mecanism, this function should never be called
|
|---|
| 236 | return kSM_FatalError;
|
|---|
| 237 |
|
|---|
| 238 | switch (GetCurrentState())
|
|---|
| 239 | {
|
|---|
| 240 | case kSM_Error:
|
|---|
| 241 | case kSM_Ready:
|
|---|
| 242 | case kSM_DailyOpen:
|
|---|
| 243 | case kSM_WaitingRun:
|
|---|
| 244 | case kSM_Logging:
|
|---|
| 245 | case kSM_BadDailyConfig:
|
|---|
| 246 | case kSM_BadRunConfig:
|
|---|
| 247 | return GetCurrentState();
|
|---|
| 248 |
|
|---|
| 249 | }
|
|---|
| 250 | //this line below should never be hit. It here mainly to remove warnings at compilation
|
|---|
| 251 | return kSM_FatalError;
|
|---|
| 252 | }
|
|---|
| 253 | /****************************************************************
|
|---|
| 254 | *
|
|---|
| 255 | * DATA LOGGER'S TRANSITION
|
|---|
| 256 | *
|
|---|
| 257 | ****************************************************************/
|
|---|
| 258 |
|
|---|
| 259 | //! Shouldn't be run as we use callbacks instead
|
|---|
| 260 | int DataLogger::Transition(const Event& evt)
|
|---|
| 261 | {
|
|---|
| 262 | //due to the callback mecanism, this function should never be called
|
|---|
| 263 | return kSM_FatalError;
|
|---|
| 264 |
|
|---|
| 265 | switch (evt.GetTargetState())
|
|---|
| 266 | {
|
|---|
| 267 | case kSM_Ready:
|
|---|
| 268 | /*here we must figure out whether the STOP or RESET command was sent*/
|
|---|
| 269 | /*close opened files and go back to ready state*/
|
|---|
| 270 | switch (GetCurrentState())
|
|---|
| 271 | {
|
|---|
| 272 | case kSM_BadDailyConfig:
|
|---|
| 273 | case kSM_BadRunConfig:
|
|---|
| 274 | case kSM_Error:
|
|---|
| 275 | return ResetPlease();
|
|---|
| 276 |
|
|---|
| 277 | case kSM_Logging:
|
|---|
| 278 | case kSM_WaitingRun:
|
|---|
| 279 | case kSM_DailyOpen:
|
|---|
| 280 | return StopPlease();
|
|---|
| 281 | }
|
|---|
| 282 | break;
|
|---|
| 283 |
|
|---|
| 284 | case kSM_DailyOpen:
|
|---|
| 285 | /*Attempt to open the daily file */
|
|---|
| 286 | switch (GetCurrentState())
|
|---|
| 287 | {
|
|---|
| 288 | case kSM_Ready:
|
|---|
| 289 | case kSM_BadDailyConfig:
|
|---|
| 290 | return StartPlease();
|
|---|
| 291 | }
|
|---|
| 292 | break;
|
|---|
| 293 |
|
|---|
| 294 | case kSM_WaitingRun:
|
|---|
| 295 | /*either close the run file, or just go to the waitingrun state (if coming from daily open*/
|
|---|
| 296 | switch (GetCurrentState())
|
|---|
| 297 | {
|
|---|
| 298 | case kSM_DailyOpen:
|
|---|
| 299 | return kSM_WaitingRun;
|
|---|
| 300 |
|
|---|
| 301 | case kSM_Logging:
|
|---|
| 302 | return StopRunPlease();
|
|---|
| 303 | }
|
|---|
| 304 | break;
|
|---|
| 305 |
|
|---|
| 306 | case kSM_Logging:
|
|---|
| 307 | /*Attempt to open run file */
|
|---|
| 308 | switch (GetCurrentState())
|
|---|
| 309 | {
|
|---|
| 310 | case kSM_WaitingRun:
|
|---|
| 311 | case kSM_BadRunConfig:
|
|---|
| 312 | return StartRunPlease();
|
|---|
| 313 | }
|
|---|
| 314 | break;
|
|---|
| 315 | }
|
|---|
| 316 | //Getting here means that an invalid transition has been asked.
|
|---|
| 317 | //TODO Log an error message
|
|---|
| 318 | //and return the fatal error state
|
|---|
| 319 | return kSM_FatalError;
|
|---|
| 320 | }
|
|---|
| 321 | /****************************************************************
|
|---|
| 322 | *
|
|---|
| 323 | * DATA LOGGER'S CONFIGURE
|
|---|
| 324 | *
|
|---|
| 325 | ****************************************************************/
|
|---|
| 326 | //! Shouldn't be run as we use callbacks instead
|
|---|
| 327 | int DataLogger::Configure(const Event& evt)
|
|---|
| 328 | {
|
|---|
| 329 | //due to the callback mecanism, this function should never be called
|
|---|
| 330 | return kSM_FatalError;
|
|---|
| 331 |
|
|---|
| 332 | switch (evt.GetTargetState())
|
|---|
| 333 | {
|
|---|
| 334 | case kSM_Ready:
|
|---|
| 335 | case kSM_BadDailyConfig:
|
|---|
| 336 | return ConfigureDailyFileName(evt);
|
|---|
| 337 | break;
|
|---|
| 338 |
|
|---|
| 339 | case kSM_WaitingRun:
|
|---|
| 340 | case kSM_BadRunConfig:
|
|---|
| 341 | return ConfigureRunFileName(evt);
|
|---|
| 342 | break;
|
|---|
| 343 |
|
|---|
| 344 | case kSM_Logging:
|
|---|
| 345 | case kSM_DailyOpen:
|
|---|
| 346 | return LogMessagePlease(evt);
|
|---|
| 347 | break;
|
|---|
| 348 |
|
|---|
| 349 | }
|
|---|
| 350 | //Getting here means that an invalid configuration has been asked.
|
|---|
| 351 | //TODO Log an error message
|
|---|
| 352 | //and return the fatal error state
|
|---|
| 353 | return kSM_FatalError;
|
|---|
| 354 | }
|
|---|
| 355 | /****************************************************************
|
|---|
| 356 | *
|
|---|
| 357 | * DATA LOGGER'S INFOHANDLER
|
|---|
| 358 | *
|
|---|
| 359 | ****************************************************************/
|
|---|
| 360 | void DataLogger::infoHandler()
|
|---|
| 361 | {
|
|---|
| 362 | DimInfo* I = getInfo();
|
|---|
| 363 | //there I should get the services updates. It remains unclear whether I will be getting the new services or not through here
|
|---|
| 364 | // CheckForServicesUpdate(); //in this function I will add/remove services subscription
|
|---|
| 365 | CheckForRunNumber(I);
|
|---|
| 366 | LogPlease(I);
|
|---|
| 367 | }
|
|---|
| 368 | //! Checks for changes in the existingn services
|
|---|
| 369 | //! @todo finish this function as most of it is still missing (plus what is already there isn't great)
|
|---|
| 370 | void DataLogger::CheckForServicesUpdate()
|
|---|
| 371 | {//TODO well... do it...
|
|---|
| 372 | //TODO handle the cases were one server/service was removed and one was added
|
|---|
| 373 | const std::vector<std::string> serverList = fServiceList.GetServerList();
|
|---|
| 374 | if (serverList.size() != fServiceSubscriptions.size())
|
|---|
| 375 | {//some servers were added/deleted. Rebuild the list entirely
|
|---|
| 376 | std::cout << "Redoing the server list entirely " << serverList.size() << " " << fServiceSubscriptions.size() << std::endl;
|
|---|
| 377 | std::map<std::string, std::vector<DimStampedInfo> >::iterator it;
|
|---|
| 378 | for (it=fServiceSubscriptions.begin(); it != fServiceSubscriptions.end(); it++)
|
|---|
| 379 | (*it).second.clear();
|
|---|
| 380 | fServiceSubscriptions.clear();
|
|---|
| 381 | InitServiceSubscription();
|
|---|
| 382 | return;
|
|---|
| 383 | }
|
|---|
| 384 | //TODO crawl the list to see if any of the servers has updated its service list
|
|---|
| 385 |
|
|---|
| 386 | }
|
|---|
| 387 | //! Looks whether the currently being processed DimInfo indeed is a run number or not
|
|---|
| 388 | void DataLogger::CheckForRunNumber(DimInfo* I)
|
|---|
| 389 | {
|
|---|
| 390 | return;
|
|---|
| 391 | if (strstr(I->getName(), runNumberInfo) != NULL)
|
|---|
| 392 | {//assumes that the run number is an integer
|
|---|
| 393 | //TODO check the format here
|
|---|
| 394 | runNumber = I->getInt();
|
|---|
| 395 | }
|
|---|
| 396 | }
|
|---|
| 397 | /****************************************************************
|
|---|
| 398 | *
|
|---|
| 399 | * DATA LOGGER'S RUN LOG
|
|---|
| 400 | *
|
|---|
| 401 | * write info to run log. Go to error if anything goes wrong
|
|---|
| 402 | *
|
|---|
| 403 | ****************************************************************/
|
|---|
| 404 | //! write info to logs. Go to error if anything goes wrong
|
|---|
| 405 | void DataLogger::LogPlease(DimInfo* I)
|
|---|
| 406 | {
|
|---|
| 407 | if (I->getSize() == 0)
|
|---|
| 408 | return;
|
|---|
| 409 | //TODO add service exclusion
|
|---|
| 410 |
|
|---|
| 411 | if (!fDailyFile.is_open())
|
|---|
| 412 | return;
|
|---|
| 413 | //construct the header
|
|---|
| 414 | std::stringstream header;
|
|---|
| 415 | Time cTime((time_t)(I->getTimestamp()), 0);
|
|---|
| 416 | header << I->getName() << " " << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
|
|---|
| 417 | header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
|
|---|
| 418 | header << cTime.ms() << " " << I->getQuality() << " ";
|
|---|
| 419 |
|
|---|
| 420 | if (fDailyFile.is_open())
|
|---|
| 421 | fDailyFile << header;
|
|---|
| 422 | if (fRunFile.is_open())
|
|---|
| 423 | fRunFile << header;
|
|---|
| 424 |
|
|---|
| 425 |
|
|---|
| 426 | std::string text = ToString(I->getFormat(), I->getData(), I->getSize());
|
|---|
| 427 |
|
|---|
| 428 | if (!text.empty())
|
|---|
| 429 | {//replace bizarre characters by white space
|
|---|
| 430 | for (unsigned int i=0; i<text.size(); i++)
|
|---|
| 431 | {
|
|---|
| 432 | if (text[i] == '\n')
|
|---|
| 433 | text[i] = '\\';
|
|---|
| 434 | else
|
|---|
| 435 | if (iscntrl(text[i]))
|
|---|
| 436 | text[i] = ' ';
|
|---|
| 437 | }
|
|---|
| 438 | if (fDailyFile.is_open())
|
|---|
| 439 | fDailyFile << text;
|
|---|
| 440 | if (fRunFile.is_open())
|
|---|
| 441 | fRunFile << text;
|
|---|
| 442 | }
|
|---|
| 443 | else
|
|---|
| 444 | {
|
|---|
| 445 | if (fDailyFile.is_open())
|
|---|
| 446 | fDailyFile << "Cannot interpret service format" << std::endl;
|
|---|
| 447 | if (fRunFile.is_open())
|
|---|
| 448 | fRunFile << "Cannot interpret service format" << std::endl;
|
|---|
| 449 | }
|
|---|
| 450 | }
|
|---|
| 451 | //! Translates DIM data safely to string (assures no invalid memory accesses are made)
|
|---|
| 452 | //! Was mostly copied from DColl.cc
|
|---|
| 453 | std::string DataLogger::ToString(const char *format, const void *data, int size) {
|
|---|
| 454 |
|
|---|
| 455 | std::ostringstream Text;
|
|---|
| 456 |
|
|---|
| 457 | // Structure: print hex representation
|
|---|
| 458 | if (strlen(format) != 1) {
|
|---|
| 459 | for (int i=0; i<size; i++) {
|
|---|
| 460 | Text << std::setw(2) << std::hex << *((char *) data + i) << " ";
|
|---|
| 461 | }
|
|---|
| 462 | return Text.str();
|
|---|
| 463 | }
|
|---|
| 464 |
|
|---|
| 465 | // String if format "C" and terminated with \0
|
|---|
| 466 | if (strcmp(format, "C") == 0 && size > 0 && *((char *) data+size-1)=='\0') {
|
|---|
| 467 | return std::string((char *) data);
|
|---|
| 468 | }
|
|---|
| 469 |
|
|---|
| 470 | // Number array
|
|---|
| 471 | int ElementSize;
|
|---|
| 472 | switch (*format) {
|
|---|
| 473 | case 'C': ElementSize = sizeof(char); break;
|
|---|
| 474 | case 'I':
|
|---|
| 475 | case 'L': ElementSize = sizeof(int); break;
|
|---|
| 476 | case 'S': ElementSize = sizeof(short); break;
|
|---|
| 477 | case 'F': ElementSize = sizeof(float); break;
|
|---|
| 478 | case 'D': ElementSize = sizeof(double); break;
|
|---|
| 479 | case 'X': ElementSize = sizeof(long long); break;
|
|---|
| 480 | default: return std::string();
|
|---|
| 481 | }
|
|---|
| 482 |
|
|---|
| 483 | for (int i=0; i<size/ElementSize; i++) {
|
|---|
| 484 | // Space between entries
|
|---|
| 485 | if (i != 0) Text << " ";
|
|---|
| 486 |
|
|---|
| 487 | // Translate data
|
|---|
| 488 | switch (*format) {
|
|---|
| 489 | case 'C': Text << *((char *) data + i); break;
|
|---|
| 490 | case 'I':
|
|---|
| 491 | case 'L': Text << *((int *) data + i); break;
|
|---|
| 492 | case 'S': Text << *((short *) data + i); break;
|
|---|
| 493 | case 'F': Text << *((float *) data + i); break;
|
|---|
| 494 | case 'D': Text << *((double *) data + i); break;
|
|---|
| 495 | case 'X': Text << *((long long *) data + i); break;
|
|---|
| 496 | }
|
|---|
| 497 | }
|
|---|
| 498 |
|
|---|
| 499 | return Text.str();
|
|---|
| 500 | }
|
|---|
| 501 | //! write messages to logs. Go to error if anything goes wrong
|
|---|
| 502 | int DataLogger::LogMessagePlease(const Event& evt)
|
|---|
| 503 | {
|
|---|
| 504 | if (!fDailyFile.is_open())
|
|---|
| 505 | return GetCurrentState();
|
|---|
| 506 |
|
|---|
| 507 | std::stringstream header;
|
|---|
| 508 | const Time& cTime = evt.GetTime();
|
|---|
| 509 | header << evt.GetName() << " " << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
|
|---|
| 510 | header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
|
|---|
| 511 | header << cTime.ms() << " ";
|
|---|
| 512 |
|
|---|
| 513 | if (fDailyFile.is_open())
|
|---|
| 514 | fDailyFile << header;
|
|---|
| 515 | if (fRunFile.is_open())
|
|---|
| 516 | fRunFile << header;
|
|---|
| 517 |
|
|---|
| 518 | std::string text = ToString(evt.GetFormat().c_str(), evt.GetData(), evt.GetSize());
|
|---|
| 519 |
|
|---|
| 520 | if (!text.empty())
|
|---|
| 521 | {//replace bizarre characters by white space
|
|---|
| 522 | for (unsigned int i=0; i<text.size(); i++)
|
|---|
| 523 | {
|
|---|
| 524 | if (text[i] == '\n')
|
|---|
| 525 | text[i] = '\\';
|
|---|
| 526 | else
|
|---|
| 527 | if (iscntrl(text[i]))
|
|---|
| 528 | text[i] = ' ';
|
|---|
| 529 | }
|
|---|
| 530 | if (fDailyFile.is_open())
|
|---|
| 531 | fDailyFile << text;
|
|---|
| 532 | if (fRunFile.is_open())
|
|---|
| 533 | fRunFile << text;
|
|---|
| 534 | }
|
|---|
| 535 | else
|
|---|
| 536 | {
|
|---|
| 537 | if (fDailyFile.is_open())
|
|---|
| 538 | fDailyFile << "Cannot interpret log message format" << std::endl;
|
|---|
| 539 | if (fRunFile.is_open())
|
|---|
| 540 | fRunFile << "Cannot interpret log message format" << std::endl;
|
|---|
| 541 | }
|
|---|
| 542 |
|
|---|
| 543 | return GetCurrentState();
|
|---|
| 544 | }
|
|---|
| 545 | /****************************************************************
|
|---|
| 546 | *
|
|---|
| 547 | * DATA LOGGER'S RUN LOG
|
|---|
| 548 | */
|
|---|
| 549 | //!Set the current daily file name. This will NOT close any file
|
|---|
| 550 | /*
|
|---|
| 551 | ****************************************************************/
|
|---|
| 552 | int DataLogger::ConfigureDailyFileName(const Event& evt)
|
|---|
| 553 | {
|
|---|
| 554 | fDailyFileName = std::string(evt.GetText());
|
|---|
| 555 | return GetCurrentState();
|
|---|
| 556 | }
|
|---|
| 557 | /****************************************************************
|
|---|
| 558 | *
|
|---|
| 559 | * DATA LOGGER'S CONFIGURE RUN FILE NAME
|
|---|
| 560 | *
|
|---|
| 561 | */
|
|---|
| 562 | //! Set the current run folder name. This will NOT close any file
|
|---|
| 563 | /*
|
|---|
| 564 | ****************************************************************/
|
|---|
| 565 | int DataLogger::ConfigureRunFileName(const Event& evt)
|
|---|
| 566 | {
|
|---|
| 567 | fRunFileName = std::string(evt.GetText());
|
|---|
| 568 | return GetCurrentState();
|
|---|
| 569 | }
|
|---|
| 570 | /****************************************************************
|
|---|
| 571 | *
|
|---|
| 572 | * DATA LOGGER'S CONFIGURE RUN NUMBER
|
|---|
| 573 | *
|
|---|
| 574 | */
|
|---|
| 575 | //! set the current run number. This will NOT close any file.
|
|---|
| 576 | /*
|
|---|
| 577 | ****************************************************************/
|
|---|
| 578 | int DataLogger::ConfigureRunNumber(const Event& evt)
|
|---|
| 579 | {
|
|---|
| 580 | runNumber = evt.GetInt();
|
|---|
| 581 | //TODO replace the run number in the filename if already exist. Otherwise just append it
|
|---|
| 582 | return GetCurrentState();
|
|---|
| 583 | }
|
|---|
| 584 | /****************************************************************
|
|---|
| 585 | *
|
|---|
| 586 | * DATA LOGGER'S START PLEASE
|
|---|
| 587 | *
|
|---|
| 588 | */
|
|---|
| 589 | //! Implements the start transition
|
|---|
| 590 | /*
|
|---|
| 591 | ****************************************************************/
|
|---|
| 592 | int DataLogger::StartPlease()
|
|---|
| 593 | {
|
|---|
| 594 | //TODO concatenate the dailyFileName and the formatted date and extension to obtain the full file name
|
|---|
| 595 | Time time;//(Time::utc);
|
|---|
| 596 | std::stringstream sTime;
|
|---|
| 597 | sTime << time.Y() << "_" << time.M() << "_" << time.D();
|
|---|
| 598 | std::string fullName = fDailyFileName + '/' + sTime.str() + ".log";
|
|---|
| 599 |
|
|---|
| 600 | fDailyFile.open(fullName.c_str(), std::ios_base::out | std::ios_base::ate); //maybe should be "app" instead of "ate" ??
|
|---|
| 601 | if (!fDailyFile.is_open())
|
|---|
| 602 | {
|
|---|
| 603 | //TODO send an error message
|
|---|
| 604 | return kSM_BadDailyConfig;
|
|---|
| 605 | }
|
|---|
| 606 | return kSM_DailyOpen;
|
|---|
| 607 | }
|
|---|
| 608 | /****************************************************************
|
|---|
| 609 | *
|
|---|
| 610 | * DATA LOGGER'S STOP PLEASE
|
|---|
| 611 | *
|
|---|
| 612 | */
|
|---|
| 613 | //! Implements the stop transition
|
|---|
| 614 | /*
|
|---|
| 615 | ****************************************************************/
|
|---|
| 616 | int DataLogger::StopPlease()
|
|---|
| 617 | {
|
|---|
| 618 | if (fDailyFile.is_open())
|
|---|
| 619 | fDailyFile.close();
|
|---|
| 620 |
|
|---|
| 621 | if (fRunFile.is_open())
|
|---|
| 622 | fRunFile.close();
|
|---|
| 623 |
|
|---|
| 624 | return kSM_Ready;
|
|---|
| 625 |
|
|---|
| 626 | }
|
|---|
| 627 | /****************************************************************
|
|---|
| 628 | *
|
|---|
| 629 | * DATA LOGGER'S START RUN PLEASE
|
|---|
| 630 | *
|
|---|
| 631 | */
|
|---|
| 632 | //! Implements the start run transtition
|
|---|
| 633 | /*
|
|---|
| 634 | ****************************************************************/
|
|---|
| 635 | int DataLogger::StartRunPlease()
|
|---|
| 636 | {
|
|---|
| 637 | //attempt to open run file with current parameters
|
|---|
| 638 | if (runNumber == -1)
|
|---|
| 639 | return kSM_BadRunConfig;
|
|---|
| 640 | std::stringstream sRun;
|
|---|
| 641 | sRun << runNumber;
|
|---|
| 642 | std::string fullName = fRunFileName + '/' + sRun.str() + ".log";
|
|---|
| 643 |
|
|---|
| 644 | fRunFile.open(fullName.c_str(), std::ios_base::out | std::ios_base::ate); //maybe should be app instead of ate
|
|---|
| 645 | if (!fRunFile.is_open())
|
|---|
| 646 | {
|
|---|
| 647 | //TODO send an error message
|
|---|
| 648 | return kSM_BadRunConfig;
|
|---|
| 649 | }
|
|---|
| 650 |
|
|---|
| 651 | return kSM_Logging;
|
|---|
| 652 | }
|
|---|
| 653 | /****************************************************************
|
|---|
| 654 | *
|
|---|
| 655 | * DATA LOGGER'S STOP RUN PLEASE
|
|---|
| 656 | *
|
|---|
| 657 | */
|
|---|
| 658 | //! Implements the stop run transition
|
|---|
| 659 | /*
|
|---|
| 660 | ****************************************************************/
|
|---|
| 661 | int DataLogger::StopRunPlease()
|
|---|
| 662 | {
|
|---|
| 663 | if (!fRunFile.is_open())
|
|---|
| 664 | return kSM_FatalError;
|
|---|
| 665 |
|
|---|
| 666 | fRunFile.close();
|
|---|
| 667 |
|
|---|
| 668 | return kSM_WaitingRun;
|
|---|
| 669 |
|
|---|
| 670 | }
|
|---|
| 671 | /****************************************************************
|
|---|
| 672 | *
|
|---|
| 673 | * DATA LOGGER'S RESET PLEASE
|
|---|
| 674 | *
|
|---|
| 675 | */
|
|---|
| 676 | //! Implements the reset transition
|
|---|
| 677 | /*
|
|---|
| 678 | ****************************************************************/
|
|---|
| 679 | int DataLogger::ResetPlease()
|
|---|
| 680 | {
|
|---|
| 681 | if (fDailyFile.is_open())
|
|---|
| 682 | fDailyFile.close();
|
|---|
| 683 |
|
|---|
| 684 | if (fRunFile.is_open())
|
|---|
| 685 | fRunFile.close();
|
|---|
| 686 |
|
|---|
| 687 | return kSM_Ready;
|
|---|
| 688 | }
|
|---|
| 689 | //! Implements the Daily to WaitRun transition
|
|---|
| 690 | int DataLogger::DailyToWaitRunPlease()
|
|---|
| 691 | {
|
|---|
| 692 | return kSM_WaitingRun;
|
|---|
| 693 | }
|
|---|
| 694 | /*
|
|---|
| 695 | bool DataLogger::ServiceOk(DimInfo* item)
|
|---|
| 696 | {
|
|---|
| 697 | return !((item->getSize() == strlen(NO_LINK)+1) && (memcmp(item->getData(), NO_LINK, item->getSize()) == 0));
|
|---|
| 698 | }*/
|
|---|
| 699 | /****************************************************************
|
|---|
| 700 | *
|
|---|
| 701 | * MAIN
|
|---|
| 702 | *
|
|---|
| 703 | ****************************************************************/
|
|---|
| 704 | extern bool CheckDim(bool=true);
|
|---|
| 705 |
|
|---|
| 706 | int main()
|
|---|
| 707 | {
|
|---|
| 708 | std::cout << "Data Logger Starting" << std::endl;
|
|---|
| 709 |
|
|---|
| 710 | if (!CheckDim())
|
|---|
| 711 | return -1;
|
|---|
| 712 |
|
|---|
| 713 | std::cout << "Continuing" << std::endl;
|
|---|
| 714 | DataLogger log;
|
|---|
| 715 | std::cout << "DataLogger created. Starting main loop" << std::endl;
|
|---|
| 716 | while (!log.IsRExitRequested())
|
|---|
| 717 | {
|
|---|
| 718 | usleep(1);
|
|---|
| 719 | }
|
|---|
| 720 | return 0;
|
|---|
| 721 |
|
|---|
| 722 | }
|
|---|