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

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