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

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