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

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