- Timestamp:
- 05/18/11 16:00:41 (14 years ago)
- Location:
- trunk/FACT++/src
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/FACT++/src/Fits.cc
r10725 r10741 35 35 //! @param numDataBytes the number of bytes taken by the variable 36 36 // 37 void Fits::AddStandardColumn(Description& desc, st d::string dataFormat, void* dataPointer, long unsigned int numDataBytes)37 void Fits::AddStandardColumn(Description& desc, string dataFormat, void* dataPointer, long unsigned int numDataBytes) 38 38 { 39 39 //check if entry already exist 40 for ( std::vector<Description>::iterator it=fStandardColDesc.begin(); it != fStandardColDesc.end(); it++)40 for (vector<Description>::iterator it=fStandardColDesc.begin(); it != fStandardColDesc.end(); it++) 41 41 if (it->name == desc.name) 42 42 return; … … 54 54 //! @param numDataBytes the number of bytes taken by the DIM data. 55 55 // 56 void Fits::InitDataColumns( std::vector<Description> desc, std::vector<std::string>& dataFormat, void* dataPointer, int numDataBytes)56 void Fits::InitDataColumns(vector<Description> desc, vector<string>& dataFormat, void* dataPointer, int numDataBytes) 57 57 {//we will copy this information here. It duplicates the data, which is not great, but it is the easiest way of doing it right now 58 58 if (desc.size() == dataFormat.size()) … … 65 65 for (unsigned int i=0;i<dataFormat.size();i++) 66 66 { 67 st d::stringstream stt;67 stringstream stt; 68 68 stt << "Data" << i; 69 69 fDataColDesc.push_back(Description(stt.str(), "comment", "unit")); … … 83 83 //! @param out a pointer to the MessageImp that should be used to log errors 84 84 // 85 void Fits::Open(const st d::string& fileName, const std::string& tableName, FITS* file, int* fitsCounter, MessageImp* out)//std::ostream& out)85 void Fits::Open(const string& fileName, const string& tableName, FITS* file, int* fitsCounter, MessageImp* out)//ostream& out) 86 86 { 87 87 // if (fMess) … … 98 98 catch (CCfits::FitsError e) 99 99 { 100 st d::stringstream str;100 stringstream str; 101 101 str << "Could not open FITS file " << fileName << " reason: " << e.message(); 102 102 fMess->Error(str); … … 115 115 //concatenate the standard and data columns 116 116 //do it the inneficient way first: its easier and faster to code. 117 std::vector<std::string> allNames;118 std::vector<std::string> allDataTypes;119 std::vector<std::string> allUnits;117 vector<string> allNames; 118 vector<string> allDataTypes; 119 vector<string> allUnits; 120 120 fTotalNumBytes = 0; 121 121 for (unsigned int i=0;i<fStandardColDesc.size();i++) … … 133 133 else 134 134 { 135 st d::stringstream stt;135 stringstream stt; 136 136 stt << "Data" << i; 137 137 allNames.push_back(stt.str()); … … 145 145 try 146 146 { 147 st d::string factTableName = "FACT-" + tableName;147 string factTableName = "FACT-" + tableName; 148 148 fTable = fFile->addTable(factTableName, 0, allNames, allDataTypes, allUnits); 149 149 fTable->makeThisCurrent(); … … 159 159 } 160 160 //read the table binary data. 161 std::vector<string> colName;161 vector<string> colName; 162 162 bTable->readData(true, colName); 163 163 164 164 //double check that the data was indeed read from the disk. Go through the fTable instead as colName is empty (yes, it is !) 165 std::map<std::string, Column*> cMap = fTable->column();166 std::map<std::string, Column*>::iterator cMapIt;165 map<string, Column*> cMap = fTable->column(); 166 map<string, Column*>::iterator cMapIt; 167 167 168 168 for (cMapIt = cMap.begin(); cMapIt != cMap.end(); cMapIt++) … … 179 179 catch(CCfits::FitsError e) 180 180 { 181 st d::stringstream str;181 stringstream str; 182 182 str << "Could not open or create FITS table " << tableName << " in file " << fileName << " reason: " << e.message(); 183 183 fMess->Error(str); … … 190 190 WriteHeaderKeys(); 191 191 } 192 // -------------------------------------------------------------------------- 193 // 194 //!This writes a single header key in the currently open file. 195 //!@param name the key 196 //!@param value the key value 197 //!@param a comment explaining the meaning of the key 192 198 template <typename T> 193 199 void Fits::WriteSingleHeaderKey(string name, T value, string comment) … … 199 205 catch (CCfits::FitsError e) 200 206 { 201 st d::stringstream str;207 stringstream str; 202 208 str << "Could not add header keys in file " << fFileName << " reason: " << e.message(); 203 209 fMess->Error(str); … … 212 218 if (!fTable) 213 219 return; 214 std::string name; 215 std::string comment; 216 217 // float floatValue; 218 // double doubleValue; 219 std::string stringValue; 220 string name; 221 string comment; 222 223 string stringValue; 220 224 221 225 WriteSingleHeaderKey("EXTREL", 1.0f, "Release Number"); … … 230 234 WriteSingleHeaderKey("TIMEREF", "UTC", "Time reference frame"); 231 235 WriteSingleHeaderKey("MJDREF", fRefMjD, "Modified Julian Date of origin"); 236 WriteSingleHeaderKey("TSTOP", fEndMjD, "Time of the last receied data"); 232 237 } 233 238 // -------------------------------------------------------------------------- … … 239 244 { 240 245 241 // try242 // {243 246 fTable->makeThisCurrent(); 244 247 int status(0); 245 248 if (fits_insert_rows(fTable->fitsPointer(), fNumRows, 1, &status)) 246 249 { 247 st d::stringstream str;250 stringstream str; 248 251 str << "Could not insert row in file " << fFileName << ". cfitsio error code: " << status; 249 252 fMess->Error(str); 250 253 } 251 // fTable->insertRows(fNumRows);252 // }253 // catch(CCfits::FitsError e)254 // {255 // std::stringstream str;256 // str << "Could not insert row in file " << fFileName << " reason: " << e.message();257 // fMess->Error(str);258 // }259 254 fNumRows++; 260 255 … … 273 268 { 274 269 const char * charSrc = static_cast<char*>(fStandardPointers[i]); 275 276 270 reverse_copy(charSrc, charSrc+fStandardNumBytes[i], &fCopyBuffer[shift]); 277 // for (int j=0; j<fStandardNumBytes[i]; j++)278 // fCopyBuffer[shift+j] = static_cast<char*>(fStandardPointers[i])[fStandardNumBytes[i]-(j+1)];279 271 shift+= fStandardNumBytes[i]; 280 272 } … … 284 276 285 277 //data copied to buffer, can write to fits 286 // int status = 0;287 //TODO check the status after the write operation288 278 fits_write_tblbytes(fFile->fitsPointer(), fNumRows, 1, fTotalNumBytes, fCopyBuffer, &status); 289 279 if (status) … … 291 281 char text[30];//max length of cfitsio error strings (from doc) 292 282 fits_get_errstatus(status, text); 293 st d::stringstream str;283 stringstream str; 294 284 str << "Error while writing FITS row in " << fFileName << ". Message: " << text << " [" << status << "]"; 295 285 fMess->Error(str); 296 286 } 297 //This forces the writting of each row to the disk. Otherwise all rows are written when the file is closed. 298 ///TODO check whether this consumes too much resources or not. If it does, flush every N write operations instead 299 /* try 300 { 301 fFile->flush(); 302 } 303 catch (CCfits::FitsError e) 304 { 305 std::stringstream str; 306 str << "Error while flushing bytes to disk. File: " << fFileName << " reason: " << e.message(); 307 fMess->Error(str); 308 } 309 */} 287 } 310 288 // -------------------------------------------------------------------------- 311 289 // … … 335 313 336 314 // -------------------------------------------------------------------------- 337 // 315 //! Returns the size on the disk of the Fits file being written. 338 316 int Fits::GetWrittenSize() 339 317 { -
trunk/FACT++/src/Fits.h
r10725 r10741 10 10 class MessageImp; 11 11 12 using namespace std; 13 12 14 class Fits 13 15 { 14 16 private: 15 17 ///The CCfits object to the FITS file 16 18 CCfits::FITS* fFile; 17 19 ///Flag indicating whether the FITS object should be managed internally or not. 18 20 bool fOwner; … … 24 26 ///TODO make these variable static so that they are shared by every object. 25 27 ///TODO add also a static boolean to initialize these only once 26 std::vector<Description> fStandardColDesc;28 vector<Description> fStandardColDesc; 27 29 ///Format of the standard columns. 28 std::vector<std::string> fStandardFormats;30 vector<string> fStandardFormats; 29 31 ///the pointers to the standard variables 30 std::vector<void*> fStandardPointers;32 vector<void*> fStandardPointers; 31 33 ///the number of bytes taken by each standard variable 32 std::vector<int> fStandardNumBytes;34 vector<int> fStandardNumBytes; 33 35 ///the vector of data column names 34 std::vector<Description> fDataColDesc;36 vector<Description> fDataColDesc; 35 37 ///the data format of the data columns 36 std::vector<std::string> fDataFormats;38 vector<string> fDataFormats; 37 39 ///the pointer to the contiguous memory location where the data is stored (i.e. the dim data pointer) 38 40 void* fDataPointer; … … 51 53 public: 52 54 ///Name of the openned file. For querying stats 53 st d::string fFileName;55 string fFileName; 54 56 private: 55 57 ///Keep track of number of opened fits … … 83 85 84 86 ///Adds a column that exists in all FITS files 85 void AddStandardColumn(Description& desc, st d::string dataFormat, void* dataPointer, long unsigned int numDataBytes);87 void AddStandardColumn(Description& desc, string dataFormat, void* dataPointer, long unsigned int numDataBytes); 86 88 87 89 ///Adds columns specific to the service being logged. 88 void InitDataColumns( std::vector<Description> desc, std::vector<std::string>& dataFormat, void* dataPointer, int numDataBytes);90 void InitDataColumns(vector<Description> desc, vector<string>& dataFormat, void* dataPointer, int numDataBytes); 89 91 90 92 ///Opens a FITS file 91 void Open(const st d::string& fileName, const std::string& tableName, CCfits::FITS* file, int* fitsCounter, MessageImp* out);//std::ostream& out);93 void Open(const string& fileName, const string& tableName, CCfits::FITS* file, int* fitsCounter, MessageImp* out);//ostream& out); 92 94 93 95 ///Write one line of data. Use the given converter. -
trunk/FACT++/src/dataLogger.cc
r10739 r10741 11 11 \dot 12 12 digraph datalogger { 13 14 13 node [shape=record, fontname=Helvetica, fontsize=10]; 14 e [label="Error" color="red"]; 15 15 r [label="Ready"] 16 16 d [label="NightlyOpen"] 17 17 w [label="WaitingRun"] 18 18 l [label="Logging"] 19 19 b [label="BadNightlyconfig" color="red"] 20 20 c [label="BadRunConfig" color="red"] … … 37 37 } 38 38 \enddot 39 40 @todo41 - Retrieve also the messages, not only the infos42 39 */ 43 40 //**************************************************************** … … 82 79 //Dim structures 83 80 struct DataLoggerStats { 84 85 86 81 long sizeWritten; 82 long freeSpace; 83 long writingRate; 87 84 }; 88 85 89 86 struct NumSubAndFitsType { 90 91 87 int numSubscriptions; 88 int numOpenFits; 92 89 }; 93 90 94 91 struct OpenFileToDim { 95 96 92 int code; 93 char fileName[FILENAME_MAX]; 97 94 }; 98 //For debugging DIM's services 99 class MyService95 96 class DataLogger : public StateMachineDim, DimInfoHandler 100 97 { 101 98 public: 102 MyService(){}; 103 MyService(std::string, std::string, void*, int){}; 104 MyService(std::string, const char*){}; 105 void updateService(){}; 106 void updateService(void*, int){}; 107 void setQuality(int){}; 108 }; 109 class DataLogger : public StateMachineDim, DimInfoHandler 110 { 99 /// The list of existing states specific to the DataLogger 100 enum 101 { 102 kSM_NightlyOpen = 20, ///< Nightly file openned and writing 103 kSM_WaitingRun = 30, ///< waiting for the run number to open the run file 104 kSM_Logging = 40, ///< both files openned and writing 105 kSM_BadNightlyConfig = 0x101, ///< the folder specified for Nightly logging does not exist or has bad permissions 106 kSM_BadRunConfig = 0x102, ///< the folder specified for the run logging does not exist or has wrong permissions or no run number 107 } localstates_t; 108 109 DataLogger(ostream &out); 110 ~DataLogger(); 111 112 private: 113 //Define all the data structure specific to the DataLogger here 114 /// ofstream for the NightlyLogfile 115 ofstream fNightlyLogFile; 116 /// ofstream for the run-specific Log file 117 ofstream fRunLogFile; 118 119 /// ofstream for the Nightly report file 120 ofstream fNightlyReportFile; 121 /// ofstream for the run-specific report file 122 ofstream fRunReportFile; 123 /// base path of the Nightlyfile 124 string fNightlyFileName; 125 ///base path of the run file 126 string fRunFileName; 127 ///run number (-1 means no run number specified) 128 int fRunNumber; 129 ///previous run number. to check if changed while logging 130 int fPreviousRunNumber; 131 ///Current Service Quality 132 int fQuality; 133 ///Modified Julian Date 134 double fMjD; 111 135 public: 112 /// The list of existing states specific to the DataLogger 113 enum 114 { 115 kSM_NightlyOpen = 20, ///< Nightly file openned and writing 116 kSM_WaitingRun = 30, ///< waiting for the run number to open the run file 117 kSM_Logging = 40, ///< both files openned and writing 118 kSM_BadNightlyConfig = 0x101, ///< the folder specified for Nightly logging does not exist or has bad permissions 119 kSM_BadRunConfig = 0x102, ///< the folder specified for the run logging does not exist or has wrong permissions or no run number 120 } localstates_t; 121 122 DataLogger(std::ostream &out); 123 ~DataLogger(); 124 136 ///Define all the static names 137 static const char* fConfigDay; 138 static const char* fConfigRun; 139 static const char* fConfigRunNumber; 140 static const char* fConfigLog; 141 static const char* fTransStart; 142 static const char* fTransStop; 143 static const char* fTransStartRun; 144 static const char* fTransStopRun; 145 static const char* fTransReset; 146 static const char* fTransWait; 147 static const char* fRunNumberInfo; ///< This is the name of the dimInfo received to specify the run number. It must be updated once the final name will be defined 148 static const char* fPrintCommand; 149 static const char* fDebugOnOff; 150 static const char* fStatsPeriod; 151 static const char* fStartStopOpenedFiles; 152 static const char* fStartStopNumSubsAndFits; 125 153 private: 126 //Define all the data structure specific to the DataLogger here 127 /// ofstream for the NightlyLogfile 128 std::ofstream fNightlyLogFile; 129 /// ofstream for the run-specific Log file 130 std::ofstream fRunLogFile; 131 132 /// ofstream for the Nightly report file 133 std::ofstream fNightlyReportFile; 134 /// ofstream for the run-specific report file 135 std::ofstream fRunReportFile; 136 /// base path of the Nightlyfile 137 std::string fNightlyFileName; 138 ///base path of the run file 139 std::string fRunFileName; 140 ///run number (-1 means no run number specified) 141 int fRunNumber; 142 ///previous run number. to check if changed while logging 143 int fPreviousRunNumber; 144 ///Current Service Quality 145 int fQuality; 146 ///Modified Julian Date 147 double fMjD; 148 public: 149 ///Define all the static names 150 static const char* fConfigDay; 151 static const char* fConfigRun; 152 static const char* fConfigRunNumber; 153 static const char* fConfigLog; 154 static const char* fTransStart; 155 static const char* fTransStop; 156 static const char* fTransStartRun; 157 static const char* fTransStopRun; 158 static const char* fTransReset; 159 static const char* fTransWait; 160 static const char* fRunNumberInfo; ///< This is the name of the dimInfo received to specify the run number. It must be updated once the final name will be defined 161 static const char* fPrintCommand; 162 static const char* fDebugOnOff; 163 static const char* fStatsPeriod; 164 static const char* fStartStopOpenedFiles; 165 static const char* fStartStopNumSubsAndFits; 154 //overloading of DIM's infoHandler function 155 void infoHandler(); 156 157 ///for obtaining the name of the existing services 158 ServiceList fServiceList; 159 160 ///A std pair to store both the DimInfo pointer and the corresponding outputted fits file 161 struct SubscriptionType 162 { 163 #ifdef HAVE_FITS 164 ///Nightly FITS output file 165 Fits nightlyFile; 166 ///run-specific FITS output file 167 Fits runFile; 168 #endif 169 ///the actual dimInfo pointer 170 DimStampedInfo* dimInfo; 171 ///the converter for outputting the data according to the format 172 Converter* fConv; 173 ///the number of existing handlers to this structure. 174 ///This is required otherwise I MUST handle the deleting of dimInfo outside from the destructor 175 int* numCopies; 176 void operator = (const SubscriptionType& other) 177 { 178 #ifdef HAVE_FITS 179 nightlyFile = other.nightlyFile; 180 runFile = other.runFile; 181 #endif 182 dimInfo = other.dimInfo; 183 numCopies = other.numCopies; 184 fConv = other.fConv; 185 (*numCopies)++; 186 } 187 SubscriptionType(const SubscriptionType& other) 188 { 189 #ifdef HAVE_FITS 190 nightlyFile = other.nightlyFile; 191 runFile = other.runFile; 192 #endif 193 dimInfo = other.dimInfo; 194 numCopies = other.numCopies; 195 fConv = other.fConv; 196 (*numCopies)++; 197 } 198 SubscriptionType(DimStampedInfo* info) 199 { 200 dimInfo = info; 201 fConv = NULL; 202 numCopies = new int(1); 203 } 204 SubscriptionType() 205 { 206 dimInfo = NULL; 207 fConv = NULL; 208 numCopies = new int(1); 209 } 210 ~SubscriptionType() 211 { 212 if (numCopies) 213 (*numCopies)--; 214 if (numCopies) 215 if (*numCopies < 1) 216 { 217 if (dimInfo) 218 delete dimInfo; 219 #ifdef HAVE_FITS 220 if (nightlyFile.IsOpen()) 221 nightlyFile.Close(); 222 if (runFile.IsOpen()) 223 runFile.Close(); 224 #endif 225 if (numCopies) 226 delete numCopies; 227 delete fConv; 228 fConv = NULL; 229 dimInfo = NULL; 230 numCopies = NULL; 231 } 232 } 233 }; 234 typedef map<const string, map<string, SubscriptionType> > SubscriptionsListType; 235 ///All the services to which we have subscribed to, sorted by server name. 236 SubscriptionsListType fServiceSubscriptions; 237 238 ///Reporting method for the services info received 239 void ReportPlease(DimInfo* I, SubscriptionType& sub); 240 241 ///Configuration of the nightly file path 242 int ConfigureNightlyFileName(const Event& evt); 243 ///Configuration fo the file name 244 int ConfigureRunFileName(const Event& evt); 245 ///DEPREC - configuration of the run number 246 int ConfigureRunNumber(const Event& evt); 247 ///logging method for the messages 248 int LogMessagePlease(const Event& evt); 249 ///print the current state of the dataLogger 250 int PrintStatePlease(const Event& evt); 251 ///checks whether or not the current info being treated is a run number 252 void CheckForRunNumber(DimInfo* I); 253 /// start transition 254 int StartPlease(); 255 ///from waiting to logging transition 256 int StartRunPlease(); 257 /// from logging to waiting transition 258 int StopRunPlease(); 259 ///stop and reset transition 260 int GoToReadyPlease(); 261 ///from NightlyOpen to waiting transition 262 int NightlyToWaitRunPlease(); 263 #ifdef HAVE_FITS 264 ///Open fits files 265 void OpenFITSFilesPlease(SubscriptionType& sub); 266 ///Write data to FITS files 267 void WriteToFITS(SubscriptionType& sub); 268 ///Allocate the buffers required for fits 269 void AllocateFITSBuffers(SubscriptionType& sub); 270 ///FITS file for runs grouping. only one, hence dealt with in the dataLogger itself 271 CCfits::FITS* fRunFitsFile; 272 #endif//has_fits 273 public: 274 ///checks with fServiceList whether or not the services got updated 275 bool CheckForServicesUpdate(); 276 277 private: 278 ///monitoring notification loop 279 void ServicesMonitoring(); 280 ///services notification thread 281 boost::thread fMonitoringThread; 282 ///end of the monitoring 283 bool fContinueMonitoring; 284 ///required for accurate monitoring 285 map<string, long> fFileSizesMap; 286 string fFullNightlyLogFileName; 287 string fFullNightlyReportFileName; 288 string fFullRunLogFileName; 289 string fFullRunReportFileName; 290 long fBaseSizeNightly; 291 long fPreviousSize; 292 long fBaseSizeRun; 293 ///Service for opened files 294 DimDescribedService* fOpenedNightlyFiles; 295 DimDescribedService* fOpenedRunFiles; 296 DimDescribedService* fNumSubAndFits; 297 NumSubAndFitsType fNumSubAndFitsData; 298 299 inline void NotifyOpenedFile(string name, int type, DimDescribedService* service); 300 301 public: 302 bool SetConfiguration(Configuration& conf); 303 166 304 private: 167 //overloading of DIM's infoHandler function 168 void infoHandler(); 169 170 ///for obtaining the name of the existing services 171 ServiceList fServiceList; 172 173 ///A std pair to store both the DimInfo pointer and the corresponding outputted fits file 174 struct SubscriptionType 175 { 305 set<string> fBlackList; 306 set<string> fWhiteList; 307 set<string> fGrouping; 308 bool fHasBlackList; 309 bool fHasWhiteList; 310 bool fDebugIsOn; 311 float fStatsPeriodDuration; 312 bool fOpenedFilesIsOn; 313 bool fNumSubAndFitsIsOn; 314 //functions for controlling the services behavior 315 int SetDebugOnOff(const Event& evt); 316 int SetStatsPeriod(const Event& evt); 317 int SetOpenedFilesOnOff(const Event& evt); 318 int SetNumSubsAndFitsOnOff(const Event& evt); 319 ///boolean to prevent DIM update while desctructing the dataLogger 320 bool fDestructing; 321 322 ///Small function for calculating the total size written so far 323 void calculateTotalSizeWritten(DataLoggerStats& statVar, bool& shouldWarn, bool isPrinting); 324 325 ///vectors to keep track of opened Fits files, for grouping purposes. 326 //This cannot be done otherwise, as services may disapear before the files are nicely closed. Hence which files were opened must be remembered. 327 map<string, vector<string> > fOpenedRunFits; 328 map<string, vector<string> > fOpenedNightlyFits; 329 void CreateFitsGrouping(bool runGroup); 330 }; //DataLogger 331 332 void DataLogger::calculateTotalSizeWritten(DataLoggerStats& statVar, bool& shouldWarn, bool isPrinting) 333 { 176 334 #ifdef HAVE_FITS 177 ///Nightly FITS output file 178 Fits nightlyFile; 179 ///run-specific FITS output file 180 Fits runFile; 335 if (isPrinting) 336 { 337 stringstream str; 338 str.str(""); 339 str << "There are " << fNumSubAndFitsData.numOpenFits << " FITS files open:"; 340 Message(str.str()); 341 } 342 SubscriptionsListType::iterator x; 343 map<string, SubscriptionType>::iterator y; 344 ///TODO the grouping file is dealt with several times. This should not be a problem but well, better to fix it I guess. 345 for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++) 346 { 347 for (y=x->second.begin(); y != x->second.end(); y++) 348 { 349 if (y->second.runFile.IsOpen()) 350 { 351 fFileSizesMap[y->second.runFile.fFileName] = y->second.runFile.GetWrittenSize(); 352 if (isPrinting) 353 Message("-> "+y->second.runFile.fFileName); 354 } 355 if (y->second.nightlyFile.IsOpen()) 356 { 357 fFileSizesMap[y->second.nightlyFile.fFileName] = y->second.nightlyFile.GetWrittenSize(); 358 if (isPrinting) 359 Message("-> "+y->second.nightlyFile.fFileName); 360 } 361 } 362 } 363 #else 364 if (isPrinting) 365 Message("FITS output disabled at compilation"); 181 366 #endif 182 ///the actual dimInfo pointer 183 DimStampedInfo* dimInfo; 184 ///the converter for outputting the data according to the format 185 Converter* fConv; 186 ///the number of existing handlers to this structure. 187 ///This is required otherwise I MUST handle the deleting of dimInfo outside from the destructor 188 int* numCopies; 189 void operator = (const SubscriptionType& other) 190 { 191 #ifdef HAVE_FITS 192 nightlyFile = other.nightlyFile; 193 runFile = other.runFile; 194 #endif 195 dimInfo = other.dimInfo; 196 numCopies = other.numCopies; 197 fConv = other.fConv; 198 (*numCopies)++; 199 } 200 SubscriptionType(const SubscriptionType& other) 201 { 202 #ifdef HAVE_FITS 203 nightlyFile = other.nightlyFile; 204 runFile = other.runFile; 205 #endif 206 dimInfo = other.dimInfo; 207 numCopies = other.numCopies; 208 fConv = other.fConv; 209 (*numCopies)++; 210 } 211 SubscriptionType(DimStampedInfo* info) 212 { 213 dimInfo = info; 214 fConv = NULL; 215 numCopies = new int(1); 216 } 217 SubscriptionType() 218 { 219 dimInfo = NULL; 220 fConv = NULL; 221 numCopies = new int(1); 222 } 223 ~SubscriptionType() 224 { 225 if (numCopies) 226 (*numCopies)--; 227 if (numCopies) 228 if (*numCopies < 1) 229 { 230 if (dimInfo) 231 delete dimInfo; 232 #ifdef HAVE_FITS 233 if (nightlyFile.IsOpen()) 234 nightlyFile.Close(); 235 if (runFile.IsOpen()) 236 runFile.Close(); 237 #endif 238 if (numCopies) 239 delete numCopies; 240 delete fConv; 241 fConv = NULL; 242 dimInfo = NULL; 243 numCopies = NULL; 244 } 245 } 246 }; 247 typedef std::map<const std::string, std::map<std::string, SubscriptionType>> SubscriptionsListType; 248 ///All the services to which we have subscribed to, sorted by server name. 249 SubscriptionsListType fServiceSubscriptions; 250 251 ///Reporting method for the services info received 252 void ReportPlease(DimInfo* I, SubscriptionType& sub); 253 254 ///Configuration of the nightly file path 255 int ConfigureNightlyFileName(const Event& evt); 256 ///Configuration fo the file name 257 int ConfigureRunFileName(const Event& evt); 258 ///DEPREC - configuration of the run number 259 int ConfigureRunNumber(const Event& evt); 260 ///logging method for the messages 261 int LogMessagePlease(const Event& evt); 262 ///print the current state of the dataLogger 263 int PrintStatePlease(const Event& evt); 264 ///checks whether or not the current info being treated is a run number 265 void CheckForRunNumber(DimInfo* I); 266 /// start transition 267 int StartPlease(); 268 ///from waiting to logging transition 269 int StartRunPlease(); 270 /// from logging to waiting transition 271 int StopRunPlease(); 272 ///stop and reset transition 273 int GoToReadyPlease(); 274 ///from NightlyOpen to waiting transition 275 int NightlyToWaitRunPlease(); 276 #ifdef HAVE_FITS 277 ///Open fits files 278 void OpenFITSFilesPlease(SubscriptionType& sub); 279 ///Write data to FITS files 280 void WriteToFITS(SubscriptionType& sub); 281 ///Allocate the buffers required for fits 282 void AllocateFITSBuffers(SubscriptionType& sub); 283 284 #ifdef ONE_RUN_FITS_ONLY 285 ///FITS file for runs. only one, hence dealt with in the dataLogger itself 286 CCfits::FITS* fRunFitsFile; 287 #endif //one_run_fits_only 288 #endif//has_fits 289 public: 290 ///checks with fServiceList whether or not the services got updated 291 bool CheckForServicesUpdate(); 292 293 private: 294 ///monitoring notification loop 295 void ServicesMonitoring(); 296 ///services notification thread 297 boost::thread fMonitoringThread; 298 ///end of the monitoring 299 bool fContinueMonitoring; 300 ///required for accurate monitoring 301 std::map<std::string, long> fFileSizesMap; 302 std::string fFullNightlyLogFileName; 303 std::string fFullNightlyReportFileName; 304 std::string fFullRunLogFileName; 305 std::string fFullRunReportFileName; 306 long fBaseSizeNightly; 307 long fPreviousSize; 308 long fBaseSizeRun; 309 ///Service for opened files 310 DimDescribedService* fOpenedNightlyFiles; 311 DimDescribedService* fOpenedRunFiles; 312 DimDescribedService* fNumSubAndFits; 313 NumSubAndFitsType fNumSubAndFitsData; 314 315 inline void NotifyOpenedFile(std::string name, int type, DimDescribedService* service); 316 317 public: 318 bool SetConfiguration(Configuration& conf); 319 320 private: 321 std::set<std::string> fBlackList; 322 std::set<std::string> fWhiteList; 323 bool fHasBlackList; 324 bool fHasWhiteList; 325 bool fDebugIsOn; 326 float fStatsPeriodDuration; 327 bool fOpenedFilesIsOn; 328 bool fNumSubAndFitsIsOn; 329 //functions for controlling the services behavior 330 int SetDebugOnOff(const Event& evt); 331 int SetStatsPeriod(const Event& evt); 332 int SetOpenedFilesOnOff(const Event& evt); 333 int SetNumSubsAndFitsOnOff(const Event& evt); 334 ///boolean to prevent DIM update while desctructing the dataLogger 335 bool fDestructing; 336 337 ///Small function for calculating the total size written so far 338 void calculateTotalSizeWritten(DataLoggerStats& statVar, bool& shouldWarn, bool isPrinting); 339 340 ///vectors to keep track of opened Fits files, for grouping purposes. 341 //This cannot be done otherwise, as services may disapear before the files are nicely closed. Hence which files were opened must be remembered. 342 map<string, string> fOpenedRunFits; 343 map<string, string> fOpenedNightlyFits; 344 void CreateFitsGrouping(bool runGroup); 345 }; //DataLogger 346 347 void DataLogger::calculateTotalSizeWritten(DataLoggerStats& statVar, bool& shouldWarn, bool isPrinting) 348 { 349 #ifdef HAVE_FITS 350 if (isPrinting) 351 { 352 stringstream str; 353 str.str(""); 354 str << "There are " << fNumSubAndFitsData.numOpenFits << " FITS files open:"; 355 Message(str.str()); 356 } 357 SubscriptionsListType::iterator x; 358 std::map<std::string, SubscriptionType>::iterator y; 359 bool runFileDone = false; 360 for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++) 361 { 362 for (y=x->second.begin(); y != x->second.end(); y++) 363 { 364 if (y->second.runFile.IsOpen() && !runFileDone) 365 { 366 fFileSizesMap[y->second.runFile.fFileName] = y->second.runFile.GetWrittenSize(); 367 if (isPrinting) 368 Message("-> "+y->second.runFile.fFileName); 369 #ifdef ONE_FITS_ONLY 370 runFileDone = true; 371 #endif 372 } 373 if (y->second.nightlyFile.IsOpen()) 374 { 375 fFileSizesMap[y->second.nightlyFile.fFileName] = y->second.nightlyFile.GetWrittenSize(); 376 if (isPrinting) 377 Message("-> "+y->second.nightlyFile.fFileName); 378 } 379 } 380 } 381 #else 382 if (isPrinting) 383 Message("FITS output disabled at compilation"); 384 #endif 385 struct stat st; 386 //gather log and report files sizes on disk 387 if (fNightlyLogFile.is_open()) 388 { 389 stat(fFullNightlyLogFileName.c_str(), &st); 390 fFileSizesMap[fFullNightlyLogFileName] = st.st_size; 391 } 392 if (fNightlyReportFile.is_open()) 393 { 394 stat(fFullNightlyReportFileName.c_str(), &st); 395 fFileSizesMap[fFullNightlyReportFileName] = st.st_size; 396 } 397 if (fRunLogFile.is_open()) 398 { 399 stat(fFullRunLogFileName.c_str(), &st); 400 fFileSizesMap[fFullRunLogFileName] = st.st_size; 401 } 402 if (fRunReportFile.is_open()) 403 { 404 stat(fFullRunReportFileName.c_str(), &st); 405 fFileSizesMap[fFullRunReportFileName] = st.st_size; 406 } 407 struct statvfs vfs; 408 if (!statvfs(fNightlyFileName.c_str(), &vfs)) 409 { 410 statVar.freeSpace = vfs.f_bsize*vfs.f_bavail; 411 shouldWarn = false; 412 } 413 else 414 { 415 stringstream str; 416 str.str(""); 417 str << "Unable to retrieve stats for " << fNightlyFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 418 if (!shouldWarn) 419 Error(str); 420 shouldWarn = true; 421 statVar.freeSpace = -1; 422 } 423 //sum up all the file sizes. past and present 424 statVar.sizeWritten = 0; 425 for (std::map<std::string, long>::iterator it=fFileSizesMap.begin(); it != fFileSizesMap.end(); it++) 426 statVar.sizeWritten += it->second; 427 statVar.sizeWritten -= fBaseSizeNightly; 428 statVar.sizeWritten -= fBaseSizeRun; 367 struct stat st; 368 //gather log and report files sizes on disk 369 if (fNightlyLogFile.is_open()) 370 { 371 stat(fFullNightlyLogFileName.c_str(), &st); 372 fFileSizesMap[fFullNightlyLogFileName] = st.st_size; 373 } 374 if (fNightlyReportFile.is_open()) 375 { 376 stat(fFullNightlyReportFileName.c_str(), &st); 377 fFileSizesMap[fFullNightlyReportFileName] = st.st_size; 378 } 379 if (fRunLogFile.is_open()) 380 { 381 stat(fFullRunLogFileName.c_str(), &st); 382 fFileSizesMap[fFullRunLogFileName] = st.st_size; 383 } 384 if (fRunReportFile.is_open()) 385 { 386 stat(fFullRunReportFileName.c_str(), &st); 387 fFileSizesMap[fFullRunReportFileName] = st.st_size; 388 } 389 struct statvfs vfs; 390 if (!statvfs(fNightlyFileName.c_str(), &vfs)) 391 { 392 statVar.freeSpace = vfs.f_bsize*vfs.f_bavail; 393 shouldWarn = false; 394 } 395 else 396 { 397 stringstream str; 398 str.str(""); 399 str << "Unable to retrieve stats for " << fNightlyFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 400 if (!shouldWarn) 401 Error(str); 402 shouldWarn = true; 403 statVar.freeSpace = -1; 404 } 405 //sum up all the file sizes. past and present 406 statVar.sizeWritten = 0; 407 for (map<string, long>::iterator it=fFileSizesMap.begin(); it != fFileSizesMap.end(); it++) 408 statVar.sizeWritten += it->second; 409 statVar.sizeWritten -= fBaseSizeNightly; 410 statVar.sizeWritten -= fBaseSizeRun; 429 411 } 430 412 //static members initialization … … 449 431 void DataLogger::ServicesMonitoring() 450 432 { 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 433 DataLoggerStats statVar; 434 statVar.sizeWritten = 0; 435 statVar.freeSpace = 0; 436 statVar.writingRate = 0; 437 438 struct statvfs vfs; 439 if (!statvfs(fNightlyFileName.c_str(), &vfs)) 440 statVar.freeSpace = vfs.f_bsize*vfs.f_bavail; 441 else 442 statVar.freeSpace = -1; 443 444 DimDescribedService srvc ("DATA_LOGGER/STATS", "X:3", statVar, "Add description here"); 445 fPreviousSize = 0; 446 bool statWarning = false; 447 //loop-wait for broadcast 448 while (fContinueMonitoring) 449 { 450 if (fStatsPeriodDuration == 0.0f) 451 { 452 sleep(0.1f); 453 continue; 454 } 455 else 456 sleep(fStatsPeriodDuration); 457 //update the fits files sizes 458 calculateTotalSizeWritten(statVar, statWarning, false); 459 if (fStatsPeriodDuration == 0.0f) 460 continue; 461 statVar.writingRate = (statVar.sizeWritten - fPreviousSize)/fStatsPeriodDuration; 462 463 fPreviousSize = statVar.sizeWritten; 464 if (statVar.writingRate != 0) //if data has been written 465 { 466 srvc.updateService(); 467 if(fDebugIsOn) 468 { 469 stringstream str; 470 str << "Size written: " << statVar.sizeWritten/1024 << " KB; writting rate: "; 471 str << statVar.writingRate/1024 << " KB/s; free space: "; 472 str << statVar.freeSpace/(1024*1024) << " MB"; 473 Debug(str.str()); 474 } 475 } 476 } 495 477 } 496 478 … … 503 485 //!Setup the allows states, configs and transitions for the data logger 504 486 // 505 DataLogger::DataLogger( std::ostream &out) : StateMachineDim(out, "DATA_LOGGER")487 DataLogger::DataLogger(ostream &out) : StateMachineDim(out, "DATA_LOGGER") 506 488 { 507 489 dic_disable_padding(); 508 490 dis_disable_padding(); 509 510 511 512 513 491 //initialize member data 492 fNightlyFileName = "."; 493 fRunFileName = "."; 494 fRunNumber = -1; 495 fPreviousRunNumber = fRunNumber; 514 496 #ifdef HAVE_FITS 515 #ifdef ONE_RUN_FITS_ONLY 516 fRunFitsFile = NULL; 497 fRunFitsFile = NULL; 517 498 #endif 518 #endif 519 520 //Give a name to this machine's specific states 521 AddStateName(kSM_NightlyOpen, "NightlyFileOpen", "The summary files for the night are open."); 522 AddStateName(kSM_WaitingRun, "WaitForRun", "The summary files for the night are open and we wait for a run to be started."); 523 AddStateName(kSM_Logging, "Logging", "The summary files for the night and the files for a single run are open."); 524 AddStateName(kSM_BadNightlyConfig, "ErrNightlyFolder", "The folder for the nighly summary files is invalid."); 525 AddStateName(kSM_BadRunConfig, "ErrRunFolder", "The folder for the run files is invalid."); 526 527 /*Add the possible transitions for this machine*/ 528 AddEvent(kSM_NightlyOpen, fTransStart, kSM_Ready, kSM_BadNightlyConfig) 529 (boost::bind(&DataLogger::StartPlease, this)) 530 ("Start the nightly logging. Nightly file location must be specified already"); 531 532 AddEvent(kSM_Ready, fTransStop, kSM_NightlyOpen, kSM_WaitingRun, kSM_Logging) 533 (boost::bind(&DataLogger::GoToReadyPlease, this)) 534 ("Stop all data logging, close all files."); 535 536 AddEvent(kSM_Logging, fTransStartRun, kSM_WaitingRun, kSM_BadRunConfig) 537 (boost::bind(&DataLogger::StartRunPlease, this)) 538 ("Start the run logging. Run file location must be specified already."); 539 540 AddEvent(kSM_WaitingRun, fTransStopRun, kSM_Logging) 541 (boost::bind(&DataLogger::StopRunPlease, this)) 542 ("Wait for a run to be started, open run-files as soon as a run number arrives."); 543 544 AddEvent(kSM_Ready, fTransReset, kSM_Error, kSM_BadNightlyConfig, kSM_BadRunConfig, kSM_Error) 545 (boost::bind(&DataLogger::GoToReadyPlease, this)) 546 ("Transition to exit error states. Closes the nightly file if already opened."); 547 548 AddEvent(kSM_WaitingRun, fTransWait, kSM_NightlyOpen) 549 (boost::bind(&DataLogger::NightlyToWaitRunPlease, this)); 550 551 /*Add the possible configurations for this machine*/ 552 AddEvent(fConfigDay, "C", kSM_Ready, kSM_BadNightlyConfig) 553 (boost::bind(&DataLogger::ConfigureNightlyFileName, this, _1)) 554 ("Configure the folder for the nightly files." 555 "|Path[string]:Absolute or relative path name where the nightly files should be stored."); 556 557 AddEvent(fConfigRun, "C", kSM_Ready, kSM_BadNightlyConfig, kSM_NightlyOpen, kSM_WaitingRun, kSM_BadRunConfig) 558 (boost::bind(&DataLogger::ConfigureRunFileName, this, _1)) 559 ("Configure the folder for the run files." 560 "|Path[string]:Absolute or relative path name where the run files should be stored."); 561 562 AddEvent(fConfigRunNumber, "I", kSM_Ready, kSM_BadNightlyConfig, kSM_NightlyOpen, kSM_WaitingRun, kSM_BadRunConfig) 563 (boost::bind(&DataLogger::ConfigureRunNumber, this, _1)) 564 ("configure the run number. cannot be done in logging state"); 565 566 //Provide a logging command 567 //I get the feeling that I should be going through the EventImp 568 //instead of DimCommand directly, mainly because the commandHandler 569 //is already done in StateMachineImp.cc 570 //Thus I'll simply add a configuration, which I will treat as the logging command 571 AddEvent(fConfigLog, "C", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_BadRunConfig) 572 (boost::bind(&DataLogger::LogMessagePlease, this, _1)) 573 ("Log a single message to the log-files." 574 "|Message[string]:Message to be logged."); 575 576 //Provide a print command 577 stringstream str; 578 str << kSM_Ready << " " << kSM_NightlyOpen << " " << kSM_WaitingRun << " " << kSM_Logging << " " << kSM_BadNightlyConfig; 579 str << " " << kSM_BadRunConfig; 580 581 AddEvent(fPrintCommand, str.str().c_str(), "") 582 // AddEvent(fPrintCommand, kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_BadNightlyConfig, kSM_BadRunConfig) 583 (boost::bind(&DataLogger::PrintStatePlease, this, _1)) 584 ("Print information about the internal status of the data logger."); 585 586 fServiceList.SetHandler(this); 587 CheckForServicesUpdate(); 588 589 //start the monitoring service 590 fContinueMonitoring = true; 591 fMonitoringThread = boost::thread(boost::bind(&DataLogger::ServicesMonitoring, this)); 592 fBaseSizeNightly = 0; 593 fBaseSizeRun = 0; 594 OpenFileToDim fToDim; 595 fToDim.code = 0; 596 fToDim.fileName[0] = '\0'; 597 598 fOpenedNightlyFiles = new DimDescribedService(GetName() + "/FILENAME_NIGHTLY", "I:1;C", fToDim, 599 "Path and base name which is used to compile the filenames for the nightly files." 600 "|Type[int]:type of open files (1=log, 2=rep, 4=fits)" 601 "|Name[string]:path and base file name"); 602 603 fOpenedRunFiles = new DimDescribedService(GetName() + "/FILENAME_RUN", "I:1;C", fToDim, 604 "Path and base name which is used to compile the filenames for the run files." 605 "|Type[int]:type of open files (1=log, 2=rep, 4=fits)" 606 "|Name[string]:path and base file name"); 607 608 fNumSubAndFitsData.numSubscriptions = 0; 609 fNumSubAndFitsData.numOpenFits = 0; 610 fNumSubAndFits = new DimDescribedService(GetName() + "/NUM_SUBS", "I:2", fNumSubAndFitsData, 611 "Shows number of services to which the data logger is currently subscribed and the total number of open files." 612 "|Subscriptions[int]:number of dim services to which the data logger is currently subscribed." 613 "|NumOpenFiles[int]:number of files currently open by the data logger"); 614 615 //black/white list 616 fHasBlackList = false; 617 fHasWhiteList = false; 618 fBlackList.clear(); 619 fWhiteList.clear(); 620 //services parameters 621 fDebugIsOn = false; 622 fStatsPeriodDuration = 1.0f; 623 fOpenedFilesIsOn = true; 624 fNumSubAndFitsIsOn = true; 625 626 //provide services control commands 627 AddEvent(fDebugOnOff, "B:1", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready) 628 (boost::bind(&DataLogger::SetDebugOnOff, this, _1)) 629 ("Switch debug mode on off. Debug mode prints ifnormation about every service written to a file." 630 "|Enable[bool]:Enable of disable debuig mode (yes/no)."); 631 632 AddEvent(fStatsPeriod, "F", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready) 633 (boost::bind(&DataLogger::SetStatsPeriod, this, _1)) 634 ("Interval in which the data-logger statitistics service (STATS) is updated." 635 "Interval[s]:Floating point value in seconds."); 636 637 AddEvent(fStartStopOpenedFiles, "B:1", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready) 638 (boost::bind(&DataLogger::SetOpenedFilesOnOff ,this, _1)) 639 ("Can be used to switch the service off which distributes information about the open files."); 640 641 AddEvent(fStartStopNumSubsAndFits, "B:1", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready) 642 (boost::bind(&DataLogger::SetNumSubsAndFitsOnOff, this, _1)) 643 ("Can be used to switch the service off which distributes information about the number of subscriptions and open files."); 644 645 fDestructing = false; 646 if(fDebugIsOn) 647 { 648 Debug("DataLogger Init Done."); 649 } 499 500 //Give a name to this machine's specific states 501 AddStateName(kSM_NightlyOpen, "NightlyFileOpen", "The summary files for the night are open."); 502 AddStateName(kSM_WaitingRun, "WaitForRun", "The summary files for the night are open and we wait for a run to be started."); 503 AddStateName(kSM_Logging, "Logging", "The summary files for the night and the files for a single run are open."); 504 AddStateName(kSM_BadNightlyConfig, "ErrNightlyFolder", "The folder for the nighly summary files is invalid."); 505 AddStateName(kSM_BadRunConfig, "ErrRunFolder", "The folder for the run files is invalid."); 506 507 /*Add the possible transitions for this machine*/ 508 AddEvent(kSM_NightlyOpen, fTransStart, kSM_Ready, kSM_BadNightlyConfig) 509 (boost::bind(&DataLogger::StartPlease, this)) 510 ("Start the nightly logging. Nightly file location must be specified already"); 511 512 AddEvent(kSM_Ready, fTransStop, kSM_NightlyOpen, kSM_WaitingRun, kSM_Logging) 513 (boost::bind(&DataLogger::GoToReadyPlease, this)) 514 ("Stop all data logging, close all files."); 515 516 AddEvent(kSM_Logging, fTransStartRun, kSM_WaitingRun, kSM_BadRunConfig) 517 (boost::bind(&DataLogger::StartRunPlease, this)) 518 ("Start the run logging. Run file location must be specified already."); 519 520 AddEvent(kSM_WaitingRun, fTransStopRun, kSM_Logging) 521 (boost::bind(&DataLogger::StopRunPlease, this)) 522 ("Wait for a run to be started, open run-files as soon as a run number arrives."); 523 524 AddEvent(kSM_Ready, fTransReset, kSM_Error, kSM_BadNightlyConfig, kSM_BadRunConfig, kSM_Error) 525 (boost::bind(&DataLogger::GoToReadyPlease, this)) 526 ("Transition to exit error states. Closes the nightly file if already opened."); 527 528 AddEvent(kSM_WaitingRun, fTransWait, kSM_NightlyOpen) 529 (boost::bind(&DataLogger::NightlyToWaitRunPlease, this)); 530 531 /*Add the possible configurations for this machine*/ 532 AddEvent(fConfigDay, "C", kSM_Ready, kSM_BadNightlyConfig) 533 (boost::bind(&DataLogger::ConfigureNightlyFileName, this, _1)) 534 ("Configure the folder for the nightly files." 535 "|Path[string]:Absolute or relative path name where the nightly files should be stored."); 536 537 AddEvent(fConfigRun, "C", kSM_Ready, kSM_BadNightlyConfig, kSM_NightlyOpen, kSM_WaitingRun, kSM_BadRunConfig) 538 (boost::bind(&DataLogger::ConfigureRunFileName, this, _1)) 539 ("Configure the folder for the run files." 540 "|Path[string]:Absolute or relative path name where the run files should be stored."); 541 542 AddEvent(fConfigRunNumber, "I", kSM_Ready, kSM_BadNightlyConfig, kSM_NightlyOpen, kSM_WaitingRun, kSM_BadRunConfig) 543 (boost::bind(&DataLogger::ConfigureRunNumber, this, _1)) 544 ("configure the run number. cannot be done in logging state"); 545 546 //Provide a logging command 547 //I get the feeling that I should be going through the EventImp 548 //instead of DimCommand directly, mainly because the commandHandler 549 //is already done in StateMachineImp.cc 550 //Thus I'll simply add a configuration, which I will treat as the logging command 551 AddEvent(fConfigLog, "C", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_BadRunConfig) 552 (boost::bind(&DataLogger::LogMessagePlease, this, _1)) 553 ("Log a single message to the log-files." 554 "|Message[string]:Message to be logged."); 555 556 //Provide a print command 557 stringstream str; 558 str << kSM_Ready << " " << kSM_NightlyOpen << " " << kSM_WaitingRun << " " << kSM_Logging << " " << kSM_BadNightlyConfig; 559 str << " " << kSM_BadRunConfig; 560 AddEvent(fPrintCommand, str.str().c_str(), "") 561 (boost::bind(&DataLogger::PrintStatePlease, this, _1)) 562 ("Print information about the internal status of the data logger."); 563 564 fServiceList.SetHandler(this); 565 CheckForServicesUpdate(); 566 567 //start the monitoring service 568 fContinueMonitoring = true; 569 fMonitoringThread = boost::thread(boost::bind(&DataLogger::ServicesMonitoring, this)); 570 fBaseSizeNightly = 0; 571 fBaseSizeRun = 0; 572 OpenFileToDim fToDim; 573 fToDim.code = 0; 574 fToDim.fileName[0] = '\0'; 575 576 fOpenedNightlyFiles = new DimDescribedService(GetName() + "/FILENAME_NIGHTLY", "I:1;C", fToDim, 577 "Path and base name which is used to compile the filenames for the nightly files." 578 "|Type[int]:type of open files (1=log, 2=rep, 4=fits)" 579 "|Name[string]:path and base file name"); 580 581 fOpenedRunFiles = new DimDescribedService(GetName() + "/FILENAME_RUN", "I:1;C", fToDim, 582 "Path and base name which is used to compile the filenames for the run files." 583 "|Type[int]:type of open files (1=log, 2=rep, 4=fits)" 584 "|Name[string]:path and base file name"); 585 586 fNumSubAndFitsData.numSubscriptions = 0; 587 fNumSubAndFitsData.numOpenFits = 0; 588 fNumSubAndFits = new DimDescribedService(GetName() + "/NUM_SUBS", "I:2", fNumSubAndFitsData, 589 "Shows number of services to which the data logger is currently subscribed and the total number of open files." 590 "|Subscriptions[int]:number of dim services to which the data logger is currently subscribed." 591 "|NumOpenFiles[int]:number of files currently open by the data logger"); 592 593 //black/white list 594 fHasBlackList = false; 595 fHasWhiteList = false; 596 fBlackList.clear(); 597 fWhiteList.clear(); 598 //services parameters 599 fDebugIsOn = false; 600 fStatsPeriodDuration = 1.0f; 601 fOpenedFilesIsOn = true; 602 fNumSubAndFitsIsOn = true; 603 604 //provide services control commands 605 AddEvent(fDebugOnOff, "B:1", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready) 606 (boost::bind(&DataLogger::SetDebugOnOff, this, _1)) 607 ("Switch debug mode on off. Debug mode prints ifnormation about every service written to a file." 608 "|Enable[bool]:Enable of disable debuig mode (yes/no)."); 609 610 AddEvent(fStatsPeriod, "F", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready) 611 (boost::bind(&DataLogger::SetStatsPeriod, this, _1)) 612 ("Interval in which the data-logger statitistics service (STATS) is updated." 613 "Interval[s]:Floating point value in seconds."); 614 615 AddEvent(fStartStopOpenedFiles, "B:1", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready) 616 (boost::bind(&DataLogger::SetOpenedFilesOnOff ,this, _1)) 617 ("Can be used to switch the service off which distributes information about the open files."); 618 619 AddEvent(fStartStopNumSubsAndFits, "B:1", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready) 620 (boost::bind(&DataLogger::SetNumSubsAndFitsOnOff, this, _1)) 621 ("Can be used to switch the service off which distributes information about the number of subscriptions and open files."); 622 623 fDestructing = false; 624 if(fDebugIsOn) 625 { 626 Debug("DataLogger Init Done."); 627 } 650 628 } 651 629 // -------------------------------------------------------------------------- … … 653 631 //! Checks for changes in the existing services. 654 632 //! Any new service will be added to the service list, while the ones which disappeared are removed. 655 //! @todo656 //! add the configuration (using the conf class ?)657 633 // 658 634 //FIXME The service must be udpated so that I get the first notification. This should not be 659 635 bool DataLogger::CheckForServicesUpdate() 660 636 { 661 bool serviceUpdated = false; 662 //get the current server list 663 const std::vector<std::string> serverList = fServiceList.GetServerList(); 664 //first let's remove the servers that may have disapeared 665 //can't treat the erase on maps the same way as for vectors. Do it the safe way instead 666 std::vector<std::string> toBeDeleted; 667 for (SubscriptionsListType::iterator cListe = fServiceSubscriptions.begin(); cListe != fServiceSubscriptions.end(); cListe++) 668 { 669 std::vector<std::string>::const_iterator givenServers; 670 for (givenServers=serverList.begin(); givenServers!= serverList.end(); givenServers++) 671 if (cListe->first == *givenServers) 672 break; 673 if (givenServers == serverList.end())//server vanished. Remove it 674 { 675 toBeDeleted.push_back(cListe->first); 676 serviceUpdated = true; 677 } 678 679 } 680 for (std::vector<std::string>::const_iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); it++) 681 fServiceSubscriptions.erase(*it); 682 //now crawl through the list of servers, and see if there was some updates 683 for (std::vector<std::string>::const_iterator i=serverList.begin(); i!=serverList.end();i++) 684 { 685 //skip the two de-fact excluded services 686 //Dim crashes if the publisher subscribes to its own service. This sounds weird, I agree. 687 if ((i->find("DIS_DNS") != std::string::npos) || 688 (i->find("DATA_LOGGER") != std::string::npos)) 689 continue; 690 //find the current server in our subscription list 691 SubscriptionsListType::iterator cSubs = fServiceSubscriptions.find(*i); 692 //get the service list of the current server 693 std::vector<std::string> cServicesList = fServiceList.GetServiceList(*i); 694 if (cSubs != fServiceSubscriptions.end())//if the current server already is in our subscriptions 695 { //then check and update our list of subscriptions 696 //first, remove the services that may have dissapeared. 697 std::map<std::string, SubscriptionType>::iterator serverSubs; 698 std::vector<std::string>::const_iterator givenSubs; 699 toBeDeleted.clear(); 700 for (serverSubs=cSubs->second.begin(); serverSubs != cSubs->second.end(); serverSubs++) 701 { 702 for (givenSubs = cServicesList.begin(); givenSubs != cServicesList.end(); givenSubs++) 703 if (serverSubs->first == *givenSubs) 704 break; 705 if (givenSubs == cServicesList.end()) 706 { 707 toBeDeleted.push_back(serverSubs->first); 708 serviceUpdated = true; 709 } 710 } 711 for (std::vector<std::string>::const_iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); it++) 712 cSubs->second.erase(*it); 713 //now check for new services 714 for (givenSubs = cServicesList.begin(); givenSubs != cServicesList.end(); givenSubs++) 715 { 716 if (*givenSubs == "SERVICE_LIST") 717 continue; 718 719 if (fHasWhiteList && (fWhiteList.find(*i + "/") == fWhiteList.end()) && 637 bool serviceUpdated = false; 638 //get the current server list 639 const vector<string> serverList = fServiceList.GetServerList(); 640 //first let's remove the servers that may have disapeared 641 //can't treat the erase on maps the same way as for vectors. Do it the safe way instead 642 vector<string> toBeDeleted; 643 for (SubscriptionsListType::iterator cListe = fServiceSubscriptions.begin(); cListe != fServiceSubscriptions.end(); cListe++) 644 { 645 vector<string>::const_iterator givenServers; 646 for (givenServers=serverList.begin(); givenServers!= serverList.end(); givenServers++) 647 if (cListe->first == *givenServers) 648 break; 649 if (givenServers == serverList.end())//server vanished. Remove it 650 { 651 toBeDeleted.push_back(cListe->first); 652 serviceUpdated = true; 653 } 654 } 655 for (vector<string>::const_iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); it++) 656 fServiceSubscriptions.erase(*it); 657 //now crawl through the list of servers, and see if there was some updates 658 for (vector<string>::const_iterator i=serverList.begin(); i!=serverList.end();i++) 659 { 660 //skip the two de-fact excluded services 661 //Dim crashes if the publisher subscribes to its own service. This sounds weird, I agree. 662 if ((i->find("DIS_DNS") != string::npos) || 663 (i->find("DATA_LOGGER") != string::npos)) 664 continue; 665 //find the current server in our subscription list 666 SubscriptionsListType::iterator cSubs = fServiceSubscriptions.find(*i); 667 //get the service list of the current server 668 vector<string> cServicesList = fServiceList.GetServiceList(*i); 669 if (cSubs != fServiceSubscriptions.end())//if the current server already is in our subscriptions 670 { //then check and update our list of subscriptions 671 //first, remove the services that may have dissapeared. 672 map<string, SubscriptionType>::iterator serverSubs; 673 vector<string>::const_iterator givenSubs; 674 toBeDeleted.clear(); 675 for (serverSubs=cSubs->second.begin(); serverSubs != cSubs->second.end(); serverSubs++) 676 { 677 for (givenSubs = cServicesList.begin(); givenSubs != cServicesList.end(); givenSubs++) 678 if (serverSubs->first == *givenSubs) 679 break; 680 if (givenSubs == cServicesList.end()) 681 { 682 toBeDeleted.push_back(serverSubs->first); 683 serviceUpdated = true; 684 } 685 } 686 for (vector<string>::const_iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); it++) 687 cSubs->second.erase(*it); 688 //now check for new services 689 for (givenSubs = cServicesList.begin(); givenSubs != cServicesList.end(); givenSubs++) 690 { 691 if (*givenSubs == "SERVICE_LIST") 692 continue; 693 694 if (fHasWhiteList && (fWhiteList.find(*i + "/") == fWhiteList.end()) && 720 695 (fWhiteList.find(*i + "/" + *givenSubs) == fWhiteList.end()) && 721 696 (fWhiteList.find("/" + *givenSubs) == fWhiteList.end())) 722 697 continue; 723 698 if (fHasBlackList && ((fBlackList.find(*i + "/") != fBlackList.end()) || 724 699 (fBlackList.find(*i + "/" + *givenSubs) != fBlackList.end()) || … … 727 702 728 703 if (cSubs->second.find(*givenSubs) == cSubs->second.end()) 729 730 731 732 733 734 735 736 Debug(str.str()); 737 738 } 739 740 741 742 743 fServiceSubscriptions[*i] = std::map<std::string, SubscriptionType>();744 std::map<std::string, SubscriptionType>& liste = fServiceSubscriptions[*i];745 for (std::vector<std::string>::const_iterator j = cServicesList.begin(); j!= cServicesList.end(); j++)746 747 748 704 {//service not found. Add it 705 cSubs->second[*givenSubs].dimInfo = new DimStampedInfo(((*i) + "/" + *givenSubs).c_str(), const_cast<char*>(""), this); 706 serviceUpdated = true; 707 if(fDebugIsOn) 708 { 709 stringstream str; 710 str << "Subscribing to service " << *i << "/" << *givenSubs; 711 Debug(str.str()); 712 } 713 } 714 } 715 } 716 else //server not found in our list. Create its entry 717 { 718 fServiceSubscriptions[*i] = map<string, SubscriptionType>(); 719 map<string, SubscriptionType>& liste = fServiceSubscriptions[*i]; 720 for (vector<string>::const_iterator j = cServicesList.begin(); j!= cServicesList.end(); j++) 721 { 722 if (*j == "SERVICE_LIST") 723 continue; 749 724 if (fHasWhiteList && (fWhiteList.find(*i + "/") == fWhiteList.end()) && 750 725 (fWhiteList.find(*i + "/" + *j) == fWhiteList.end()) && … … 756 731 continue; 757 732 758 759 liste[*j].dimInfo = new DimStampedInfo(((*i) + "/" + (*j)).c_str(), const_cast<char*>(""), this); 760 serviceUpdated = true; 761 if(fDebugIsOn) 762 { 763 stringstream str; 764 str << "Subscribing to service " << *i << "/" << *j; 765 Debug(str.str()); 766 } 767 } 768 } 769 } 770 return serviceUpdated; 733 liste[*j].dimInfo = new DimStampedInfo(((*i) + "/" + (*j)).c_str(), const_cast<char*>(""), this); 734 serviceUpdated = true; 735 if(fDebugIsOn) 736 { 737 stringstream str; 738 str << "Subscribing to service " << *i << "/" << *j; 739 Debug(str.str()); 740 } 741 } 742 } 743 } 744 return serviceUpdated; 771 745 } 772 746 // -------------------------------------------------------------------------- … … 776 750 DataLogger::~DataLogger() 777 751 { 778 if (fDebugIsOn) 779 { 780 Debug("DataLogger destruction starts"); 781 } 782 fDestructing = true; 783 //first let's go to the ready state 784 //TODO some closing done below has already been executed by GoToReady. figure out what should be removed. 785 GoToReadyPlease(); 786 //release the services subscriptions 787 fServiceSubscriptions.clear(); 788 //exit the monitoring loop 789 fContinueMonitoring = false; 790 // delete[] fDimBuffer; 791 fMonitoringThread.join(); 792 //close the files 793 if (fNightlyLogFile.is_open()) 794 fNightlyLogFile.close(); 795 if (fNightlyReportFile.is_open()) 796 fNightlyReportFile.close(); 797 if (fRunLogFile.is_open()) 798 fRunLogFile.close(); 799 if (fRunReportFile.is_open()) 800 fRunReportFile.close(); 801 delete fOpenedNightlyFiles; 802 delete fOpenedRunFiles; 803 delete fNumSubAndFits; 804 //TODO notify that all files were closed 752 if (fDebugIsOn) 753 { 754 Debug("DataLogger destruction starts"); 755 } 756 fDestructing = true; 757 //first let's go to the ready state 758 GoToReadyPlease(); 759 //release the services subscriptions 760 fServiceSubscriptions.clear(); 761 //exit the monitoring loop 762 fContinueMonitoring = false; 763 764 fMonitoringThread.join(); 765 //close the files 766 if (fNightlyLogFile.is_open()) 767 fNightlyLogFile.close(); 768 if (fNightlyReportFile.is_open()) 769 fNightlyReportFile.close(); 770 if (fRunLogFile.is_open()) 771 fRunLogFile.close(); 772 if (fRunReportFile.is_open()) 773 fRunReportFile.close(); 774 delete fOpenedNightlyFiles; 775 delete fOpenedRunFiles; 776 delete fNumSubAndFits; 805 777 #ifdef HAVE_FITS 806 #ifdef ONE_RUN_FITS_ONLY 807 if (fRunFitsFile != NULL) 808 delete fRunFitsFile; 809 fRunFitsFile = NULL; 778 if (fRunFitsFile != NULL) 779 delete fRunFitsFile; 780 fRunFitsFile = NULL; 810 781 #endif 811 #endif 812 if (fDebugIsOn) 813 { 814 Debug("DataLogger desctruction ends"); 815 } 782 if (fDebugIsOn) 783 { 784 Debug("DataLogger desctruction ends"); 785 } 816 786 } 817 787 … … 823 793 { 824 794 // Make sure getTimestamp is called _before_ getTimestampMillisecs 825 826 795 if (fDestructing) 796 return; 827 797 828 798 DimInfo* I = getInfo(); 829 830 std::map<std::string, SubscriptionType>::iterator y;831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 Debug(str.str()); 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 found = true; 861 862 863 864 865 866 867 868 869 799 SubscriptionsListType::iterator x; 800 map<string, SubscriptionType>::iterator y; 801 if (I==NULL) 802 { 803 if (CheckForServicesUpdate()) 804 { 805 //services were updated. Notify 806 fNumSubAndFitsData.numSubscriptions = 0; 807 for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++) 808 fNumSubAndFitsData.numSubscriptions += x->second.size(); 809 if (fNumSubAndFitsIsOn) 810 { 811 if (fDebugIsOn) 812 { 813 stringstream str; 814 str << "Updating number of subscriptions service: Num Subs=" << fNumSubAndFitsData.numSubscriptions << " Num open FITS=" << fNumSubAndFitsData.numOpenFits; 815 Debug(str.str()); 816 } 817 fNumSubAndFits->updateService(); 818 } 819 } 820 return; 821 } 822 //check if the service pointer corresponds to something that we subscribed to 823 //this is a fix for a bug that provides bad Infos when a server starts 824 bool found = false; 825 for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++) 826 {//find current service is subscriptions 827 for (y=x->second.begin(); y!=x->second.end();y++) 828 if (y->second.dimInfo == I) 829 { 830 found = true; 831 break; 832 } 833 if (found) 834 break; 835 } 836 if (!found) 837 return; 838 if (I->getSize() <= 0) 839 return; 870 840 871 841 // Make sure that getTimestampMillisecs is NEVER called before 872 842 // getTimestamp is properly called 873 843 // check that the message has been updated by something, i.e. must be different from its initial value 874 875 876 877 878 879 880 881 882 883 884 885 886 844 if (I->getTimestamp() == 0) 845 return; 846 847 CheckForRunNumber(I); 848 849 if (fPreviousRunNumber != fRunNumber) 850 {//run number has changed. close and reopen run files. 851 StopRunPlease(); 852 StartRunPlease(); 853 fPreviousRunNumber = fRunNumber; 854 } 855 856 ReportPlease(I, y->second); 887 857 888 858 } … … 893 863 //! If so, then remember it. A run number is required to open the run-log file 894 864 //! @param I 895 //! 865 //! the current DimInfo 896 866 // 897 867 void DataLogger::CheckForRunNumber(DimInfo* I) 898 868 { 899 if (strstr(I->getName(), fRunNumberInfo) != NULL) 900 {//assumes that the run number is an integer 901 //TODO check the format here 902 fRunNumber = I->getInt(); 903 stringstream str; 904 str << "New run number is " << fRunNumber; 905 Message(str.str()); 906 } 869 if (strstr(I->getName(), fRunNumberInfo) != NULL) 870 {//assumes that the run number is an integer 871 fRunNumber = I->getInt(); 872 stringstream str; 873 str << "New run number is " << fRunNumber; 874 Message(str.str()); 875 } 907 876 } 908 877 … … 911 880 //! write infos to log files. 912 881 //! @param I 913 //! 882 //! The current DimInfo 914 883 //! @param sub 915 //! 884 //! The dataLogger's subscription corresponding to this DimInfo 916 885 // 917 886 void DataLogger::ReportPlease(DimInfo* I, SubscriptionType& sub) 918 887 { 919 //should we log or report this info ? (i.e. is it a message ?) 920 bool isItaReport = ((strstr(I->getName(), "Message") == NULL) && (strstr(I->getName(), "MESSAGE") == NULL)); 921 if (I->getFormat()[0] == 'C') 922 isItaReport = false; 923 //TODO add service exclusion 924 925 if (!fNightlyReportFile.is_open()) 926 return; 927 928 //create the converter for that service 929 if (sub.fConv == NULL && isItaReport) 930 { 931 //trick the converter in case of 'C'. why do I do this ? well simple: the converter checks that the right number 932 //of bytes was written. because I skip 'C' with fits, the bytes will not be allocated, hence the "size copied ckeck" 933 //of the converter will fail, hence throwing an exception. 934 std::string fakeFormat(I->getFormat()); 935 if (fakeFormat[fakeFormat.size()-1] == 'C') 936 fakeFormat = fakeFormat.substr(0, fakeFormat.size()-1); 937 sub.fConv = new Converter(Out(), I->getFormat()); 938 if (!sub.fConv) 939 { 940 std::stringstream str; 941 str << "Couldn't properly parse the format... service " << sub.dimInfo->getName() << " ignored."; 942 Error(str); 943 return; 944 } 945 } 946 947 //construct the header 948 std::stringstream header; 949 Time cTime(I->getTimestamp(), I->getTimestampMillisecs()*1000); 950 fQuality = I->getQuality(); 951 fMjD = cTime.Mjd(); 952 953 if (isItaReport) 954 { 955 //write text header 956 header << I->getName() << " " << fQuality << " "; 957 header << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " "; 958 header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " "; 959 header << cTime.ms() << " " << I->getTimestamp() << " "; 960 961 std::string text; 888 //should we log or report this info ? (i.e. is it a message ?) 889 bool isItaReport = ((strstr(I->getName(), "Message") == NULL) && (strstr(I->getName(), "MESSAGE") == NULL)); 890 if (I->getFormat()[0] == 'C') 891 isItaReport = false; 892 893 if (!fNightlyReportFile.is_open()) 894 return; 895 896 //create the converter for that service 897 if (sub.fConv == NULL && isItaReport) 898 { 899 //trick the converter in case of 'C'. why do I do this ? well simple: the converter checks that the right number 900 //of bytes was written. because I skip 'C' with fits, the bytes will not be allocated, hence the "size copied ckeck" 901 //of the converter will fail, hence throwing an exception. 902 string fakeFormat(I->getFormat()); 903 if (fakeFormat[fakeFormat.size()-1] == 'C') 904 fakeFormat = fakeFormat.substr(0, fakeFormat.size()-1); 905 sub.fConv = new Converter(Out(), I->getFormat()); 906 if (!sub.fConv) 907 { 908 stringstream str; 909 str << "Couldn't properly parse the format... service " << sub.dimInfo->getName() << " ignored."; 910 Error(str); 911 return; 912 } 913 } 914 915 //construct the header 916 stringstream header; 917 Time cTime(I->getTimestamp(), I->getTimestampMillisecs()*1000); 918 fQuality = I->getQuality(); 919 fMjD = cTime.Mjd(); 920 921 if (isItaReport) 922 { 923 //write text header 924 header << I->getName() << " " << fQuality << " "; 925 header << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " "; 926 header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " "; 927 header << cTime.ms() << " " << I->getTimestamp() << " "; 928 929 string text; 962 930 try 963 931 { 964 965 } 966 catch (const std::runtime_error &e)967 { 968 969 std::stringstream str;970 971 932 text = sub.fConv->GetString(I->getData(), I->getSize()); 933 } 934 catch (const runtime_error &e) 935 { 936 Out() << kRed << e.what() << endl; 937 stringstream str; 938 str << "Could not properly parse the data for service " << sub.dimInfo->getName(); 939 str << " reason: " << e.what() << ". Entry ignored"; 972 940 Error(str); 973 941 return; 974 942 } 975 943 976 977 978 std::stringstream str;979 980 981 982 944 if (text.empty()) 945 { 946 stringstream str; 947 str << "Service " << sub.dimInfo->getName() << " sent an empty string"; 948 Info(str); 949 return; 950 } 983 951 //replace bizarre characters by white space 984 952 replace(text.begin(), text.end(), '\n', '\\'); 985 replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');953 replace_if(text.begin(), text.end(), ptr_fun<int, int>(&iscntrl), ' '); 986 954 987 955 //write entry to Nightly report 988 989 990 991 992 993 994 Debug(str.str()); 995 996 fNightlyReportFile << header.str() << text << std::endl;997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 Debug(str.str()); 1013 1014 fRunReportFile << header.str() << text << std::endl;1015 1016 1017 1018 1019 fRunReportFile.close(); 1020 1021 1022 1023 1024 1025 std::string n = I->getName();1026 std::stringstream msg;1027 1028 1029 1030 1031 1032 1033 1034 1035 Debug(str.str()); 1036 1037 1038 1039 1040 1041 1042 1043 fNightlyLogFile.close(); 1044 1045 1046 1047 1048 1049 1050 1051 1052 Debug(str.str()); 1053 1054 1055 1056 1057 1058 1059 1060 fRunLogFile.close(); 1061 1062 1063 956 if (fNightlyReportFile.is_open()) 957 { 958 if (fDebugIsOn) 959 { 960 stringstream str; 961 str << "Writing: \"" << header.str() << text << "\" to Nightly report file"; 962 Debug(str.str()); 963 } 964 fNightlyReportFile << header.str() << text << endl; 965 //check if either eof, bailbit or batbit are set 966 if (!fNightlyReportFile.good()) 967 { 968 Error("An error occured while writing to the nightly report file. Closing it"); 969 if (fNightlyReportFile.is_open()) 970 fNightlyReportFile.close(); 971 } 972 } 973 //write entry to run-report 974 if (fRunReportFile.is_open()) 975 { 976 if (fDebugIsOn) 977 { 978 stringstream str; 979 str << "Writing: \"" << header.str() << text << "\" to Run report file"; 980 Debug(str.str()); 981 } 982 fRunReportFile << header.str() << text << endl; 983 if (!fRunReportFile.good()) 984 { 985 Error("An error occured while writing to the run report file. Closing it."); 986 if (fRunReportFile.is_open()) 987 fRunReportFile.close(); 988 } 989 } 990 } 991 else 992 {//write entry to both Nightly and run logs 993 string n = I->getName(); 994 stringstream msg; 995 msg << n << ": " << I->getString();//n.substr(0, n.find_first_of('/')) << ": " << I->getString(); 996 997 if (fNightlyLogFile.is_open()) 998 { 999 if (fDebugIsOn) 1000 { 1001 stringstream str; 1002 str << "Writing: \"" << msg.str() << "\" to Nightly log file"; 1003 Debug(str.str()); 1004 } 1005 MessageImp nightlyMess(fNightlyLogFile); 1006 nightlyMess.Write(cTime, msg.str().c_str(), fQuality); 1007 if (!fNightlyLogFile.good()) 1008 { 1009 Error("An error occured while writing to the nightly log file. Closing it."); 1010 if (fNightlyLogFile.is_open()) 1011 fNightlyLogFile.close(); 1012 } 1013 } 1014 if (fRunLogFile.is_open()) 1015 { 1016 if (fDebugIsOn) 1017 { 1018 stringstream str; 1019 str << "Writing: \"" << msg.str() << "\" to Run log file"; 1020 Debug(str.str()); 1021 } 1022 MessageImp runMess(fRunLogFile); 1023 runMess.Write(cTime, msg.str().c_str(), fQuality); 1024 if (!fRunLogFile.good()) 1025 { 1026 Error("An error occured while writing to the run log file. Closing it."); 1027 if (fRunLogFile.is_open()) 1028 fRunLogFile.close(); 1029 } 1030 } 1031 } 1064 1032 1065 1033 #ifdef HAVE_FITS 1066 1067 1068 1069 OpenFITSFilesPlease(sub); 1070 1071 } 1034 if (isItaReport) 1035 { 1036 if (!sub.nightlyFile.IsOpen() || !sub.runFile.IsOpen()) 1037 OpenFITSFilesPlease(sub); 1038 WriteToFITS(sub); 1039 } 1072 1040 #endif 1073 1041 … … 1078 1046 //! write messages to logs. 1079 1047 //! @param evt 1080 //! 1048 //! the current event to log 1081 1049 //! @returns 1082 //! 1050 //! the new state. Currently, always the current state 1083 1051 //! 1084 1052 //! @deprecated 1085 1053 //! I guess that this function should not be any longer 1086 1054 // 1087 //TODO isn't that function not used any longer ? If so I guess that we should get rid of it...1088 1055 //Otherwise re-write it properly with the MessageImp class 1089 1056 int DataLogger::LogMessagePlease(const Event& evt) 1090 1057 { 1091 1092 1093 1094 std::stringstream header;1095 1096 1097 1098 1099 1058 if (!fNightlyLogFile.is_open()) 1059 return GetCurrentState(); 1060 Warn("LogMessagePlease has not been checked nor updated since a long while. Undefined behavior to be expected"); 1061 stringstream header; 1062 const Time& cTime = evt.GetTime(); 1063 header << evt.GetName() << " " << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " "; 1064 header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " "; 1065 header << cTime.ms() << " "; 1066 1100 1067 const Converter conv(Out(), evt.GetFormat()); 1101 1068 if (!conv) 1102 1069 { 1103 1070 Error("Couldn't properly parse the format... ignored."); 1104 1071 return GetCurrentState(); 1105 1072 } 1106 1073 1107 st d::string text;1074 string text; 1108 1075 try 1109 1076 { 1110 1111 } 1112 catch (const std::runtime_error &e)1113 { 1114 1077 text = conv.GetString(evt.GetData(), evt.GetSize()); 1078 } 1079 catch (const runtime_error &e) 1080 { 1081 Out() << kRed << e.what() << endl; 1115 1082 Error("Couldn't properly parse the data... ignored."); 1116 1083 return GetCurrentState(); 1117 1084 } 1118 1085 1119 1086 if (text.empty()) 1120 1087 return GetCurrentState(); 1121 1088 1122 1089 //replace bizarre characters by white space 1123 1090 replace(text.begin(), text.end(), '\n', '\\'); 1124 replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');1125 1126 1127 1128 1129 Debug(str.str()); 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 fNightlyLogFile.close(); 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 fRunLogFile.close(); 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 fNightlyLogFile.close(); 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 fRunLogFile.close(); 1170 1171 1172 1091 replace_if(text.begin(), text.end(), ptr_fun<int, int>(&iscntrl), ' '); 1092 if (fDebugIsOn) 1093 { 1094 stringstream str; 1095 str << "Logging: \"" << header << text << "\""; 1096 Debug(str.str()); 1097 } 1098 1099 if (fNightlyLogFile.is_open()) 1100 { 1101 fNightlyLogFile << header; 1102 if (!fNightlyLogFile.good()) 1103 { 1104 Error("An error occured while writing to the run log file. Closing it."); 1105 if (fNightlyLogFile.is_open()) 1106 fNightlyLogFile.close(); 1107 } 1108 } 1109 if (fRunLogFile.is_open()) 1110 { 1111 fRunLogFile << header; 1112 if (!fRunLogFile.good()) 1113 { 1114 Error("An error occured while writing to the run log file. Closing it."); 1115 if (fRunLogFile.is_open()) 1116 fRunLogFile.close(); 1117 } 1118 } 1119 if (fNightlyLogFile.is_open()) 1120 { 1121 fNightlyLogFile << text; 1122 if (!fNightlyLogFile.good()) 1123 { 1124 Error("An error occured while writing to the run log file. Closing it."); 1125 if (fNightlyLogFile.is_open()) 1126 fNightlyLogFile.close(); 1127 } 1128 } 1129 if (fRunLogFile.is_open()) 1130 { 1131 fRunLogFile << text; 1132 if (!fRunLogFile.good()) 1133 { 1134 Error("An error occured while writing to the run log file. Closing it."); 1135 if (fRunLogFile.is_open()) 1136 fRunLogFile.close(); 1137 } 1138 } 1139 return GetCurrentState(); 1173 1140 } 1174 1141 // -------------------------------------------------------------------------- … … 1176 1143 //! print the dataLogger's current state. invoked by the PRINT command 1177 1144 //! @param evt 1178 //! 1145 //! the current event. Not used by the method 1179 1146 //! @returns 1180 //! 1147 //! the new state. Which, in that case, is the current state 1181 1148 //! 1182 1149 int DataLogger::PrintStatePlease(const Event& ) 1183 1150 { 1184 1185 1186 1187 1188 std::string actualTargetDir;1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1151 Message("-----------------------------------------"); 1152 Message("------ DATA LOGGER CURRENT STATE --------"); 1153 Message("-----------------------------------------"); 1154 //print the path configuration 1155 string actualTargetDir; 1156 if (fNightlyFileName == ".") 1157 { 1158 char currentPath[FILENAME_MAX]; 1159 if (getcwd(currentPath, sizeof(currentPath))) 1160 actualTargetDir = currentPath; 1161 } 1162 else 1163 actualTargetDir = fNightlyFileName; 1164 Message("Nightly Path: " + actualTargetDir); 1165 if (fRunFileName == ".") 1166 { 1167 char currentPath[FILENAME_MAX]; 1168 if (getcwd(currentPath, sizeof(currentPath))) 1169 actualTargetDir = currentPath; 1170 } 1171 else 1172 actualTargetDir = fRunFileName; 1173 Message("Run Path: " + actualTargetDir); 1174 stringstream str; 1175 str << "Run Number: " << fRunNumber; 1176 Message(str.str()); 1177 Message("----------- OPENED FILES ----------------"); 1178 //print all the open files. 1179 if (fNightlyLogFile.is_open()) 1180 Message("Nightly Log..........OPEN"); 1181 else 1182 Message("Nightly log........CLOSED"); 1183 if (fNightlyReportFile.is_open()) 1184 Message("Nightly Report.......OPEN"); 1185 else 1186 Message("Nightly Report.....CLOSED"); 1187 if (fRunLogFile.is_open()) 1188 Message("Run Log..............OPEN"); 1189 else 1190 Message("Run Log............CLOSED"); 1191 if (fRunReportFile.is_open()) 1192 Message("Run Report...........OPEN"); 1193 else 1194 Message("Run Report.........CLOSED"); 1195 bool statWarning = false; 1196 DataLoggerStats statVar; 1197 calculateTotalSizeWritten(statVar, statWarning, false); 1198 Message("---------------- STATS ------------------"); 1199 str.str(""); 1200 str << "Total Size written: " << statVar.sizeWritten << " bytes."; 1234 1201 Message(str.str()); 1235 1236 1202 str.str(""); 1203 str << "Disk free space: " << statVar.freeSpace << " bytes."; 1237 1204 Message(str.str()); 1238 1205 str.str(""); 1239 1206 str << "Statistics are updated every " << fStatsPeriodDuration << " seconds"; 1240 1207 if (fStatsPeriodDuration != 0) 1241 1208 Message(str); 1242 1209 else 1243 Message("Statistics updates are currently disabled"); 1244 Message("----------- DIM SUBSCRIPTIONS -----------"); 1245 1246 str.str(""); 1247 str << "There are " << fNumSubAndFitsData.numSubscriptions << " active DIM subscriptions:"; 1248 Message(str.str()); 1249 1250 for (std::map<const std::string, std::map<std::string, SubscriptionType>>::const_iterator it=fServiceSubscriptions.begin(); it!= fServiceSubscriptions.end();it++) 1251 { 1252 Message("Server "+it->first); 1253 for (std::map<std::string, SubscriptionType>::const_iterator it2=it->second.begin(); it2!=it->second.end(); it2++) 1254 Message(" -> "+it2->first); 1255 } 1256 if (fHasBlackList) 1257 { 1258 Message("------------- BLOCK LIST ----------------"); 1259 for (set<string>::iterator it=fBlackList.begin(); it != fBlackList.end(); it++) 1260 Message(*it); 1261 } 1262 if (fHasWhiteList) 1263 { 1264 Message("----------- ALLOW LIST ------------------"); 1265 for (set<string>::iterator it=fWhiteList.begin(); it != fWhiteList.end(); it++) 1266 Message(*it); 1267 } 1268 1269 return GetCurrentState(); 1210 Message("Statistics updates are currently disabled"); 1211 Message("----------- DIM SUBSCRIPTIONS -----------"); 1212 1213 str.str(""); 1214 str << "There are " << fNumSubAndFitsData.numSubscriptions << " active DIM subscriptions:"; 1215 Message(str.str()); 1216 1217 for (map<const string, map<string, SubscriptionType> >::const_iterator it=fServiceSubscriptions.begin(); it!= fServiceSubscriptions.end();it++) 1218 { 1219 Message("Server "+it->first); 1220 for (map<string, SubscriptionType>::const_iterator it2=it->second.begin(); it2!=it->second.end(); it2++) 1221 Message(" -> "+it2->first); 1222 } 1223 if (fHasBlackList) 1224 { 1225 Message("------------- BLOCK LIST ----------------"); 1226 for (set<string>::iterator it=fBlackList.begin(); it != fBlackList.end(); it++) 1227 Message(*it); 1228 } 1229 if (fHasWhiteList) 1230 { 1231 Message("----------- ALLOW LIST ------------------"); 1232 for (set<string>::iterator it=fWhiteList.begin(); it != fWhiteList.end(); it++) 1233 Message(*it); 1234 } 1235 if (fGrouping.size() != 0) 1236 { 1237 Message("--------- GROUPING LIST -----------------"); 1238 Message("The following servers and/or services will be grouping under a single run fits file:"); 1239 for (set<string>::iterator it=fGrouping.begin(); it != fGrouping.end(); it++) 1240 Message(*it); 1241 } 1242 Message("-----------------------------------------"); 1243 Message("------ END OF DATA LOGGER STATE ---------"); 1244 Message("-----------------------------------------"); 1245 1246 return GetCurrentState(); 1270 1247 } 1271 1248 … … 1274 1251 //! turn debug mode on and off 1275 1252 //! @param evt 1276 //! 1253 //! the current event. contains the instruction string: On, Off, on, off, ON, OFF, 0 or 1 1277 1254 //! @returns 1278 //! 1255 //! the new state. Which, in that case, is the current state 1279 1256 //! 1280 1257 int DataLogger::SetDebugOnOff(const Event& evt) 1281 1258 { 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1259 bool backupDebug = fDebugIsOn; 1260 fDebugIsOn = evt.GetBool(); 1261 if (fDebugIsOn == backupDebug) 1262 Warn("Warning: debug mode was already in the requested state"); 1263 else 1264 { 1265 stringstream str; 1266 str << "Debug mode is now " << fDebugIsOn; 1267 Message(str.str()); 1268 } 1269 return GetCurrentState(); 1293 1270 } 1294 1271 // -------------------------------------------------------------------------- … … 1296 1273 //! set the statistics update period duration. 0 disables the statistics 1297 1274 //! @param evt 1298 //! 1275 //! the current event. contains the new duration. 1299 1276 //! @returns 1300 //! 1277 //! the new state. Which, in that case, is the current state 1301 1278 //! 1302 1279 int DataLogger::SetStatsPeriod(const Event& evt) 1303 1280 { 1304 1305 1306 1307 1308 1309 1310 return GetCurrentState(); 1311 1312 1313 1314 1315 1316 return GetCurrentState(); 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 Message(str.str()); 1329 } 1330 1331 1281 float backupDuration = fStatsPeriodDuration; 1282 fStatsPeriodDuration = evt.GetFloat(); 1283 if (fStatsPeriodDuration < 0) 1284 { 1285 Error("Statistics period duration should be greater than zero. Discarding provided value."); 1286 fStatsPeriodDuration = backupDuration; 1287 return GetCurrentState(); 1288 } 1289 if (fStatsPeriodDuration != fStatsPeriodDuration) 1290 { 1291 Error("Provided duration does not appear to be a valid float. discarding it."); 1292 fStatsPeriodDuration = backupDuration; 1293 return GetCurrentState(); 1294 } 1295 if (backupDuration == fStatsPeriodDuration) 1296 Warn("Warning: statistics period was not modified: supplied value already in use"); 1297 else 1298 { 1299 if (fStatsPeriodDuration == 0.0f) 1300 Message("Statistics are now OFF"); 1301 else 1302 { 1303 stringstream str; 1304 str << "Statistics period is now " << fStatsPeriodDuration << " seconds"; 1305 Message(str.str()); 1306 } 1307 } 1308 return GetCurrentState(); 1332 1309 } 1333 1310 // -------------------------------------------------------------------------- … … 1335 1312 //! set the opened files service on or off. 1336 1313 //! @param evt 1337 //! 1314 //! the current event. contains the instruction string. similar to setdebugonoff 1338 1315 //! @returns 1339 //! 1316 //! the new state. Which, in that case, is the current state 1340 1317 //! 1341 1318 int DataLogger::SetOpenedFilesOnOff(const Event& evt) 1342 1319 { 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1320 bool backupOpened = fOpenedFilesIsOn; 1321 fOpenedFilesIsOn = evt.GetBool(); 1322 if (fOpenedFilesIsOn == backupOpened) 1323 Warn("Warning: opened files service mode was already in the requested state"); 1324 else 1325 { 1326 stringstream str; 1327 str << "Opened files service mode is now " << fOpenedFilesIsOn; 1328 Message(str.str()); 1329 } 1330 return GetCurrentState(); 1331 1355 1332 } 1356 1333 // -------------------------------------------------------------------------- … … 1358 1335 //! set the number of subscriptions and opened fits on and off 1359 1336 //! @param evt 1360 //! 1337 //! the current event. contains the instruction string. similar to setdebugonoff 1361 1338 //! @returns 1362 //! 1339 //! the new state. Which, in that case, is the current state 1363 1340 //! 1364 1341 int DataLogger::SetNumSubsAndFitsOnOff(const Event& evt) 1365 1342 { 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 } 1378 // -------------------------------------------------------------------------- 1379 // 1380 //! 1343 bool backupSubs = fNumSubAndFitsIsOn; 1344 fNumSubAndFitsIsOn = evt.GetBool(); 1345 if (fNumSubAndFitsIsOn == backupSubs) 1346 Warn("Warning: Number of subscriptions service mode was already in the requested state"); 1347 else 1348 { 1349 stringstream str; 1350 str << "Number of subscriptions service mode is now " << fNumSubAndFitsIsOn; 1351 Message(str.str()); 1352 } 1353 return GetCurrentState(); 1354 } 1355 // -------------------------------------------------------------------------- 1356 // 1357 //! Sets the path to use for the Nightly log file. 1381 1358 //! @param evt 1382 //! 1359 //! the event transporting the path 1383 1360 //! @returns 1384 //! 1361 //! currently only the current state. 1385 1362 // 1386 1363 int DataLogger::ConfigureNightlyFileName(const Event& evt) 1387 1364 { 1388 1389 1390 fNightlyFileName = std::string(evt.GetText()); 1391 1392 1393 1394 1395 1396 1365 if (evt.GetText() != NULL) 1366 { 1367 fNightlyFileName = string(evt.GetText()); 1368 Message("New Nightly folder specified: " + fNightlyFileName); 1369 } 1370 else 1371 Error("Empty Nightly folder given. Please specify a valid path."); 1372 1373 return GetCurrentState(); 1397 1374 } 1398 1375 // -------------------------------------------------------------------------- … … 1400 1377 //! Sets the path to use for the run log file. 1401 1378 //! @param evt 1402 //! 1379 //! the event transporting the path 1403 1380 //! @returns 1404 //! 1381 //! currently only the current state 1405 1382 int DataLogger::ConfigureRunFileName(const Event& evt) 1406 1383 { 1407 1408 1409 fRunFileName = std::string(evt.GetText());1410 1411 1412 1413 1414 1415 1384 if (evt.GetText() != NULL) 1385 { 1386 fRunFileName = string(evt.GetText()); 1387 Message("New Run folder specified: " + fRunFileName); 1388 } 1389 else 1390 Error("Empty Nightly folder given. Please specify a valid path"); 1391 1392 return GetCurrentState(); 1416 1393 } 1417 1394 // -------------------------------------------------------------------------- … … 1419 1396 //! Sets the run number. 1420 1397 //! @param evt 1421 //! 1398 //! the event transporting the run number 1422 1399 //! @returns 1423 //! currently only the current state 1424 //TODO remove this function as the run numbers will be distributed through a dedicated service 1400 //! currently only the current state 1425 1401 int DataLogger::ConfigureRunNumber(const Event& evt) 1426 1402 { 1427 1428 std::stringstream str;1429 1430 1431 1403 fRunNumber = evt.GetInt(); 1404 stringstream str; 1405 str << "The new run number is: " << fRunNumber; 1406 Message(str.str()); 1407 return GetCurrentState(); 1432 1408 } 1433 1409 // -------------------------------------------------------------------------- … … 1435 1411 //! Notifies the DIM service that a particular file was opened 1436 1412 //! @ param name the base name of the opened file, i.e. without path nor extension. 1437 //! 1438 //! 1413 //! WARNING: use string instead of string& because I pass values that do not convert to string&. 1414 //! this is not a problem though because file are not opened so often. 1439 1415 //! @ param type the type of the opened file. 0 = none open, 1 = log, 2 = text, 4 = fits 1440 inline void DataLogger::NotifyOpenedFile(st d::string name, int type, DimDescribedService* service)1441 { 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1416 inline void DataLogger::NotifyOpenedFile(string name, int type, DimDescribedService* service) 1417 { 1418 if (fOpenedFilesIsOn) 1419 { 1420 if (fDebugIsOn) 1421 { 1422 stringstream str; 1423 str << "Updating files service " << service->getName() << "with code: " << type << " and file: " << name; 1424 Debug(str.str()); 1425 str.str(""); 1426 str << "Num subs: " << fNumSubAndFitsData.numSubscriptions << " Num open FITS: " << fNumSubAndFitsData.numOpenFits; 1427 Debug(str.str()); 1428 } 1429 OpenFileToDim fToDim; 1430 fToDim.code = type; 1431 memcpy(fToDim.fileName, name.c_str(), name.size()+1); 1432 service->setData(reinterpret_cast<void*>(&fToDim), name.size()+1+sizeof(int)); 1433 service->setQuality(0); 1434 service->updateService(); 1435 } 1460 1436 } 1461 1437 // -------------------------------------------------------------------------- … … 1465 1441 //! and tries to open it. 1466 1442 //! @returns 1467 //! 1443 //! kSM_NightlyOpen if success, kSM_BadNightlyConfig if failure 1468 1444 int DataLogger::StartPlease() 1469 1445 { 1470 if (fDebugIsOn) 1471 { 1472 Debug("Starting..."); 1473 } 1474 Time time; 1475 std::stringstream sTime; 1476 sTime << time.Y() << "_" << time.M() << "_" << time.D(); 1477 1478 fFullNightlyLogFileName = fNightlyFileName + '/' + sTime.str() + ".log"; 1479 fNightlyLogFile.open(fFullNightlyLogFileName.c_str(), std::ios_base::out | std::ios_base::app); 1480 if (errno != 0) 1481 { 1482 std::stringstream str; 1483 str << "Unable to open Nightly Log " << fFullNightlyLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1484 Error(str); 1485 } 1486 fFullNightlyReportFileName = fNightlyFileName + '/' + sTime.str() + ".rep"; 1487 fNightlyReportFile.open(fFullNightlyReportFileName.c_str(), std::ios_base::out | std::ios_base::app); 1488 if (errno != 0) 1489 { 1490 std::stringstream str; 1491 str << "Unable to open Nightly Report " << fFullNightlyReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1492 Error(str); 1493 } 1494 1495 if (!fNightlyLogFile.is_open() || !fNightlyReportFile.is_open()) 1496 { 1497 //TODO send an error message 1498 return kSM_BadNightlyConfig; 1499 } 1500 //get the size of the newly opened file. 1501 struct stat st; 1502 stat(fFullNightlyLogFileName.c_str(), &st); 1503 fBaseSizeNightly = st.st_size; 1504 stat(fFullNightlyReportFileName.c_str(), &st); 1505 fBaseSizeNightly += st.st_size; 1506 fFileSizesMap.clear(); 1507 fBaseSizeRun = 0; 1508 fPreviousSize = 0; 1509 //notify that files were opened 1510 std::string actualTargetDir; 1511 if (fNightlyFileName == ".") 1512 { 1513 char currentPath[FILENAME_MAX]; 1514 if (!getcwd(currentPath, sizeof(currentPath))) 1515 { 1516 if (errno != 0) 1517 { 1518 std::stringstream str; 1519 str << "Unable retrieve current path" << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1520 Error(str); 1521 } 1522 } 1523 actualTargetDir = currentPath; 1524 } 1525 else 1526 { 1527 actualTargetDir = fNightlyFileName; 1528 } 1529 //notify that a new file has been opened. 1530 NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 3, fOpenedNightlyFiles); 1531 1532 fOpenedNightlyFits.clear(); 1533 1534 return kSM_NightlyOpen; 1446 if (fDebugIsOn) 1447 { 1448 Debug("Starting..."); 1449 } 1450 Time time; 1451 stringstream sTime; 1452 sTime << time.Y() << "_" << time.M() << "_" << time.D(); 1453 1454 fFullNightlyLogFileName = fNightlyFileName + '/' + sTime.str() + ".log"; 1455 fNightlyLogFile.open(fFullNightlyLogFileName.c_str(), ios_base::out | ios_base::app); 1456 if (errno != 0) 1457 { 1458 stringstream str; 1459 str << "Unable to open Nightly Log " << fFullNightlyLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1460 Error(str); 1461 } 1462 fFullNightlyReportFileName = fNightlyFileName + '/' + sTime.str() + ".rep"; 1463 fNightlyReportFile.open(fFullNightlyReportFileName.c_str(), ios_base::out | ios_base::app); 1464 if (errno != 0) 1465 { 1466 stringstream str; 1467 str << "Unable to open Nightly Report " << fFullNightlyReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1468 Error(str); 1469 } 1470 1471 if (!fNightlyLogFile.is_open() || !fNightlyReportFile.is_open()) 1472 { 1473 stringstream str; 1474 str << "Something went wrong while openning nightly files " << fFullNightlyLogFileName << " and " << fFullNightlyReportFileName; 1475 Error(str.str()); 1476 return kSM_BadNightlyConfig; 1477 } 1478 //get the size of the newly opened file. 1479 struct stat st; 1480 stat(fFullNightlyLogFileName.c_str(), &st); 1481 fBaseSizeNightly = st.st_size; 1482 stat(fFullNightlyReportFileName.c_str(), &st); 1483 fBaseSizeNightly += st.st_size; 1484 fFileSizesMap.clear(); 1485 fBaseSizeRun = 0; 1486 fPreviousSize = 0; 1487 //notify that files were opened 1488 string actualTargetDir; 1489 if (fNightlyFileName == ".") 1490 { 1491 char currentPath[FILENAME_MAX]; 1492 if (!getcwd(currentPath, sizeof(currentPath))) 1493 { 1494 if (errno != 0) 1495 { 1496 stringstream str; 1497 str << "Unable retrieve current path" << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1498 Error(str); 1499 } 1500 } 1501 actualTargetDir = currentPath; 1502 } 1503 else 1504 { 1505 actualTargetDir = fNightlyFileName; 1506 } 1507 //notify that a new file has been opened. 1508 NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 3, fOpenedNightlyFiles); 1509 1510 fOpenedNightlyFits.clear(); 1511 1512 return kSM_NightlyOpen; 1535 1513 } 1536 1514 … … 1540 1518 //! open if required a the FITS files corresponding to a given subscription 1541 1519 //! @param sub 1542 //! 1520 //! the current DimInfo subscription being examined 1543 1521 void DataLogger::OpenFITSFilesPlease(SubscriptionType& sub) 1544 1522 { 1545 std::string serviceName(sub.dimInfo->getName()); 1546 for (unsigned int i=0;i<serviceName.size(); i++) 1547 { 1548 if (serviceName[i] == '/') 1549 { 1550 serviceName[i] = '_'; 1551 break; 1552 } 1553 } 1554 Time time; 1555 std::stringstream sTime; 1556 sTime << time.Y() << "_" << time.M() << "_" << time.D(); 1557 //we open the NightlyFile anyway, otherwise this function shouldn't have been called. 1558 if (!sub.nightlyFile.IsOpen()) 1559 { 1560 std::string fileNameOnly = sTime.str() + '_' + serviceName + ".fits"; 1561 std::string partialName = fNightlyFileName + '/' + fileNameOnly; 1562 AllocateFITSBuffers(sub); 1563 //get the size of the file we're about to open 1564 if (fFileSizesMap.find(partialName) == fFileSizesMap.end()) 1565 { 1566 struct stat st; 1567 if (!stat(partialName.c_str(), &st)) 1568 fBaseSizeNightly += st.st_size; 1569 fFileSizesMap[partialName] = 0; 1570 //remember that this file was opened. 1571 fOpenedNightlyFits[fileNameOnly] = serviceName; 1572 } 1573 sub.nightlyFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, this);//Out()); 1574 1575 //notify the opening 1576 std::string actualTargetDir; 1577 if (fNightlyFileName == ".") 1578 { 1579 char currentPath[FILENAME_MAX]; 1580 if (getcwd(currentPath, sizeof(currentPath))) 1581 actualTargetDir = currentPath; 1582 } 1583 else 1584 { 1585 actualTargetDir = fNightlyFileName; 1586 } 1587 NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 7, fOpenedNightlyFiles); 1588 if (fNumSubAndFitsIsOn) 1589 fNumSubAndFits->updateService(); 1590 if (fDebugIsOn) 1591 { 1592 stringstream str; 1593 str << "Opened Nightly FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits; 1594 Debug(str.str()); 1595 } 1596 } 1597 if (!sub.runFile.IsOpen() && (GetCurrentState() == kSM_Logging)) 1598 {//buffer for the run file have already been allocated when doing the Nightly file 1599 std::stringstream sRun; 1600 sRun << fRunNumber; 1601 #ifdef ONE_RUN_FITS_ONLY 1602 std::string fileNameOnly = sRun.str() + ".fits"; 1603 std::string partialName = fRunFileName + '/' + fileNameOnly; 1604 if (fRunFitsFile == NULL) 1605 { 1606 #else 1607 std::string fileNameOnly = sRun.str() + '_' + serviceName + ".fits"; 1608 std::string partialName = fRunFileName + '/' + fileNameOnly; 1609 #endif 1610 //get the size of the file we're about to open 1611 if (fFileSizesMap.find(partialName) == fFileSizesMap.end()) 1612 { 1613 struct stat st; 1614 if (!stat(partialName.c_str(), &st)) 1615 fBaseSizeRun += st.st_size; 1616 else 1617 fBaseSizeRun = 0; 1618 fFileSizesMap[partialName] = 0; 1619 fOpenedRunFits[fileNameOnly] = serviceName; 1620 } 1621 #ifdef ONE_RUN_FITS_ONLY 1622 try 1623 { 1624 fRunFitsFile = new CCfits::FITS(partialName, CCfits::RWmode::Write); 1625 (fNumSubAndFitsData.numOpenFits)++; 1626 } 1627 catch (CCfits::FitsError e) 1628 { 1629 std::stringstream str; 1630 str << "Could not open FITS Run file " << partialName << " reason: " << e.message(); 1631 Error(str); 1632 fRunFitsFile = NULL; 1633 } 1634 #endif 1635 std::string actualTargetDir; 1636 if (fRunFileName == ".") 1637 { 1638 char currentPath[FILENAME_MAX]; 1639 if (getcwd(currentPath, sizeof(currentPath))) 1640 actualTargetDir = currentPath; 1641 } 1642 else 1643 { 1644 actualTargetDir = fRunFileName; 1645 } 1646 NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 7, fOpenedRunFiles);// + '_' + serviceName, 4); 1647 #ifdef ONE_RUN_FITS_ONLY 1648 } 1649 sub.runFile.Open(partialName, serviceName, fRunFitsFile, &fNumSubAndFitsData.numOpenFits, this);//Out()); 1650 #else 1651 sub.runFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, this);//Out()); 1652 #endif //one_run_fits_only 1653 if (fNumSubAndFitsIsOn) 1654 fNumSubAndFits->updateService(); 1655 if (fDebugIsOn) 1656 { 1657 stringstream str; 1658 str << "Opened Run FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits; 1659 Debug(str.str()); 1660 } 1661 } 1662 } 1523 string serviceName(sub.dimInfo->getName()); 1524 //we must check if we should group this service subscription to a single fits file before we replace the / by _ 1525 bool hasGrouping = false; 1526 if (!sub.runFile.IsOpen() && (GetCurrentState() == kSM_Logging)) 1527 {//will we find this service in the grouping list ? 1528 for (set<string>::iterator it=fGrouping.begin(); it!=fGrouping.end(); it++) 1529 { 1530 if (serviceName.find(*it) != string::npos) 1531 { 1532 hasGrouping = true; 1533 break; 1534 } 1535 } 1536 } 1537 for (unsigned int i=0;i<serviceName.size(); i++) 1538 { 1539 if (serviceName[i] == '/') 1540 { 1541 serviceName[i] = '_'; 1542 break; 1543 } 1544 } 1545 Time time; 1546 stringstream sTime; 1547 sTime << time.Y() << "_" << time.M() << "_" << time.D(); 1548 //we open the NightlyFile anyway, otherwise this function shouldn't have been called. 1549 if (!sub.nightlyFile.IsOpen()) 1550 { 1551 string fileNameOnly = sTime.str() + '_' + serviceName + ".fits"; 1552 string partialName = fNightlyFileName + '/' + fileNameOnly; 1553 AllocateFITSBuffers(sub); 1554 //get the size of the file we're about to open 1555 if (fFileSizesMap.find(partialName) == fFileSizesMap.end()) 1556 { 1557 struct stat st; 1558 if (!stat(partialName.c_str(), &st)) 1559 fBaseSizeNightly += st.st_size; 1560 fFileSizesMap[partialName] = 0; 1561 //remember that this file was opened. 1562 fOpenedNightlyFits[fileNameOnly].push_back(serviceName); 1563 } 1564 sub.nightlyFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, this);//Out()); 1565 1566 //notify the opening 1567 string actualTargetDir; 1568 if (fNightlyFileName == ".") 1569 { 1570 char currentPath[FILENAME_MAX]; 1571 if (getcwd(currentPath, sizeof(currentPath))) 1572 actualTargetDir = currentPath; 1573 } 1574 else 1575 { 1576 actualTargetDir = fNightlyFileName; 1577 } 1578 NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 7, fOpenedNightlyFiles); 1579 if (fNumSubAndFitsIsOn) 1580 fNumSubAndFits->updateService(); 1581 if (fDebugIsOn) 1582 { 1583 stringstream str; 1584 str << "Opened Nightly FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits; 1585 Debug(str.str()); 1586 } 1587 } 1588 if (!sub.runFile.IsOpen() && (GetCurrentState() == kSM_Logging)) 1589 {//buffer for the run file have already been allocated when doing the Nightly file 1590 stringstream sRun; 1591 sRun << fRunNumber; 1592 string fileNameOnly; 1593 string partialName; 1594 1595 if (hasGrouping) 1596 { 1597 fileNameOnly = sRun.str() + "_group.fits"; 1598 partialName = fRunFileName + '/' + fileNameOnly; 1599 } 1600 else 1601 { 1602 fileNameOnly = sRun.str() + '_' + serviceName + ".fits"; 1603 partialName = fRunFileName + '/' + fileNameOnly; 1604 } 1605 //get the size of the file we're about to open 1606 if (fFileSizesMap.find(partialName) == fFileSizesMap.end()) 1607 { 1608 struct stat st; 1609 if (!stat(partialName.c_str(), &st)) 1610 fBaseSizeRun += st.st_size; 1611 else 1612 fBaseSizeRun = 0; 1613 fFileSizesMap[partialName] = 0; 1614 fOpenedRunFits[fileNameOnly].push_back(serviceName); 1615 } 1616 else 1617 if (hasGrouping) 1618 {//most likely I should add this service name. 1619 //the only case for which I should not add it is if a service disapeared, hence the file was closed 1620 //and reopened again. Unlikely to happen, but well it may 1621 bool found = false; 1622 for (vector<string>::iterator it=fOpenedRunFits[fileNameOnly].begin(); it!=fOpenedRunFits[fileNameOnly].end(); it++) 1623 if (*it == serviceName) 1624 { 1625 found = true; 1626 break; 1627 } 1628 if (!found) 1629 fOpenedRunFits[fileNameOnly].push_back(serviceName); 1630 } 1631 if (hasGrouping && fRunFitsFile == NULL) 1632 try 1633 { 1634 fRunFitsFile = new CCfits::FITS(partialName, CCfits::RWmode::Write); 1635 (fNumSubAndFitsData.numOpenFits)++; 1636 } 1637 catch (CCfits::FitsError e) 1638 { 1639 stringstream str; 1640 str << "Could not open FITS Run file " << partialName << " reason: " << e.message(); 1641 Error(str); 1642 fRunFitsFile = NULL; 1643 } 1644 1645 string actualTargetDir; 1646 if (fRunFileName == ".") 1647 { 1648 char currentPath[FILENAME_MAX]; 1649 if (getcwd(currentPath, sizeof(currentPath))) 1650 actualTargetDir = currentPath; 1651 } 1652 else 1653 { 1654 actualTargetDir = fRunFileName; 1655 } 1656 NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 7, fOpenedRunFiles);// + '_' + serviceName, 4); 1657 if (hasGrouping) 1658 sub.runFile.Open(partialName, serviceName, fRunFitsFile, &fNumSubAndFitsData.numOpenFits, this);//Out()); 1659 else 1660 sub.runFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, this);//Out()); 1661 1662 if (fNumSubAndFitsIsOn) 1663 fNumSubAndFits->updateService(); 1664 if (fDebugIsOn) 1665 { 1666 stringstream str; 1667 str << "Opened Run FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits; 1668 Debug(str.str()); 1669 } 1670 } 1671 } 1663 1672 // -------------------------------------------------------------------------- 1664 1673 // 1665 1674 void DataLogger::AllocateFITSBuffers(SubscriptionType& sub) 1666 1675 { 1667 1668 1669 1670 Description dateDesc(std::string("Time"), std::string("Modified Julian Date"), std::string("MjD"));1671 1672 1673 1674 1675 1676 1677 1678 1676 int size = sub.dimInfo->getSize(); 1677 1678 //Init the time columns of the file 1679 Description dateDesc(string("Time"), string("Modified Julian Date"), string("MjD")); 1680 sub.nightlyFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double)); 1681 sub.runFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double)); 1682 1683 Description QoSDesc("Qos", "Quality of service", "None"); 1684 sub.nightlyFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int)); 1685 sub.runFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int)); 1686 1687 const Converter::FormatList flist = sub.fConv->GetList(); 1679 1688 // Compilation failed 1680 1689 if (flist.empty() || flist.back().first.second!=0) 1681 1690 { 1682 1691 Error("Compilation of format string failed."); 1683 1692 return; 1684 1693 } 1685 1694 1686 //we've got a nice structure describing the format of this service's messages. 1687 //Let's create the appropriate FITS columns 1688 std::vector<std::string> dataFormatsLocal; 1689 for (unsigned int i=0;i<flist.size()-1;i++) 1690 { 1691 std::stringstream dataQualifier; 1692 1693 dataQualifier << flist[i].second.first; 1694 switch (flist[i].first.first->name()[0]) 1695 {//TODO handle all the data format cases 1696 case 'c': 1697 case 'C': 1698 dataQualifier.str("S"); 1699 break; 1700 case 's': 1701 dataQualifier << "I"; 1702 break; 1703 case 'i': 1704 case 'I': 1705 dataQualifier << "J"; 1706 break; 1707 case 'l': 1708 case 'L': 1709 dataQualifier << "J"; 1710 //TODO triple check that in FITS, long = int 1711 break; 1712 case 'f': 1713 case 'F': 1714 dataQualifier << "E"; 1715 break; 1716 case 'd': 1717 case 'D': 1718 dataQualifier << "D"; 1719 break; 1720 case 'x': 1721 case 'X': 1722 dataQualifier << "K"; 1723 break; 1724 case 'S': 1725 //for strings, the number of elements I get is wrong. Correct it 1726 dataQualifier.str(""); //clear 1727 dataQualifier << size-1 << "A"; 1728 size = size-1; 1729 break; 1730 1731 default: 1732 Fatal("THIS SHOULD NEVER BE REACHED. dataLogger.cc ln 1198."); 1733 }; 1734 //we skip the variable length strings for now (in fits only) 1735 if (dataQualifier.str() != "S") 1736 dataFormatsLocal.push_back(dataQualifier.str()); 1737 } 1738 sub.nightlyFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size); 1739 sub.runFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size); 1695 //we've got a nice structure describing the format of this service's messages. 1696 //Let's create the appropriate FITS columns 1697 vector<string> dataFormatsLocal; 1698 for (unsigned int i=0;i<flist.size()-1;i++) 1699 { 1700 stringstream dataQualifier; 1701 1702 dataQualifier << flist[i].second.first; 1703 switch (flist[i].first.first->name()[0]) 1704 { 1705 case 'c': 1706 case 'C': 1707 dataQualifier.str("S"); 1708 break; 1709 case 's': 1710 dataQualifier << "I"; 1711 break; 1712 case 'i': 1713 case 'I': 1714 dataQualifier << "J"; 1715 break; 1716 case 'l': 1717 case 'L': 1718 dataQualifier << "J"; 1719 break; 1720 case 'f': 1721 case 'F': 1722 dataQualifier << "E"; 1723 break; 1724 case 'd': 1725 case 'D': 1726 dataQualifier << "D"; 1727 break; 1728 case 'x': 1729 case 'X': 1730 dataQualifier << "K"; 1731 break; 1732 case 'S': 1733 //for strings, the number of elements I get is wrong. Correct it 1734 dataQualifier.str(""); //clear 1735 dataQualifier << size-1 << "A"; 1736 size = size-1; 1737 break; 1738 1739 default: 1740 Fatal("THIS SHOULD NEVER BE REACHED. dataLogger.cc ln 1198."); 1741 }; 1742 //we skip the variable length strings for now (in fits only) 1743 if (dataQualifier.str() != "S") 1744 dataFormatsLocal.push_back(dataQualifier.str()); 1745 } 1746 sub.nightlyFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size); 1747 sub.runFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size); 1740 1748 } 1741 1749 // -------------------------------------------------------------------------- … … 1745 1753 void DataLogger::WriteToFITS(SubscriptionType& sub) 1746 1754 { 1747 1748 1749 1750 1751 1752 1753 Debug("Writing to nightly FITS " + sub.nightlyFile.fFileName); 1754 1755 1756 1757 1758 1759 1760 1761 Debug("Writing to Run FITS " + sub.runFile.fFileName); 1762 1763 1755 //nightly File status (open or not) already checked 1756 if (sub.nightlyFile.IsOpen()) 1757 { 1758 sub.nightlyFile.Write(sub.fConv); 1759 if (fDebugIsOn) 1760 { 1761 Debug("Writing to nightly FITS " + sub.nightlyFile.fFileName); 1762 } 1763 } 1764 if (sub.runFile.IsOpen()) 1765 { 1766 sub.runFile.Write(sub.fConv); 1767 if (fDebugIsOn) 1768 { 1769 Debug("Writing to Run FITS " + sub.runFile.fFileName); 1770 } 1771 } 1764 1772 } 1765 1773 #endif //if has_fits … … 1770 1778 //! and tries to open it. 1771 1779 //! @returns 1772 //! 1780 //! kSM_Logging if success, kSM_BadRunConfig if failure. 1773 1781 int DataLogger::StartRunPlease() 1774 1782 { 1775 if (fDebugIsOn) 1776 { 1777 Debug("Starting Run Logging..."); 1778 } 1779 //attempt to open run file with current parameters 1780 // if (fRunNumber == -1) 1781 // return kSM_BadRunConfig; 1782 std::stringstream sRun; 1783 sRun << fRunNumber; 1784 fFullRunLogFileName = fRunFileName + '/' + sRun.str() + ".log"; 1785 fRunLogFile.open(fFullRunLogFileName.c_str(), std::ios_base::out | std::ios_base::app); //maybe should be app instead of ate 1786 if (errno != 0) 1787 { 1788 std::stringstream str; 1789 str << "Unable to open run Log " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1790 Error(str); 1791 } 1792 fFullRunReportFileName = fRunFileName + '/' + sRun.str() + ".rep"; 1793 fRunReportFile.open(fFullRunReportFileName.c_str(), std::ios_base::out | std::ios_base::app); 1794 if (errno != 0) 1795 { 1796 std::stringstream str; 1797 str << "Unable to open run report " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1798 Error(str); 1799 } 1800 1801 if (!fRunLogFile.is_open() || !fRunReportFile.is_open()) 1802 { 1803 //TODO send an error message 1804 return kSM_BadRunConfig; 1805 } 1806 //get the size of the newly opened file. 1807 struct stat st; 1808 fBaseSizeRun = 0; 1809 if (fFileSizesMap.find(fFullRunLogFileName) == fFileSizesMap.end()) 1810 { 1811 stat(fFullRunLogFileName.c_str(), &st); 1812 if (errno != 0) 1813 { 1814 std::stringstream str; 1815 str << "Unable to stat " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1816 Error(str); 1817 } 1818 else 1819 fBaseSizeRun += st.st_size; 1820 fFileSizesMap[fFullRunLogFileName] = 0; 1821 } 1822 if (fFileSizesMap.find(fFullRunReportFileName) == fFileSizesMap.end()) 1823 { 1824 stat(fFullRunReportFileName.c_str(), &st); 1825 if (errno != 0) 1826 { 1827 std::stringstream str; 1828 str << "Unable to stat " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1829 Error(str); 1830 } 1831 else 1832 fBaseSizeRun += st.st_size; 1833 fFileSizesMap[fFullRunReportFileName] = 0; 1834 } 1835 std::string actualTargetDir; 1836 if (fRunFileName == ".") 1837 { 1838 char currentPath[FILENAME_MAX]; 1839 if (!getcwd(currentPath, sizeof(currentPath))) 1840 { 1841 if (errno != 0) 1842 { 1843 std::stringstream str; 1844 str << "Unable to retrieve the current path" << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1845 Error(str); 1846 } 1847 } 1848 actualTargetDir = currentPath; 1849 } 1850 else 1851 { 1852 actualTargetDir = fRunFileName; 1853 } 1854 NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 3, fOpenedRunFiles); 1855 1856 fOpenedRunFits.clear(); 1857 1858 return kSM_Logging; 1783 if (fDebugIsOn) 1784 { 1785 Debug("Starting Run Logging..."); 1786 } 1787 //attempt to open run file with current parameters 1788 // if (fRunNumber == -1) 1789 // return kSM_BadRunConfig; 1790 stringstream sRun; 1791 sRun << fRunNumber; 1792 fFullRunLogFileName = fRunFileName + '/' + sRun.str() + ".log"; 1793 fRunLogFile.open(fFullRunLogFileName.c_str(), ios_base::out | ios_base::app); //maybe should be app instead of ate 1794 if (errno != 0) 1795 { 1796 stringstream str; 1797 str << "Unable to open run Log " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1798 Error(str); 1799 } 1800 fFullRunReportFileName = fRunFileName + '/' + sRun.str() + ".rep"; 1801 fRunReportFile.open(fFullRunReportFileName.c_str(), ios_base::out | ios_base::app); 1802 if (errno != 0) 1803 { 1804 stringstream str; 1805 str << "Unable to open run report " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1806 Error(str); 1807 } 1808 1809 if (!fRunLogFile.is_open() || !fRunReportFile.is_open()) 1810 { 1811 stringstream str; 1812 str << "Something went wrong while openning nightly files " << fFullRunLogFileName << " and " << fFullRunReportFileName; 1813 Error(str.str()); 1814 return kSM_BadRunConfig; 1815 } 1816 //get the size of the newly opened file. 1817 struct stat st; 1818 fBaseSizeRun = 0; 1819 if (fFileSizesMap.find(fFullRunLogFileName) == fFileSizesMap.end()) 1820 { 1821 stat(fFullRunLogFileName.c_str(), &st); 1822 if (errno != 0) 1823 { 1824 stringstream str; 1825 str << "Unable to stat " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1826 Error(str); 1827 } 1828 else 1829 fBaseSizeRun += st.st_size; 1830 fFileSizesMap[fFullRunLogFileName] = 0; 1831 } 1832 if (fFileSizesMap.find(fFullRunReportFileName) == fFileSizesMap.end()) 1833 { 1834 stat(fFullRunReportFileName.c_str(), &st); 1835 if (errno != 0) 1836 { 1837 stringstream str; 1838 str << "Unable to stat " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1839 Error(str); 1840 } 1841 else 1842 fBaseSizeRun += st.st_size; 1843 fFileSizesMap[fFullRunReportFileName] = 0; 1844 } 1845 string actualTargetDir; 1846 if (fRunFileName == ".") 1847 { 1848 char currentPath[FILENAME_MAX]; 1849 if (!getcwd(currentPath, sizeof(currentPath))) 1850 { 1851 if (errno != 0) 1852 { 1853 stringstream str; 1854 str << "Unable to retrieve the current path" << ". Reason: " << strerror(errno) << " [" << errno << "]"; 1855 Error(str); 1856 } 1857 } 1858 actualTargetDir = currentPath; 1859 } 1860 else 1861 { 1862 actualTargetDir = fRunFileName; 1863 } 1864 NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 3, fOpenedRunFiles); 1865 1866 fOpenedRunFits.clear(); 1867 1868 return kSM_Logging; 1859 1869 } 1860 1870 #ifdef HAVE_FITS 1861 1871 void DataLogger::CreateFitsGrouping(bool runGroup) 1862 1872 { 1863 //create the FITS group corresponding to the ending run.ETIENNEICI 1873 if (fDebugIsOn) 1874 { 1875 stringstream str; 1876 str << "Creating fits group for "; 1877 if (runGroup) 1878 str << "run files"; 1879 else 1880 str << "nightly files"; 1881 Debug(str.str()); 1882 } 1883 //create the FITS group corresponding to the ending run. 1864 1884 CCfits::FITS* groupFile; 1865 1866 #ifdef ONE_RUN_FITS_ONLY 1867 if (runGroup) 1868 return; 1869 #endif 1870 map<string, string>& filesToGroup = runGroup? fOpenedRunFits : fOpenedNightlyFits; 1871 unsigned int numFilesToGroup = filesToGroup.size(); 1885 map<string, vector<string> >& filesToGroup = runGroup? fOpenedRunFits : fOpenedNightlyFits; 1886 unsigned int numFilesToGroup = 0; 1887 for (map<string, vector<string> >::iterator it=filesToGroup.begin(); it != filesToGroup.end(); it++) 1888 { 1889 numFilesToGroup += it->second.size(); 1890 } 1891 if (fDebugIsOn) 1892 { 1893 stringstream str; 1894 str << "There are " << numFilesToGroup << " tables to group"; 1895 Debug(str.str()); 1896 } 1872 1897 if (numFilesToGroup <= 1) 1873 1898 { … … 1883 1908 { 1884 1909 Time time; 1885 st d::stringstream sTime;1910 stringstream sTime; 1886 1911 sTime << time.Y() << "_" << time.M() << "_" << time.D(); 1887 1912 1888 1913 groupName << fNightlyFileName << '/' << sTime.str() << ".fits"; 1889 1914 } 1915 CCfits::Table* groupTable; 1916 int maxCharLength = 50;//FILENAME_MAX; 1890 1917 try 1891 1918 { 1892 1919 groupFile = new CCfits::FITS(groupName.str(), CCfits::RWmode::Write); 1893 1920 //setup the column names 1894 int maxCharLength = FILENAME_MAX;1895 1921 stringstream pathTypeName; 1896 1922 pathTypeName << maxCharLength << "A"; … … 1905 1931 names.push_back("MEMBER_NAME"); 1906 1932 dataTypes.push_back(pathTypeName.str()); 1907 CCfits::Table* groupTable = groupFile->addTable("GROUPING", numFilesToGroup, names, dataTypes); 1933 1934 groupTable = groupFile->addTable("GROUPING", numFilesToGroup, names, dataTypes); 1908 1935 } 1909 1936 catch (CCfits::FitsError e) 1910 1937 { 1911 st d::stringstream str;1938 stringstream str; 1912 1939 str << "Could not open or create FITS table GROUPING in file " << groupName.str() << " reason: " << e.message(); 1913 1940 Error(str); … … 1920 1947 //create appropriate buffer. 1921 1948 unsigned char* fitsBuffer = new unsigned char[8 + 3 + 2*maxCharLength + 1]; //+1 for trailling character 1949 memset(fitsBuffer, 0, 8 + 3 + 2*maxCharLength + 1); 1922 1950 char* startOfExtension = reinterpret_cast<char*>(fitsBuffer); 1923 1951 char* startOfURI = reinterpret_cast<char*>(&fitsBuffer[8]); 1924 1952 char* startOfLocation = reinterpret_cast<char*>(&fitsBuffer[8 + 3]); 1925 1953 char* startOfName = reinterpret_cast<char*>(&fitsBuffer[8+3+maxCharLength]); 1954 // char* startOfNameVisible = reinterpret_cast<char*>(&fitsBuffer[8 + 3 + 2*maxCharLength]); 1926 1955 sprintf(startOfExtension, "%s", "BINTABLE"); 1927 1956 sprintf(startOfURI, "%s", "URL"); 1928 1957 int i=1; 1929 for (map<string, string>::iterator it=filesToGroup.begin(); it!=filesToGroup.end(); it++, i++) 1930 { 1931 strcpy(startOfLocation, it->first.c_str()); 1932 strcpy(startOfName, it->second.c_str()); 1933 int status = 0; 1934 fits_write_tblbytes(groupFile->fitsPointer(), i, 1, 8+3+2*maxCharLength, fitsBuffer, &status); 1935 if (status) 1936 { 1937 stringstream str; 1938 str << "Could not write row #" << i << "In the fits grouping file " << groupName << ". Cfitsio error code: " << status; 1939 Error(str.str()); 1940 } 1941 } 1958 for (map<string, vector<string> >::iterator it=filesToGroup.begin(); it!=filesToGroup.end(); it++) 1959 for (vector<string>::iterator jt=it->second.begin(); jt != it->second.end(); jt++, i++) 1960 { 1961 strcpy(startOfLocation, it->first.c_str()); 1962 strcpy(startOfName, jt->c_str()); 1963 if (fDebugIsOn) 1964 { 1965 stringstream str; 1966 str << "Grouping " << it->first << " " << *jt; 1967 Debug(str.str()); 1968 } 1969 // strcpy(startOfNameVisible, jt->c_str()); 1970 int status = 0; 1971 fits_write_tblbytes(groupFile->fitsPointer(), i, 1, 8+3+2*maxCharLength, fitsBuffer, &status); 1972 if (status) 1973 { 1974 stringstream str; 1975 str << "Could not write row #" << i << "In the fits grouping file " << groupName << ". Cfitsio error code: " << status; 1976 Error(str.str()); 1977 } 1978 } 1942 1979 1943 1980 filesToGroup.clear(); … … 1950 1987 //! Attempts to close the run file. 1951 1988 //! @returns 1952 //! 1989 //! kSM_WaitingRun if success, kSM_FatalError otherwise 1953 1990 int DataLogger::StopRunPlease() 1954 1991 { 1955 1992 1956 1957 1958 Debug("Stopping Run Logging..."); 1959 1960 1961 1962 1963 1964 1965 1993 if (fDebugIsOn) 1994 { 1995 Debug("Stopping Run Logging..."); 1996 } 1997 if (!fRunLogFile.is_open() || !fRunReportFile.is_open()) 1998 return kSM_FatalError; 1999 if (fRunLogFile.is_open()) 2000 fRunLogFile.close(); 2001 if (fRunReportFile.is_open()) 2002 fRunReportFile.close(); 1966 2003 #ifdef HAVE_FITS 1967 for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++) 1968 for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++) 1969 { 1970 if (j->second.runFile.IsOpen()) 1971 j->second.runFile.Close(); 1972 } 1973 #ifdef ONE_RUN_FITS_ONLY 1974 if (fRunFitsFile != NULL) 1975 { 1976 delete fRunFitsFile; 1977 fRunFitsFile = NULL; 1978 (fNumSubAndFitsData.numOpenFits)--; 1979 } 2004 for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++) 2005 for (map<string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++) 2006 { 2007 if (j->second.runFile.IsOpen()) 2008 j->second.runFile.Close(); 2009 } 2010 if (fRunFitsFile != NULL) 2011 { 2012 delete fRunFitsFile; 2013 fRunFitsFile = NULL; 2014 (fNumSubAndFitsData.numOpenFits)--; 2015 } 1980 2016 #endif 1981 #endif 1982 NotifyOpenedFile("", 0, fOpenedRunFiles); 1983 if (fNumSubAndFitsIsOn) 1984 fNumSubAndFits->updateService(); 1985 1986 CreateFitsGrouping(true); 1987 1988 return kSM_WaitingRun; 2017 NotifyOpenedFile("", 0, fOpenedRunFiles); 2018 if (fNumSubAndFitsIsOn) 2019 fNumSubAndFits->updateService(); 2020 2021 CreateFitsGrouping(true); 2022 2023 return kSM_WaitingRun; 1989 2024 1990 2025 } … … 1994 2029 //! Attempts to close any openned file. 1995 2030 //! @returns 1996 //! 2031 //! kSM_Ready 1997 2032 int DataLogger::GoToReadyPlease() 1998 2033 { 1999 2000 2001 2002 } 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2034 if (fDebugIsOn) 2035 { 2036 Debug("Going to the Ready state..."); 2037 } 2038 if (fNightlyLogFile.is_open()) 2039 fNightlyLogFile.close(); 2040 if (fNightlyReportFile.is_open()) 2041 fNightlyReportFile.close(); 2042 2043 if (fRunLogFile.is_open()) 2044 fRunLogFile.close(); 2045 if (fRunReportFile.is_open()) 2046 fRunReportFile.close(); 2047 2013 2048 #ifdef HAVE_FITS 2014 for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++) 2015 for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++) 2016 { 2017 if (j->second.nightlyFile.IsOpen()) 2018 j->second.nightlyFile.Close(); 2019 if (j->second.runFile.IsOpen()) 2020 j->second.runFile.Close(); 2021 } 2022 #ifdef ONE_RUN_FITS_ONLY 2023 if (fRunFitsFile != NULL) 2024 { 2025 delete fRunFitsFile; 2026 fRunFitsFile = NULL; 2027 (fNumSubAndFitsData.numOpenFits)--; 2028 } 2049 for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++) 2050 for (map<string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++) 2051 { 2052 if (j->second.nightlyFile.IsOpen()) 2053 j->second.nightlyFile.Close(); 2054 if (j->second.runFile.IsOpen()) 2055 j->second.runFile.Close(); 2056 } 2057 if (fRunFitsFile != NULL) 2058 { 2059 delete fRunFitsFile; 2060 fRunFitsFile = NULL; 2061 (fNumSubAndFitsData.numOpenFits)--; 2062 } 2029 2063 #endif 2030 #endif 2031 if (GetCurrentState() == kSM_Logging) 2032 NotifyOpenedFile("", 0, fOpenedRunFiles); 2033 if (GetCurrentState() == kSM_Logging || 2034 GetCurrentState() == kSM_WaitingRun || 2035 GetCurrentState() == kSM_NightlyOpen) 2036 { 2037 NotifyOpenedFile("", 0, fOpenedNightlyFiles); 2038 if (fNumSubAndFitsIsOn) 2039 fNumSubAndFits->updateService(); 2040 } 2041 CreateFitsGrouping(true); 2042 CreateFitsGrouping(false); 2043 2044 return kSM_Ready; 2064 if (GetCurrentState() == kSM_Logging) 2065 NotifyOpenedFile("", 0, fOpenedRunFiles); 2066 if (GetCurrentState() == kSM_Logging || 2067 GetCurrentState() == kSM_WaitingRun || 2068 GetCurrentState() == kSM_NightlyOpen) 2069 { 2070 NotifyOpenedFile("", 0, fOpenedNightlyFiles); 2071 if (fNumSubAndFitsIsOn) 2072 fNumSubAndFits->updateService(); 2073 } 2074 CreateFitsGrouping(true); 2075 CreateFitsGrouping(false); 2076 2077 return kSM_Ready; 2045 2078 } 2046 2079 // -------------------------------------------------------------------------- … … 2048 2081 //! Implements the transition towards kSM_WaitingRun 2049 2082 //! Does nothing really. 2050 //! 2051 //! 2083 //! @returns 2084 //! kSM_WaitingRun 2052 2085 int DataLogger::NightlyToWaitRunPlease() 2053 2086 { 2054 2055 2056 Debug("Going to Wait Run Number state..."); 2057 2058 return kSM_WaitingRun; 2087 if (fDebugIsOn) 2088 { 2089 Debug("Going to Wait Run Number state..."); 2090 } 2091 return kSM_WaitingRun; 2059 2092 } 2060 2093 … … 2063 2096 fDebugIsOn = conf.Get<bool>("debug"); 2064 2097 2065 2066 2067 2098 //Set the block or allow list 2099 fBlackList.clear(); 2100 fWhiteList.clear(); 2068 2101 if (conf.Has("block")) 2069 2102 { 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2103 vector<string> vec = conf.Get<vector<string>>("block"); 2104 if (vec.size() != 0) 2105 { 2106 fHasBlackList = true; 2107 if (fDebugIsOn) 2108 Debug("Setting BLOCK list:"); 2109 } 2110 for (vector<string>::iterator it = vec.begin(); it != vec.end(); it++) 2111 { 2112 fBlackList.insert(*it); 2113 if (fDebugIsOn) 2114 Debug(" " + *it); 2115 } 2083 2116 } 2084 2117 if (conf.Has("allow")) 2085 2118 { 2086 vector<string> vec = conf.Get<vector<string>>("allow"); 2087 if (vec.size() != 0) 2088 { 2089 fHasWhiteList = true; 2090 if (fDebugIsOn) 2091 Debug("Setting ALLOW list:"); 2092 } 2093 for (vector<string>::iterator it=vec.begin(); it != vec.end(); it++) 2094 { 2095 fWhiteList.insert(*it); 2096 if (fDebugIsOn) 2097 Debug(" " + *it); 2098 } 2119 vector<string> vec = conf.Get<vector<string>>("allow"); 2120 if (vec.size() != 0) 2121 { 2122 fHasWhiteList = true; 2123 if (fDebugIsOn) 2124 Debug("Setting ALLOW list:"); 2125 } 2126 for (vector<string>::iterator it=vec.begin(); it != vec.end(); it++) 2127 { 2128 fWhiteList.insert(*it); 2129 if (fDebugIsOn) 2130 Debug(" " + *it); 2131 } 2132 } 2133 //Set the grouping 2134 if (conf.Has("group")) 2135 { 2136 vector<string> vec = conf.Get<vector<string>>("group"); 2137 if (vec.size() != 0) 2138 if (fDebugIsOn) 2139 Debug("Setting GROUPING list:"); 2140 for (vector<string>::iterator it=vec.begin(); it != vec.end(); it++) 2141 { 2142 fGrouping.insert(*it); 2143 if (fDebugIsOn) 2144 Debug(" " + *it); 2145 } 2099 2146 } 2100 2147 return true; … … 2109 2156 //log.SetWindow(stdscr); 2110 2157 if (conf.Has("log")) 2111 if (!wout.OpenLogFile(conf.Get<st d::string>("log")))2112 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<st d::string>("log") << ": " << strerror(errno) << std::endl;2158 if (!wout.OpenLogFile(conf.Get<string>("log"))) 2159 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl; 2113 2160 2114 2161 // Start io_service.Run to use the StateMachineImp::Run() loop … … 2125 2172 void RunThread(DataLogger* logger) 2126 2173 { 2127 2128 2129 2130 Readline::Stop(); 2174 // This is necessary so that the StateMachine Thread can signal the 2175 // Readline thread to exit 2176 logger->Run(true); 2177 Readline::Stop(); 2131 2178 } 2132 2179 … … 2140 2187 2141 2188 if (conf.Has("log")) 2142 if (!wout.OpenLogFile(conf.Get<st d::string>("log")))2143 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<st d::string>("log") << ": " << strerror(errno) << std::endl;2189 if (!wout.OpenLogFile(conf.Get<string>("log"))) 2190 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl; 2144 2191 2145 2192 DataLogger logger(wout); … … 2149 2196 shell.SetReceiver(logger); 2150 2197 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2198 boost::thread t(boost::bind(RunThread, &logger)); 2199 2200 shell.Run(); // Run the shell 2201 2202 logger.Stop(); 2203 2204 //Wait until the StateMachine has finished its thread 2205 //before returning and destroyinng the dim objects which might 2206 //still be in use. 2207 t.join(); 2161 2208 2162 2209 return 0; … … 2235 2282 po::options_description configs("Scheduler options"); 2236 2283 configs.add_options() 2237 ("block,b", vars<string>(), "Black-list of services") 2238 ("allow,a", vars<string>(), "White-list of services") 2239 ("debug", po_bool(), "Debug mode. Print clear text of received service reports to log-stream") 2284 ("block,b", vars<string>(), "Black-list of services") 2285 ("allow,a", vars<string>(), "White-list of services") 2286 ("debug", po_bool(), "Debug mode. Print clear text of received service reports to log-stream") 2287 ("group,g", vars<string>(), "Grouping of services into a single run-Fits") 2240 2288 ; 2241 2289 … … 2257 2305 vm = conf.Parse(argc, argv); 2258 2306 } 2259 catch ( std::exception &e)2307 catch (exception &e) 2260 2308 { 2261 2309 #if BOOST_VERSION > 104000 … … 2300 2348 return RunShell<LocalConsole>(conf); 2301 2349 } 2302 /* catch ( std::exception& e)2350 /* catch (exception& e) 2303 2351 { 2304 2352 cerr << "Exception: " << e.what() << endl;
Note:
See TracChangeset
for help on using the changeset viewer.