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

Last change on this file since 10693 was 10693, checked in by tbretz, 9 years ago
Implemented support for compilation without fits.
File size: 74.1 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        void Setup(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 = true;//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: " << fRunFileName;
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        return GetCurrentState();
1399}
1400
1401// --------------------------------------------------------------------------
1402//
1403//! turn debug mode on and off
1404//! @param evt
1405//!             the current event. contains the instruction string: On, Off, on, off, ON, OFF, 0 or 1
1406//! @returns
1407//!             the new state. Which, in that case, is the current state
1408//!
1409int DataLogger::SetDebugOnOff(const Event& evt)
1410{
1411        bool backupDebug = fDebugIsOn;
1412        fDebugIsOn = evt.GetBool();
1413        if (fDebugIsOn == backupDebug)
1414                Warn("Warning: debug mode was already in the requested state");
1415        else
1416        {
1417                stringstream str;
1418                str << "Debug mode is now " << fDebugIsOn;
1419                Message(str.str());
1420        }
1421        return GetCurrentState();
1422}
1423// --------------------------------------------------------------------------
1424//
1425//! set the statistics update period duration. 0 disables the statistics
1426//! @param evt
1427//!             the current event. contains the new duration.
1428//! @returns
1429//!             the new state. Which, in that case, is the current state
1430//!
1431int DataLogger::SetStatsPeriod(const Event& evt)
1432{
1433        float backupDuration = fStatsPeriodDuration;
1434        fStatsPeriodDuration = evt.GetFloat();
1435        if (fStatsPeriodDuration < 0)
1436        {
1437                Error("Statistics period duration should be greater than zero. Discarding provided value.");
1438                fStatsPeriodDuration = backupDuration;
1439                return GetCurrentState();       
1440        }
1441        if (fStatsPeriodDuration != fStatsPeriodDuration)
1442        {
1443                Error("Provided duration does not appear to be a valid float. discarding it.");
1444                fStatsPeriodDuration = backupDuration;
1445                return GetCurrentState();       
1446        }
1447        if (backupDuration == fStatsPeriodDuration)
1448                Warn("Warning: statistics period was not modified: supplied value already in use");
1449        else
1450        {
1451                if (fStatsPeriodDuration == 0.0f)
1452                        Message("Statistics are now OFF");
1453                else
1454                {
1455                        stringstream str;
1456                        str << "Statistics period is now " << fStatsPeriodDuration << " seconds";
1457                        Message(str.str());     
1458                }       
1459        }
1460        return GetCurrentState();
1461}
1462// --------------------------------------------------------------------------
1463//
1464//! set the opened files service on or off.
1465//! @param evt
1466//!             the current event. contains the instruction string. similar to setdebugonoff
1467//! @returns
1468//!             the new state. Which, in that case, is the current state
1469//!
1470int DataLogger::SetOpenedFilesOnOff(const Event& evt)
1471{
1472        bool backupOpened = fOpenedFilesIsOn;
1473        fOpenedFilesIsOn = evt.GetBool();
1474        if (fOpenedFilesIsOn == backupOpened)
1475                Warn("Warning: opened files service mode was already in the requested state");
1476        else
1477        {
1478                stringstream str;
1479                str << "Opened files service mode is now " << fOpenedFilesIsOn;
1480                Message(str.str());
1481        }
1482        return GetCurrentState();
1483       
1484}
1485// --------------------------------------------------------------------------
1486//
1487//! set the number of subscriptions and opened fits on and off
1488//! @param evt
1489//!             the current event. contains the instruction string. similar to setdebugonoff
1490//! @returns
1491//!             the new state. Which, in that case, is the current state
1492//!
1493int DataLogger::SetNumSubsAndFitsOnOff(const Event& evt)
1494{
1495        bool backupSubs = fNumSubAndFitsIsOn;
1496        fNumSubAndFitsIsOn = evt.GetBool();
1497        if (fNumSubAndFitsIsOn == backupSubs)
1498                Warn("Warning: Number of subscriptions service mode was already in the requested state");
1499        else
1500        {
1501                stringstream str;
1502                str << "Number of subscriptions service mode is now " << fNumSubAndFitsIsOn;
1503                Message(str.str());
1504        }
1505        return GetCurrentState();
1506}
1507// --------------------------------------------------------------------------
1508//
1509//!     Sets the path to use for the Nightly log file.
1510//! @param evt
1511//!     the event transporting the path
1512//! @returns
1513//!             currently only the current state.
1514//
1515int DataLogger::ConfigureNightlyFileName(const Event& evt)
1516{
1517        if (evt.GetText() != NULL)
1518        {
1519                fNightlyFileName = std::string(evt.GetText()); 
1520                Message("New Nightly folder specified: " + fNightlyFileName);
1521        }
1522        else
1523                Error("Empty Nightly folder given. Please specify a valid path.");
1524
1525        return GetCurrentState();
1526}
1527// --------------------------------------------------------------------------
1528//
1529//! Sets the path to use for the run log file.
1530//! @param evt
1531//!             the event transporting the path
1532//! @returns
1533//!     currently only the current state
1534int DataLogger::ConfigureRunFileName(const Event& evt)
1535{
1536        if (evt.GetText() != NULL)
1537        {
1538                fRunFileName = std::string(evt.GetText());
1539                Message("New Run folder specified: " + fRunFileName);
1540        }
1541        else
1542                Error("Empty Nightly folder given. Please specify a valid path");
1543
1544        return GetCurrentState();
1545}
1546// --------------------------------------------------------------------------
1547//
1548//! Sets the run number.
1549//! @param evt
1550//!             the event transporting the run number
1551//! @returns
1552//!     currently only the current state
1553//TODO remove this function as the run numbers will be distributed through a dedicated service
1554int DataLogger::ConfigureRunNumber(const Event& evt)
1555{
1556        fRunNumber = evt.GetInt();
1557        std::stringstream str;
1558        str << "The new run number is: " << fRunNumber;
1559        Message(str.str());
1560        return GetCurrentState();
1561}
1562// --------------------------------------------------------------------------
1563//
1564//! Notifies the DIM service that a particular file was opened
1565//! @ param name the base name of the opened file, i.e. without path nor extension.
1566//!     WARNING: use string instead of string& because I pass values that do not convert to string&.
1567//!             this is not a problem though because file are not opened so often.
1568//! @ param type the type of the opened file. 0 = none open, 1 = log, 2 = text, 4 = fits
1569inline void DataLogger::NotifyOpenedFile(std::string name, int type, DimDescribedService* service)
1570{
1571        if (fOpenedFilesIsOn)
1572        {
1573                if (fDebugIsOn)
1574                {
1575                        stringstream str;
1576                        str << "Updating files service " << service->getName() << "with code: " << type << " and file: " << name;
1577                        Debug(str.str());
1578                        str.str("");
1579                        str << "Num subs: " << fNumSubAndFitsData.numSubscriptions << " Num open FITS: " << fNumSubAndFitsData.numOpenFits;
1580                        Debug(str.str());
1581                }
1582                OpenFileToDim fToDim;
1583                fToDim.code = type;
1584                memcpy(fToDim.fileName, name.c_str(), name.size()+1);
1585                service->setData(reinterpret_cast<void*>(&fToDim), name.size()+1+sizeof(int));
1586                service->setQuality(0);
1587                service->updateService();
1588        }
1589}
1590// --------------------------------------------------------------------------
1591//
1592//! Implements the Start transition.
1593//! Concatenates the given path for the Nightly file and the filename itself (based on the day),
1594//! and tries to open it.
1595//! @returns
1596//!             kSM_NightlyOpen if success, kSM_BadNightlyConfig if failure
1597int DataLogger::StartPlease()
1598{
1599        if (fDebugIsOn)
1600        {
1601                Debug("Starting...");   
1602        }
1603        Time time;
1604        std::stringstream sTime;
1605        sTime << time.Y() << "_" << time.M() << "_" << time.D();
1606
1607        fFullNightlyLogFileName = fNightlyFileName + '/' + sTime.str() + ".log"; 
1608        fNightlyLogFile.open(fFullNightlyLogFileName.c_str(), std::ios_base::out | std::ios_base::app); 
1609        if (errno != 0)
1610        {
1611                std::stringstream str;
1612                str << "Unable to open Nightly Log " << fFullNightlyLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1613                Error(str);     
1614        }
1615        fFullNightlyReportFileName = fNightlyFileName + '/' + sTime.str() + ".rep";
1616        fNightlyReportFile.open(fFullNightlyReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1617        if (errno != 0)
1618        {
1619                std::stringstream str;
1620                str << "Unable to open Nightly Report " << fFullNightlyReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1621                Error(str);     
1622        }
1623
1624        if (!fNightlyLogFile.is_open() || !fNightlyReportFile.is_open())
1625        {       
1626                //TODO send an error message   
1627            return kSM_BadNightlyConfig;
1628        }
1629        //get the size of the newly opened file.
1630        struct stat st;
1631        stat(fFullNightlyLogFileName.c_str(), &st);
1632        fBaseSizeNightly = st.st_size; 
1633        stat(fFullNightlyReportFileName.c_str(), &st);
1634        fBaseSizeNightly += st.st_size;
1635        fFileSizesMap.clear();
1636        fBaseSizeRun = 0;
1637        fPreviousSize = 0;
1638        //notify that files were opened
1639        std::string actualTargetDir;
1640        if (fNightlyFileName == ".")
1641        {
1642                char currentPath[FILENAME_MAX];
1643                if (!getcwd(currentPath, sizeof(currentPath)))
1644                {
1645                    if (errno != 0)
1646                    {
1647                        std::stringstream str;
1648                        str << "Unable retrieve current path" << ". Reason: " << strerror(errno) << " [" << errno << "]";
1649                        Error(str);
1650                    }
1651                }
1652                actualTargetDir = currentPath;
1653        }
1654        else
1655        {
1656                actualTargetDir = fNightlyFileName;     
1657        }
1658        //notify that a new file has been opened.
1659        NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 3, fOpenedNightlyFiles);
1660       
1661        return kSM_NightlyOpen;         
1662}
1663
1664#ifdef HAVE_FITS
1665// --------------------------------------------------------------------------
1666//
1667//! open if required a the FITS files corresponding to a given subscription
1668//! @param sub
1669//!     the current DimInfo subscription being examined
1670void DataLogger::OpenFITSFilesPlease(SubscriptionType& sub)
1671{
1672        std::string serviceName(sub.dimInfo->getName());
1673        for (unsigned int i=0;i<serviceName.size(); i++)
1674        {
1675                if (serviceName[i] == '/')
1676                {
1677                        serviceName[i] = '_';
1678                        break; 
1679                }       
1680        }
1681        Time time;
1682        std::stringstream sTime;
1683        sTime << time.Y() << "_" << time.M() << "_" << time.D();
1684        //we open the NightlyFile anyway, otherwise this function shouldn't have been called.
1685        if (!sub.nightlyFile.IsOpen())
1686        {
1687                std::string partialName = fNightlyFileName + '/' + sTime.str() + '_' + serviceName + ".fits";
1688                AllocateFITSBuffers(sub);
1689                //get the size of the file we're about to open
1690                if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1691                {
1692                        struct stat st;
1693                        if (!stat(partialName.c_str(), &st))
1694                                fBaseSizeNightly += st.st_size;
1695                        fFileSizesMap[partialName] = 0;
1696                }
1697                sub.nightlyFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, Out());
1698                //notify the opening
1699                std::string actualTargetDir;
1700                if (fNightlyFileName == ".")
1701                {
1702                        char currentPath[FILENAME_MAX];
1703                        if (getcwd(currentPath, sizeof(currentPath)))
1704                            actualTargetDir = currentPath;
1705                }
1706                else
1707                {
1708                        actualTargetDir = fNightlyFileName;     
1709                }               
1710                NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 7, fOpenedNightlyFiles);
1711                if (fNumSubAndFitsIsOn)
1712                        fNumSubAndFits->updateService();
1713                if (fDebugIsOn)
1714                {
1715                        stringstream str;
1716                        str << "Opened Nightly FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits;
1717                        Debug(str.str());       
1718                }
1719        }
1720        if (!sub.runFile.IsOpen() && (GetCurrentState() == kSM_Logging))
1721        {//buffer for the run file have already been allocated when doing the Nightly file
1722                std::stringstream sRun;
1723                sRun << fRunNumber;
1724#ifdef ONE_RUN_FITS_ONLY
1725                std::string partialName = fRunFileName + '/' + sRun.str() + ".fits";
1726                if (fRunFitsFile == NULL)
1727                {
1728#else
1729                std::string partialName = fRunFileName + '/' + sRun.str() + '_' + serviceName + ".fits";
1730#endif
1731                        //get the size of the file we're about to open
1732                        if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1733                        {
1734                                struct stat st;
1735                                if (!stat(partialName.c_str(), &st))
1736                                        fBaseSizeRun += st.st_size;
1737                                else
1738                                        fBaseSizeRun = 0;
1739                                fFileSizesMap[partialName] = 0; 
1740                        }
1741#ifdef ONE_RUN_FITS_ONLY
1742                        try
1743                        {
1744                                fRunFitsFile = new FITS(partialName, RWmode::Write);   
1745                                (fNumSubAndFitsData.numOpenFits)++;
1746                        }       
1747                        catch (CCfits::FitsError e)
1748                        {
1749                                std::stringstream str;
1750                                str << "Could not open FITS Run file " << partialName << " reason: " << e.message();
1751                                Error(str);
1752                                fRunFitsFile = NULL;
1753                        }
1754#endif
1755                        std::string actualTargetDir;
1756                        if (fRunFileName == ".")
1757                        {
1758                                char currentPath[FILENAME_MAX];
1759                                if (getcwd(currentPath, sizeof(currentPath)))
1760                                    actualTargetDir = currentPath;
1761                        }
1762                        else
1763                        {
1764                                actualTargetDir = fRunFileName; 
1765                        }               
1766                        NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 7, fOpenedRunFiles);// + '_' + serviceName, 4);
1767#ifdef ONE_RUN_FITS_ONLY
1768                }
1769                sub.runFile.Open(partialName, serviceName, fRunFitsFile, &fNumSubAndFitsData.numOpenFits, Out());
1770#else
1771                sub.runFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, Out());
1772#endif //one_run_fits_only
1773           if (fNumSubAndFitsIsOn)
1774                   fNumSubAndFits->updateService();
1775                if (fDebugIsOn)
1776                {
1777                        stringstream str;
1778                        str << "Opened Run FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits;
1779                        Debug(str.str());       
1780                }
1781        }
1782}       
1783// --------------------------------------------------------------------------
1784//
1785void DataLogger::AllocateFITSBuffers(SubscriptionType& sub)
1786{
1787        int size = sub.dimInfo->getSize();
1788         
1789        //Init the time columns of the file
1790        Description dateDesc(std::string("Time"), std::string("Modified Julian Date"), std::string("MjD"));
1791        sub.nightlyFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1792        sub.runFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1793
1794        Description QoSDesc("Qos", "Quality of service", "None");
1795        sub.nightlyFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1796        sub.runFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1797
1798        const Converter::FormatList flist = sub.fConv->GetList();
1799    // Compilation failed
1800    if (flist.empty() || flist.back().first.second!=0)
1801    {
1802        Error("Compilation of format string failed.");
1803        return;
1804    }
1805
1806        //we've got a nice structure describing the format of this service's messages.
1807        //Let's create the appropriate FITS columns
1808        std::vector<std::string> dataFormatsLocal;
1809        for (unsigned int i=0;i<flist.size()-1;i++)
1810        {
1811                std::stringstream dataQualifier; 
1812
1813                dataQualifier << flist[i].second.first;
1814                switch (flist[i].first.first->name()[0])
1815                {//TODO handle all the data format cases
1816                        case 'c':
1817                        case 'C':
1818                                dataQualifier.str("S");
1819                        break;
1820                        case 's':
1821                                dataQualifier << "I";
1822                        break;
1823                        case 'i':
1824                        case 'I':
1825                                dataQualifier << "J";
1826                        break;
1827                        case 'l':
1828                        case 'L':
1829                                dataQualifier << "J";
1830                                //TODO triple check that in FITS, long = int
1831                        break;
1832                        case 'f':
1833                        case 'F':
1834                                dataQualifier << "E";
1835                        break;
1836                        case 'd':
1837                        case 'D':
1838                                dataQualifier << "D";
1839                        break;
1840                        case 'x':
1841                        case 'X':
1842                                dataQualifier << "K";
1843                        break;
1844                        case 'S':
1845                                //for strings, the number of elements I get is wrong. Correct it
1846                                dataQualifier.str(""); //clear
1847                                dataQualifier << size-1 <<  "A";
1848                                size = size-1;
1849                        break;
1850                       
1851                        default:
1852                                Fatal("THIS SHOULD NEVER BE REACHED. dataLogger.cc ln 1198.");
1853                };
1854                //we skip the variable length strings for now (in fits only)
1855                if (dataQualifier.str() != "S")
1856                        dataFormatsLocal.push_back(dataQualifier.str());
1857         }
1858         sub.nightlyFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1859         sub.runFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1860}
1861// --------------------------------------------------------------------------
1862//
1863//! write a dimInfo data to its corresponding FITS files
1864//
1865void DataLogger::WriteToFITS(SubscriptionType& sub)
1866{
1867                //nightly File status (open or not) already checked
1868                if (sub.nightlyFile.IsOpen())
1869                {
1870                        sub.nightlyFile.Write(sub.fConv);
1871                        if (fDebugIsOn)
1872                        {
1873                                Debug("Writing to nightly FITS " + sub.nightlyFile.fFileName); 
1874                        }
1875                }
1876                if (sub.runFile.IsOpen())
1877                {
1878                        sub.runFile.Write(sub.fConv);
1879                        if (fDebugIsOn)
1880                        {
1881                                Debug("Writing to Run FITS " + sub.runFile.fFileName); 
1882                        }
1883                }
1884}
1885#endif //if has_fits
1886// --------------------------------------------------------------------------
1887//
1888//! Implements the StartRun transition.
1889//! Concatenates the given path for the run file and the filename itself (based on the run number),
1890//! and tries to open it.
1891//! @returns
1892//!             kSM_Logging if success, kSM_BadRunConfig if failure.
1893int DataLogger::StartRunPlease()
1894{
1895        if (fDebugIsOn)
1896        {
1897                Debug("Starting Run Logging...");       
1898        }
1899        //attempt to open run file with current parameters
1900//      if (fRunNumber == -1)
1901//              return kSM_BadRunConfig;
1902        std::stringstream sRun;
1903        sRun << fRunNumber;
1904        fFullRunLogFileName = fRunFileName + '/' + sRun.str() + ".log";
1905        fRunLogFile.open(fFullRunLogFileName.c_str(), std::ios_base::out | std::ios_base::app); //maybe should be app instead of ate
1906        if (errno != 0)
1907        {
1908                std::stringstream str;
1909                str << "Unable to open run Log " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1910                Error(str);     
1911        }
1912        fFullRunReportFileName = fRunFileName + '/' + sRun.str() + ".rep";
1913        fRunReportFile.open(fFullRunReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1914        if (errno != 0)
1915        {
1916                std::stringstream str;
1917                str << "Unable to open run report " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1918                Error(str);     
1919        }
1920       
1921        if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1922        {
1923                //TODO send an error message
1924                return kSM_BadRunConfig;       
1925        }
1926        //get the size of the newly opened file.
1927        struct stat st;
1928        fBaseSizeRun = 0;
1929        if (fFileSizesMap.find(fFullRunLogFileName) == fFileSizesMap.end())
1930        {
1931                stat(fFullRunLogFileName.c_str(), &st);
1932                if (errno != 0)
1933                {
1934                        std::stringstream str;
1935                        str << "Unable to stat " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1936                        Error(str);     
1937                }
1938                else
1939                        fBaseSizeRun += st.st_size;
1940                fFileSizesMap[fFullRunLogFileName] = 0;
1941        }
1942        if (fFileSizesMap.find(fFullRunReportFileName) == fFileSizesMap.end())
1943        {
1944                stat(fFullRunReportFileName.c_str(), &st);
1945                if (errno != 0)
1946                {
1947                        std::stringstream str;
1948                        str << "Unable to stat " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1949                        Error(str);     
1950                }
1951                else
1952                        fBaseSizeRun += st.st_size;
1953                fFileSizesMap[fFullRunReportFileName] = 0;
1954        }
1955        std::string actualTargetDir;
1956        if (fRunFileName == ".")
1957        {
1958                char currentPath[FILENAME_MAX];
1959                if (!getcwd(currentPath, sizeof(currentPath)))
1960                {
1961                    if (errno != 0)
1962                    {
1963                        std::stringstream str;
1964                        str << "Unable to retrieve the current path" << ". Reason: " << strerror(errno) << " [" << errno << "]";
1965                        Error(str);
1966                    }
1967                }
1968                actualTargetDir = currentPath;
1969        }
1970        else
1971        {
1972                actualTargetDir = fRunFileName; 
1973        }               
1974        NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 3, fOpenedRunFiles);
1975       
1976        return kSM_Logging;
1977}
1978// --------------------------------------------------------------------------
1979//
1980//! Implements the StopRun transition.
1981//! Attempts to close the run file.
1982//! @returns
1983//!             kSM_WaitingRun if success, kSM_FatalError otherwise
1984int DataLogger::StopRunPlease()
1985{
1986        if (fDebugIsOn)
1987        {
1988                Debug("Stopping Run Logging...");       
1989        }
1990        if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1991                return kSM_FatalError;
1992        if (fRunLogFile.is_open())
1993                fRunLogFile.close();
1994        if (fRunReportFile.is_open())
1995                fRunReportFile.close();
1996#ifdef HAVE_FITS
1997        for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
1998                for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
1999                {
2000                                if (j->second.runFile.IsOpen())
2001                                        j->second.runFile.Close();     
2002                }
2003#ifdef ONE_RUN_FITS_ONLY
2004        if (fRunFitsFile != NULL)
2005        {
2006                delete fRunFitsFile;
2007                fRunFitsFile = NULL;   
2008                (fNumSubAndFitsData.numOpenFits)--;
2009        }
2010#endif
2011#endif
2012        NotifyOpenedFile("", 0, fOpenedRunFiles);
2013        if (fNumSubAndFitsIsOn)
2014                fNumSubAndFits->updateService();
2015        return kSM_WaitingRun;
2016
2017}
2018// --------------------------------------------------------------------------
2019//
2020//! Implements the Stop and Reset transitions.
2021//! Attempts to close any openned file.
2022//! @returns
2023//!     kSM_Ready
2024int DataLogger::GoToReadyPlease()
2025{
2026        if (fDebugIsOn)
2027        {
2028                Debug("Going to the Ready state...");
2029        }       
2030        if (fNightlyLogFile.is_open())
2031                fNightlyLogFile.close();
2032        if (fNightlyReportFile.is_open())
2033                fNightlyReportFile.close();
2034
2035        if (fRunLogFile.is_open())
2036                fRunLogFile.close();
2037        if (fRunReportFile.is_open())
2038                fRunReportFile.close();
2039               
2040#ifdef HAVE_FITS
2041        for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
2042                for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
2043                {
2044                                if (j->second.nightlyFile.IsOpen())
2045                                        j->second.nightlyFile.Close();
2046                                if (j->second.runFile.IsOpen())
2047                                        j->second.runFile.Close();     
2048                }
2049#ifdef ONE_RUN_FITS_ONLY
2050        if (fRunFitsFile != NULL)
2051        {
2052                delete fRunFitsFile;
2053                fRunFitsFile = NULL;
2054                (fNumSubAndFitsData.numOpenFits)--;
2055        }
2056#endif
2057#endif
2058        if (GetCurrentState() == kSM_Logging)
2059                NotifyOpenedFile("", 0, fOpenedRunFiles);
2060        if (GetCurrentState() == kSM_Logging || 
2061            GetCurrentState() == kSM_WaitingRun || 
2062            GetCurrentState() == kSM_NightlyOpen)
2063        { 
2064                NotifyOpenedFile("", 0, fOpenedNightlyFiles);
2065                if (fNumSubAndFitsIsOn)
2066                        fNumSubAndFits->updateService();
2067        }
2068        return kSM_Ready;
2069}
2070// --------------------------------------------------------------------------
2071//
2072//! Implements the transition towards kSM_WaitingRun
2073//! Does nothing really.
2074//!     @returns
2075//!             kSM_WaitingRun
2076int DataLogger::NightlyToWaitRunPlease()
2077{
2078        if (fDebugIsOn)
2079        {
2080                Debug("Going to Wait Run Number state...");     
2081        }
2082        return kSM_WaitingRun; 
2083}
2084
2085void DataLogger::Setup(Configuration& conf)
2086{
2087        //Set the block or allow list
2088        fGreyList.clear();
2089    if (conf.Has("block"))
2090    {
2091        vector<string> vec = conf.Get<vector<string>>("block");
2092        if (vec.size() != 0)
2093        {
2094                fIsBlackList = true;
2095                if (fDebugIsOn)
2096                                Debug("Setting BLOCK list:");
2097        }
2098        else if (conf.Has("allow"))
2099        {
2100                vec = conf.Get<vector<string>>("allow");
2101                if (vec.size() != 0)
2102                {
2103                        fIsBlackList = false;
2104                        if (fDebugIsOn)
2105                                Debug("Setting ALLOW list:");
2106                }
2107        }
2108        for (vector<string>::iterator it=vec.begin(); it != vec.end(); it++)
2109        {
2110                fGreyList.insert(*it);
2111                if (fDebugIsOn)
2112                        Debug("                   " + *it);
2113        }
2114    }
2115}
2116/*
2117void DataLogger::setBlackWhiteList(const std::string& black, bool isBlack)
2118{
2119        if (fDebugIsOn)
2120        {
2121                if (isBlack)
2122                        Debug("Setting BLACK list: " + black); 
2123                else
2124                        Debug("Setting WHITE list: " + black);
2125        }
2126        fGreyList.clear();
2127        stringstream stream(black);
2128
2129        string buffer;
2130        while (getline(stream, buffer, '|')) {
2131                fGreyList.insert(buffer);       
2132        }
2133        fIsBlackList = isBlack;
2134}
2135*/
2136// --------------------------------------------------------------------------
2137
2138int RunDim(Configuration &conf)
2139{
2140    WindowLog wout;
2141
2142    //log.SetWindow(stdscr);
2143    if (conf.Has("log"))
2144        if (!wout.OpenLogFile(conf.Get<std::string>("log")))
2145            wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
2146
2147    // Start io_service.Run to use the StateMachineImp::Run() loop
2148    // Start io_service.run to only use the commandHandler command detaching
2149    DataLogger logger(wout);
2150    logger.Run(true);
2151
2152    return 0;
2153}
2154
2155void RunThread(DataLogger* logger)
2156{
2157        // This is necessary so that the StateMachine Thread can signal the
2158        // Readline thread to exit
2159        logger->Run(true);
2160        Readline::Stop();       
2161}
2162
2163template<class T>
2164int RunShell(Configuration &conf)
2165{
2166    static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
2167
2168    WindowLog &win  = shell.GetStreamIn();
2169    WindowLog &wout = shell.GetStreamOut();
2170
2171    if (conf.Has("log"))
2172        if (!wout.OpenLogFile(conf.Get<std::string>("log")))
2173            win << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
2174
2175    DataLogger logger(wout);
2176   
2177    logger.Setup(conf);
2178
2179    shell.SetReceiver(logger);
2180
2181        boost::thread t(boost::bind(RunThread, &logger));
2182       
2183        shell.Run(); // Run the shell
2184       
2185        logger.Stop();
2186       
2187        //Wait until the StateMachine has finished its thread
2188        //before returning and destroyinng the dim objects which might
2189        //still be in use.
2190        t.join();
2191
2192    return 0;
2193}
2194
2195/*
2196 Extract usage clause(s) [if any] for SYNOPSIS.
2197 Translators: "Usage" and "or" here are patterns (regular expressions) which
2198 are used to match the usage synopsis in program output.  An example from cp
2199 (GNU coreutils) which contains both strings:
2200  Usage: cp [OPTION]... [-T] SOURCE DEST
2201    or:  cp [OPTION]... SOURCE... DIRECTORY
2202    or:  cp [OPTION]... -t DIRECTORY SOURCE...
2203 */
2204void PrintUsage()
2205{
2206    cout << "\n"
2207        "The data logger connects to all available Dim services and "
2208        "writes them to ascii and fits files.\n"
2209        "\n"
2210        "The default is that the program is started without user interaction. "
2211        "All actions are supposed to arrive as DimCommands. Using the -c "
2212        "option, a local shell can be initialized. With h or help a short "
2213        "help message about the usage can be brought to the screen.\n"
2214        "\n"
2215        "Usage: dataLogger [-c type] [OPTIONS]\n"
2216        "  or:  dataLogger [OPTIONS]\n";
2217    cout << endl;
2218
2219}
2220
2221void PrintHelp()
2222{
2223    /* Additional help text which is printed after the configuration
2224     options goes here */
2225    cout <<
2226        "\n"
2227        "The block option has priority over the allow, "
2228        "i.e. if both are present, only the block list is kept. "
2229        "If only a server name or service without its server prefix is given "
2230        "then all the services of that server, or all the services that "
2231        "correspond to the given suffix are ignored or considered.\n"
2232        "\n"
2233        "For example, block=DIS_DNS will skip all the services offered by "
2234        "the DIS_DNS server, while block=SERVICE_LIST will skip all the "
2235        "SERVICE_LIST services offered by any server.\n"
2236        "\n"
2237        "The commands offered by the dataLoger are the following: \n";
2238    cout << setw(20) << DataLogger::fConfigDay << " : specify the path where to put the nightly files\n";
2239    cout << setw(20) << DataLogger::fConfigRun << " : specify the path where to put the run files\n";
2240    cout << setw(20) << DataLogger::fConfigRunNumber << " : specify the run number\n";
2241    cout << setw(20) << DataLogger::fConfigLog << " : log a particular message\n";
2242    cout << setw(20) << DataLogger::fTransStart << " : start the nightly logging\n";
2243    cout << setw(20) << DataLogger::fTransStop << " : stop the nightly logging\n";
2244    cout << setw(20) << DataLogger::fTransStartRun << " : start the run logging\n";
2245    cout << setw(20) << DataLogger::fTransStopRun << " : stop the run logging\n";
2246    cout << setw(20) << DataLogger::fTransReset << " : stop any logging and/or recover from an error state\n";
2247    cout << setw(20) << DataLogger::fTransWait << " : go to the wait for run number state\n";
2248    cout << setw(20) << DataLogger::fPrintCommand << " : print the current state of the logger to the shell\n";
2249    cout << setw(20) << DataLogger::fDebugOnOff << " : turn on or off the debug mode\n";
2250    cout << setw(20) << DataLogger::fStatsPeriod << " : set the periodicity of the statistics. 0 disable them\n";
2251    cout << endl;
2252}
2253
2254void SetupConfiguration(Configuration &conf)
2255{
2256    const string n = conf.GetName()+".log";
2257
2258    po::options_description config("Program options");
2259    config.add_options()
2260        ("dns",       var<string>("localhost"),  "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
2261        ("log,l",     var<string>(n), "Write log-file")
2262        ("console,c", var<int>(),     "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
2263        ("block,b", vars<string>(), "Black-list of services")
2264        ("allow,a", vars<string>(), "White-list of services")
2265        ;
2266
2267    conf.AddEnv("dns", "DIM_DNS_NODE");
2268
2269    conf.AddOptions(config);
2270}
2271
2272int main(int argc, const char* argv[])
2273{
2274    Configuration conf(argv[0]);
2275    conf.SetPrintUsage(PrintUsage);
2276    SetupConfiguration(conf);
2277
2278    po::variables_map vm;
2279    try
2280    {
2281        vm = conf.Parse(argc, argv);
2282    }
2283    catch (std::exception &e)
2284    {
2285#if BOOST_VERSION > 104000
2286        po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
2287        if (MO)
2288            cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
2289        else
2290#endif
2291            cout << "Error: " << e.what() << endl;
2292        cout << endl;
2293
2294        return -1;
2295    }
2296
2297    if (conf.HasPrint())
2298        return -1;
2299
2300    if (conf.HasVersion())
2301    {
2302        FACT::PrintVersion(argv[0]);
2303        return -1;
2304    }
2305
2306    if (conf.HasHelp())
2307    {
2308        PrintHelp();
2309        return -1;
2310    }
2311
2312    Dim::Setup(conf.Get<string>("dns"));
2313
2314    try
2315    {
2316        // No console access at all
2317        if (!conf.Has("console"))
2318            return RunDim(conf);
2319
2320        // Console access w/ and w/o Dim
2321        if (conf.Get<int>("console")==0)
2322            return RunShell<LocalShell>(conf);
2323        else
2324            return RunShell<LocalConsole>(conf);
2325    }
2326    catch (std::exception& e)
2327    {
2328        cerr << "Exception: " << e.what() << endl;
2329        return -1;
2330    }
2331
2332    return 0;
2333}
Note: See TracBrowser for help on using the repository browser.