source: trunk/FACT++/src/dataLogger.cc@ 10623

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