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

Last change on this file since 10600 was 10600, checked in by tbretz, 14 years ago
Added fix because gcc 4.5 is not supported by boost 1.42 which are both part of natty.
File size: 69.4 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<1440
73#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
74#undef BOOST_HAS_RVALUE_REFS
75#error test
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, dataSize, "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").c_str(), "I:1;C", &fToDim, sizeof(int)+1,
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").c_str(), "I:1;C", &fToDim, sizeof(int)+1,
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").c_str(), "I:2", &fNumSubAndFitsData, sizeof(NumSubAndFitsType),
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 "Usage: dataLogger [-c type] [OPTIONS]\n"
2064 " or: dataLogger [OPTIONS]\n"
2065 "\n"
2066 "Options:\n"
2067 "The following describes the available commandline options. "
2068 "For further details on how command line option are parsed "
2069 "and in which order which configuration sources are accessed "
2070 "please refer to the class reference of the Configuration class.";
2071 cout << endl;
2072
2073}
2074
2075void PrintHelp()
2076{
2077 cout << "\n"
2078 "The default is that the program is started without user interaction. "
2079 "All actions are supposed to arrive as DimCommands. Using the -c "
2080 "option, a local shell can be initialized. With h or help a short "
2081 "help message about the usuage can be brought to the screen."
2082 << endl;
2083}
2084
2085/*
2086 The first line of the --version information is assumed to be in one
2087 of the following formats:
2088
2089 <version>
2090 <program> <version>
2091 {GNU,Free} <program> <version>
2092 <program> ({GNU,Free} <package>) <version>
2093 <program> - {GNU,Free} <package> <version>
2094
2095 and separated from any copyright/author details by a blank line.
2096
2097 Handle multi-line bug reporting sections of the form:
2098
2099 Report <program> bugs to <addr>
2100 GNU <package> home page: <url>
2101 ...
2102*/
2103void PrintVersion(const char *name)
2104{
2105 cout <<
2106 name << " - "PACKAGE_STRING"\n"
2107 "\n"
2108 "Written by Thomas Bretz et al.\n"
2109 "\n"
2110 "Report bugs to <"PACKAGE_BUGREPORT">\n"
2111 "Home page: "PACKAGE_URL"\n"
2112 "\n"
2113 "Copyright (C) 2011 by the FACT Collaboration.\n"
2114 "This is free software; see the source for copying conditions.\n"
2115 << endl;
2116}
2117
2118
2119void SetupConfiguration(Configuration &conf)
2120{
2121 const string n = conf.GetName()+".log";
2122
2123 po::options_description config("Program options");
2124 config.add_options()
2125 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
2126 ("log,l", var<string>(n), "Write log-file")
2127 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
2128 ("black-list,b", var<string>(""), "Black-list of services")
2129 ("white-list,w", var<string>(""), "White-list of services")
2130 ;
2131
2132 conf.AddEnv("dns", "DIM_DNS_NODE");
2133
2134 conf.AddOptions(config);
2135}
2136
2137int main(int argc, const char* argv[])
2138{
2139 Configuration conf(argv[0]);
2140 conf.SetPrintUsage(PrintUsage);
2141 SetupConfiguration(conf);
2142
2143 po::variables_map vm;
2144 try
2145 {
2146 vm = conf.Parse(argc, argv);
2147 }
2148 catch (std::exception &e)
2149 {
2150#if BOOST_VERSION > 104000
2151 po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
2152 if (MO)
2153 cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
2154 else
2155#endif
2156 cout << "Error: " << e.what() << endl;
2157 cout << endl;
2158
2159 return -1;
2160 }
2161
2162 if (conf.HasPrint())
2163 return -1;
2164
2165 if (conf.HasVersion())
2166 {
2167 PrintVersion(argv[0]);
2168 return -1;
2169 }
2170
2171 if (conf.HasHelp())
2172 {
2173 PrintHelp();
2174 return -1;
2175 }
2176
2177 setenv("DIM_DNS_NODE", conf.Get<string>("dns").c_str(), 1);
2178
2179 try
2180 {
2181 // No console access at all
2182 if (!conf.Has("console"))
2183 return RunDim(conf);
2184
2185 // Console access w/ and w/o Dim
2186 if (conf.Get<int>("console")==0)
2187 return RunShell<LocalShell>(conf);
2188 else
2189 return RunShell<LocalConsole>(conf);
2190 }
2191 catch (std::exception& e)
2192 {
2193 cerr << "Exception: " << e.what() << endl;
2194 return -1;
2195 }
2196
2197 return 0;
2198}
Note: See TracBrowser for help on using the repository browser.