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

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