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

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