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

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