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

Last change on this file since 10546 was 10546, checked in by tbretz, 9 years ago
Disabled Dim padding to be able to properly receive reports; initialize time-stamp in infoHandler
File size: 66.5 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        getInfo()->getTimestamp();
758
759        DimInfo* I = getInfo();
760        SubscriptionsListType::iterator x;
761        std::map<std::string, SubscriptionType>::iterator y;
762        if (I==NULL)
763        {
764                if (CheckForServicesUpdate())
765                {
766                        //services were updated. Notify
767                        fNumSubAndFitsData.numSubscriptions = 0;
768                        for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
769                                fNumSubAndFitsData.numSubscriptions += x->second.size();
770                        if (fNumSubAndFitsIsOn)
771                        {
772                                if (fDebugIsOn)
773                                {
774                                        stringstream str;
775                                        str << "Updating number of subscriptions service: Num Subs=" << fNumSubAndFitsData.numSubscriptions << " Num open FITS=" << fNumSubAndFitsData.numOpenFits;
776                                        Debug(str.str());       
777                                }
778                                fNumSubAndFits->updateService();
779                        }
780                }
781                return;
782        }
783        //check if the service pointer corresponds to something that we subscribed to
784        //this is a fix for a bug that provides bad Infos when a server starts
785        bool found = false;
786        for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
787        {//find current service is subscriptions
788                for (y=x->second.begin(); y!=x->second.end();y++)
789                        if (y->second.dimInfo == I)
790                        {
791                                found = true;   
792                                break;
793                        }
794                if (found)
795                        break;
796        }
797        if (!found)
798                return;
799        if (I->getSize() <= 0)
800                return;
801        //check that the message has been updated by something, i.e. must be different from its initial value
802        if (I->getTimestamp() == 0)
803                return;
804
805        CheckForRunNumber(I);
806        ReportPlease(I, y->second);
807
808}
809
810// --------------------------------------------------------------------------
811//
812//! Checks whether or not the current info is a run number.
813//! If so, then remember it. A run number is required to open the run-log file
814//! @param I
815//!             the current DimInfo
816//
817void DataLogger::CheckForRunNumber(DimInfo* I)
818{
819        if (strstr(I->getName(), fRunNumberInfo) != NULL)
820        {//assumes that the run number is an integer
821                //TODO check the format here
822                fRunNumber = I->getInt();       
823                stringstream str;
824                str << "New run number is " << fRunNumber;
825                Message(str.str());
826        }
827}
828
829// --------------------------------------------------------------------------
830//
831//! write infos to log files.
832//! @param I
833//!     The current DimInfo
834//
835void DataLogger::ReportPlease(DimInfo* I, SubscriptionType& sub)
836{
837        //should we log or report this info ? (i.e. is it a message ?)
838        bool isItaReport = ((strstr(I->getName(), "Message") == NULL) && (strstr(I->getName(), "MESSAGE") == NULL));
839        if (I->getFormat()[0] == 'C')
840                isItaReport = false;
841        //TODO add service exclusion
842       
843        if (!fNightlyReportFile.is_open())
844                return;
845
846        //create the converter for that service
847        if (sub.fConv == NULL && isItaReport)
848        {
849                //trick the converter in case of 'C'. why do I do this ? well simple: the converter checks that the right number
850                //of bytes was written. because I skip 'C' with fits, the bytes will not be allocated, hence the "size copied ckeck"
851                //of the converter will fail, hence throwing an exception.
852                std::string fakeFormat(I->getFormat());
853                if (fakeFormat[fakeFormat.size()-1] == 'C')
854                        fakeFormat = fakeFormat.substr(0, fakeFormat.size()-1);
855                sub.fConv = new Converter(Out(), I->getFormat());       
856                if (!sub.fConv)
857                {
858                        std::stringstream str;
859                        str << "Couldn't properly parse the format... service " << sub.dimInfo->getName() << " ignored.";
860                        Error(str);
861                        return; 
862                }
863        }
864               
865        //construct the header
866        std::stringstream header;
867        Time cTime(I->getTimestamp(), I->getTimestampMillisecs()*1000);
868        fQuality = I->getQuality();
869        fMjD = cTime.Mjd();
870
871        if (isItaReport)
872        {
873                //write text header
874                header << I->getName() << " " << fQuality << " ";
875                header << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
876                header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
877                header << cTime.ms() << " " << I->getTimestamp() << " ";
878
879                std::string text;
880        try
881        {
882                text = sub.fConv->GetString(I->getData(), I->getSize());
883        }
884        catch (const std::runtime_error &e)
885        {
886                Out() << kRed << e.what() << endl;
887                std::stringstream str;
888                str << "Could not properly parse the data for service " << sub.dimInfo->getName();
889                str << " reason: " << e.what() << ". Entry ignored";
890            Error(str);
891            return;
892        }
893
894                if (text.empty())
895                {
896                        std::stringstream str;
897                        str << "Service " << sub.dimInfo->getName() << " sent an empty string";
898                        Info(str);
899                return;
900                }
901        //replace bizarre characters by white space
902        replace(text.begin(), text.end(), '\n', '\\');
903        replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');
904       
905        //write entry to Nightly report
906                if (fNightlyReportFile.is_open())
907                {
908                        if (fDebugIsOn)
909                        {
910                                stringstream str;
911                                str << "Writing: \"" << header.str() << text << "\" to Nightly report file";
912                                Debug(str.str());       
913                        }
914                        fNightlyReportFile << header.str() << text << std::endl;
915                        //check if either eof, bailbit or batbit are set
916                        if (!fNightlyReportFile.good())
917                        {
918                                Error("An error occured while writing to the nightly report file. Closing it");
919                                if (fNightlyReportFile.is_open())
920                                        fNightlyReportFile.close();
921                        }
922                }
923                //write entry to run-report
924                if (fRunReportFile.is_open())
925                {
926                        if (fDebugIsOn)
927                        {
928                                stringstream str;
929                                str << "Writing: \"" << header.str() << text << "\" to Run report file";
930                                Debug(str.str());       
931                        }
932                        fRunReportFile << header.str() << text << std::endl;
933                        if (!fRunReportFile.good())
934                        {
935                                Error("An error occured while writing to the run report file. Closing it.");
936                                if (fRunReportFile.is_open())
937                                        fRunReportFile.close(); 
938                        }
939                }
940        }
941        else
942        {//write entry to both Nightly and run logs
943                std::string n = I->getName();
944                std::stringstream msg;
945                msg << n.substr(0, n.find_first_of('/')) << ": " << I->getString();
946
947                if (fNightlyLogFile.is_open())
948                {
949                        if (fDebugIsOn)
950                        {
951                                stringstream str;
952                                str << "Writing: \"" << msg.str() << "\" to Nightly log file";
953                                Debug(str.str());       
954                        }
955                        MessageImp nightlyMess(fNightlyLogFile);
956                        nightlyMess.Write(cTime, msg.str().c_str(), fQuality);
957                        if (!fNightlyLogFile.good())
958                        {
959                                Error("An error occured while writing to the nightly log file. Closing it.");
960                                if (fNightlyLogFile.is_open())
961                                        fNightlyLogFile.close();       
962                        }
963                }
964                if (fRunLogFile.is_open())
965                {
966                        if (fDebugIsOn)
967                        {
968                                stringstream str;
969                                str << "Writing: \"" << msg.str() << "\" to Run log file";
970                                Debug(str.str());       
971                        }
972                        MessageImp runMess(fRunLogFile);
973                        runMess.Write(cTime, msg.str().c_str(), fQuality);
974                        if (!fRunLogFile.good())
975                        {
976                                Error("An error occured while writing to the run log file. Closing it.");
977                                if (fRunLogFile.is_open())
978                                        fRunLogFile.close();   
979                        }
980                }
981        }
982
983#ifdef HAS_FITS
984        if (isItaReport)
985        {
986                if (!sub.nightlyFile.IsOpen() || !sub.runFile.IsOpen())
987                        OpenFITSFilesPlease(sub);       
988                WriteToFITS(sub);
989        }       
990#endif
991
992}
993
994// --------------------------------------------------------------------------
995//
996//! write messages to logs.
997//! @param evt
998//!             the current event to log
999//! @returns
1000//!             the new state. Currently, always the current state
1001//!
1002//! @deprecated
1003//!    I guess that this function should not be any longer
1004//
1005//TODO isn't that function not used any longer ? If so I guess that we should get rid of it...
1006//Otherwise re-write it properly with the MessageImp class
1007int DataLogger::LogMessagePlease(const Event& evt)
1008{
1009        if (!fNightlyLogFile.is_open())
1010                return GetCurrentState();
1011       
1012        std::stringstream header;
1013        const Time& cTime = evt.GetTime();
1014        header << evt.GetName() << " " << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
1015        header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
1016        header << cTime.ms() << " ";
1017               
1018    const Converter conv(Out(), evt.GetFormat());
1019    if (!conv)
1020    {
1021        Error("Couldn't properly parse the format... ignored.");
1022        return GetCurrentState();
1023    }
1024
1025    std::string text;
1026    try
1027    {
1028        text = conv.GetString(evt.GetData(), evt.GetSize());
1029    }
1030    catch (const std::runtime_error &e)
1031    {
1032        Out() << kRed << e.what() << endl;
1033        Error("Couldn't properly parse the data... ignored.");
1034        return GetCurrentState();
1035    }
1036
1037        if (text.empty())
1038        return GetCurrentState();
1039
1040    //replace bizarre characters by white space
1041    replace(text.begin(), text.end(), '\n', '\\');
1042    replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');
1043        if (fDebugIsOn)
1044        {
1045                stringstream str;
1046                str << "Logging: \"" << header << text << "\"";
1047                Debug(str.str());       
1048        }
1049       
1050        if (fNightlyLogFile.is_open())
1051        {
1052                fNightlyLogFile << header;
1053                if (!fNightlyLogFile.good())
1054                {
1055                        Error("An error occured while writing to the run log file. Closing it.");
1056                        if (fNightlyLogFile.is_open())
1057                                fNightlyLogFile.close();       
1058                }
1059        }
1060        if (fRunLogFile.is_open())
1061        {
1062                fRunLogFile << header;
1063                if (!fRunLogFile.good())
1064                {
1065                        Error("An error occured while writing to the run log file. Closing it.");
1066                        if (fRunLogFile.is_open())
1067                                fRunLogFile.close();   
1068                }
1069        }
1070        if (fNightlyLogFile.is_open())
1071        {
1072                fNightlyLogFile << text;
1073                if (!fNightlyLogFile.good())
1074                {
1075                        Error("An error occured while writing to the run log file. Closing it.");
1076                        if (fNightlyLogFile.is_open())
1077                                fNightlyLogFile.close();       
1078                }
1079        }
1080        if (fRunLogFile.is_open())
1081        {
1082                fRunLogFile << text;
1083                if (!fRunLogFile.good())
1084                {
1085                        Error("An error occured while writing to the run log file. Closing it.");
1086                        if (fRunLogFile.is_open())
1087                                fRunLogFile.close();   
1088                }
1089        }
1090        return GetCurrentState();
1091}
1092// --------------------------------------------------------------------------
1093//
1094//! print the dataLogger's current state. invoked by the PRINT command
1095//! @param evt
1096//!             the current event. Not used by the method
1097//! @returns
1098//!             the new state. Which, in that case, is the current state
1099//!
1100int DataLogger::PrintStatePlease(const Event& )
1101{
1102        Message("-----------------------------------------");
1103        Message("------DATA LOGGER CURRENT STATE----------");
1104        Message("-----------------------------------------");
1105        //print the path configuration
1106        std::string actualTargetDir;
1107        if (fNightlyFileName == ".")
1108        {
1109            char currentPath[FILENAME_MAX];
1110            if (getcwd(currentPath, sizeof(currentPath)))
1111                actualTargetDir = currentPath;
1112        }
1113        else
1114                actualTargetDir = fNightlyFileName;
1115        Message("Nightly Path: " + actualTargetDir);
1116        if (fRunFileName == ".")
1117        {
1118            char currentPath[FILENAME_MAX];
1119            if (getcwd(currentPath, sizeof(currentPath)))
1120                actualTargetDir = currentPath;
1121        }
1122        else
1123                actualTargetDir = fRunFileName;
1124        Message("Run Path: " + actualTargetDir);
1125        stringstream str;
1126        str << "Run Number: " << fRunFileName;
1127        Message(str.str());
1128        Message("-----------OPENED FILES------------------");
1129        //print all the open files.
1130        if (fNightlyLogFile.is_open())
1131                Message("Nightly Log..........OPEN");
1132        else
1133                Message("Nightly log........CLOSED");
1134        if (fNightlyReportFile.is_open())
1135                Message("Nightly Report.......OPEN");
1136        else
1137                Message("Nightly Report.....CLOSED");
1138        if (fRunLogFile.is_open())
1139                Message("Run Log..............OPEN");
1140        else
1141                Message("Run Log............CLOSED");
1142        if (fRunReportFile.is_open())
1143                Message("Run Report...........OPEN");
1144        else
1145                Message("Run Report.........CLOSED");
1146#ifdef HAS_FITS
1147        str.str("");
1148        str << "There are " << fNumSubAndFitsData.numOpenFits << " FITS files open:";
1149        Message(str.str());
1150        SubscriptionsListType::iterator x;
1151        std::map<std::string, SubscriptionType>::iterator y;
1152        bool runFileDone = false;
1153        for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
1154        {
1155                for (y=x->second.begin(); y != x->second.end(); y++)
1156                {
1157                        if (y->second.runFile.IsOpen() && !runFileDone)
1158                        {
1159                                        fFileSizesMap[y->second.runFile.fFileName] = y->second.runFile.GetWrittenSize();
1160                                        str.str("");
1161                                        str << ">>>" << y->second.runFile.fFileName;
1162                                        Message(str.str());
1163#ifdef ONE_FITS_ONLY
1164                                        runFileDone = true;
1165#endif
1166                        }
1167                        if (y->second.nightlyFile.IsOpen())
1168                        {
1169                                fFileSizesMap[y->second.nightlyFile.fFileName] = y->second.nightlyFile.GetWrittenSize();
1170                                str.str("");
1171                                str << ">>>" << y->second.nightlyFile.fFileName;
1172                                Message(str.str());
1173                        }
1174                }
1175        }
1176#else
1177        Message("FITS output disabled at compilation");
1178#endif
1179        struct stat st;
1180        DataLoggerStats statVar;
1181        //gather log and report files sizes on disk
1182        if (fNightlyLogFile.is_open())
1183        {
1184                stat(fFullNightlyLogFileName.c_str(), &st);
1185                fFileSizesMap[fFullNightlyLogFileName] = st.st_size;   
1186        }
1187        if (fNightlyReportFile.is_open())
1188        {
1189                stat(fFullNightlyReportFileName.c_str(), &st);
1190                fFileSizesMap[fFullNightlyReportFileName] = st.st_size; 
1191        }
1192        if (fRunLogFile.is_open())
1193        {
1194                stat(fFullRunLogFileName.c_str(), &st);
1195                fFileSizesMap[fFullRunLogFileName] = st.st_size;       
1196        }
1197        if (fRunReportFile.is_open())
1198        {
1199                stat(fFullRunReportFileName.c_str(), &st);
1200                fFileSizesMap[fFullRunReportFileName] = st.st_size;
1201        }       
1202        struct statvfs vfs;
1203        if (!statvfs(fNightlyFileName.c_str(), &vfs))
1204        {
1205                statVar.freeSpace = vfs.f_bsize*vfs.f_bavail;
1206        }
1207        else
1208        {
1209                str.str("");
1210                str << "Unable to retrieve stats for " << fNightlyFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1211                Error(str);;
1212                statVar.freeSpace = -1;
1213        }
1214       
1215        //sum up all the file sizes. past and present
1216        statVar.sizeWritten = 0;
1217        for (std::map<std::string, long>::iterator it=fFileSizesMap.begin(); it != fFileSizesMap.end();  it++)
1218                statVar.sizeWritten += it->second;
1219        statVar.sizeWritten -= fBaseSizeNightly;
1220        statVar.sizeWritten -= fBaseSizeRun;
1221        str.str("");
1222        str << "Total Size written: " << statVar.sizeWritten;
1223        str << " Disk free space: " << statVar.freeSpace;
1224        Message("-----------------STATS-------------------");
1225        Message(str.str());
1226        Message("------------DIM SUBSCRIPTIONS------------");
1227        str.str("");
1228        str << "There are " << fNumSubAndFitsData.numSubscriptions << " active DIM subscriptions:";
1229        Message(str.str());
1230        str.str("");
1231        for (std::map<const std::string, std::map<std::string, SubscriptionType>>::const_iterator it=fServiceSubscriptions.begin(); it!= fServiceSubscriptions.end();it++)
1232        {
1233                str << "Server " << it->first;
1234                Message(str.str());
1235                for (std::map<std::string, SubscriptionType>::const_iterator it2=it->second.begin(); it2!=it->second.end(); it2++)
1236                {
1237                        str.str("");
1238                        str << "     " << it2->first;
1239                        Message(str.str());     
1240                }       
1241        }
1242        Message("-----------------------------------------");
1243       
1244        return GetCurrentState();
1245}
1246
1247// --------------------------------------------------------------------------
1248//
1249//! turn debug mode on and off
1250//! @param evt
1251//!             the current event. contains the instruction string: On, Off, on, off, ON, OFF, 0 or 1
1252//! @returns
1253//!             the new state. Which, in that case, is the current state
1254//!
1255int DataLogger::SetDebugOnOff(const Event& evt)
1256{
1257        bool backupDebug = fDebugIsOn;
1258        fDebugIsOn = evt.GetBool();
1259        if (fDebugIsOn == backupDebug)
1260                Warn("Warning: debug mode was already in the requested state");
1261        else
1262        {
1263                stringstream str;
1264                str << "Debug mode is now " << fDebugIsOn;
1265                Message(str.str());
1266        }
1267        return GetCurrentState();
1268}
1269// --------------------------------------------------------------------------
1270//
1271//! set the statistics update period duration. 0 disables the statistics
1272//! @param evt
1273//!             the current event. contains the new duration.
1274//! @returns
1275//!             the new state. Which, in that case, is the current state
1276//!
1277int DataLogger::SetStatsPeriod(const Event& evt)
1278{
1279        float backupDuration = fStatsPeriodDuration;
1280        fStatsPeriodDuration = evt.GetFloat();
1281        if (fStatsPeriodDuration < 0)
1282        {
1283                Error("Statistics period duration should be greater than zero. Discarding provided value.");
1284                fStatsPeriodDuration = backupDuration;
1285                return GetCurrentState();       
1286        }
1287        if (fStatsPeriodDuration != fStatsPeriodDuration)
1288        {
1289                Error("Provided duration does not appear to be a valid float. discarding it.");
1290                fStatsPeriodDuration = backupDuration;
1291                return GetCurrentState();       
1292        }
1293        if (backupDuration == fStatsPeriodDuration)
1294                Warn("Warning: statistics period was not modified: supplied value already in use");
1295        else
1296        {
1297                if (fStatsPeriodDuration == 0.0f)
1298                        Message("Statistics are now OFF");
1299                else
1300                {
1301                        stringstream str;
1302                        str << "Statistics period is now " << fStatsPeriodDuration << " seconds";
1303                        Message(str.str());     
1304                }       
1305        }
1306        return GetCurrentState();
1307}
1308// --------------------------------------------------------------------------
1309//
1310//! set the opened files service on or off.
1311//! @param evt
1312//!             the current event. contains the instruction string. similar to setdebugonoff
1313//! @returns
1314//!             the new state. Which, in that case, is the current state
1315//!
1316int DataLogger::SetOpenedFilesOnOff(const Event& evt)
1317{
1318        bool backupOpened = fOpenedFilesIsOn;
1319        fOpenedFilesIsOn = evt.GetBool();
1320        if (fOpenedFilesIsOn == backupOpened)
1321                Warn("Warning: opened files service mode was already in the requested state");
1322        else
1323        {
1324                stringstream str;
1325                str << "Opened files service mode is now " << fOpenedFilesIsOn;
1326                Message(str.str());
1327        }
1328        return GetCurrentState();
1329       
1330}
1331// --------------------------------------------------------------------------
1332//
1333//! set the number of subscriptions and opened fits on and off
1334//! @param evt
1335//!             the current event. contains the instruction string. similar to setdebugonoff
1336//! @returns
1337//!             the new state. Which, in that case, is the current state
1338//!
1339int DataLogger::SetNumSubsAndFitsOnOff(const Event& evt)
1340{
1341        bool backupSubs = fNumSubAndFitsIsOn;
1342        fNumSubAndFitsIsOn = evt.GetBool();
1343        if (fNumSubAndFitsIsOn == backupSubs)
1344                Warn("Warning: Number of subscriptions service mode was already in the requested state");
1345        else
1346        {
1347                stringstream str;
1348                str << "Number of subscriptions service mode is now " << fNumSubAndFitsIsOn;
1349                Message(str.str());
1350        }
1351        return GetCurrentState();
1352}
1353// --------------------------------------------------------------------------
1354//
1355//!     Sets the path to use for the Nightly log file.
1356//! @param evt
1357//!     the event transporting the path
1358//! @returns
1359//!             currently only the current state.
1360//
1361int DataLogger::ConfigureNightlyFileName(const Event& evt)
1362{
1363        if (evt.GetText() != NULL)
1364        {
1365                fNightlyFileName = std::string(evt.GetText()); 
1366                Message("New Nightly folder specified: " + fNightlyFileName);
1367        }
1368        else
1369                Error("Empty Nightly folder given. Please specify a valid path.");
1370
1371        return GetCurrentState();
1372}
1373// --------------------------------------------------------------------------
1374//
1375//! Sets the path to use for the run log file.
1376//! @param evt
1377//!             the event transporting the path
1378//! @returns
1379//!     currently only the current state
1380int DataLogger::ConfigureRunFileName(const Event& evt)
1381{
1382        if (evt.GetText() != NULL)
1383        {
1384                fRunFileName = std::string(evt.GetText());
1385                Message("New Run folder specified: " + fRunFileName);
1386        }
1387        else
1388                Error("Empty Nightly folder given. Please specify a valid path");
1389
1390        return GetCurrentState();
1391}
1392// --------------------------------------------------------------------------
1393//
1394//! Sets the run number.
1395//! @param evt
1396//!             the event transporting the run number
1397//! @returns
1398//!     currently only the current state
1399//TODO remove this function as the run numbers will be distributed through a dedicated service
1400int DataLogger::ConfigureRunNumber(const Event& evt)
1401{
1402        fRunNumber = evt.GetInt();
1403        std::stringstream str;
1404        str << "The new run number is: " << fRunNumber;
1405        Message(str.str());
1406        return GetCurrentState();
1407}
1408// --------------------------------------------------------------------------
1409//
1410//! Notifies the DIM service that a particular file was opened
1411//! @ param name the base name of the opened file, i.e. without path nor extension.
1412//!     WARNING: use string instead of string& because I pass values that do not convert to string&.
1413//!             this is not a problem though because file are not opened so often.
1414//! @ param type the type of the opened file. 0 = none open, 1 = log, 2 = text, 4 = fits
1415inline void DataLogger::NotifyOpenedFile(std::string name, int type, DimDescribedService* service)
1416{
1417        if (fOpenedFilesIsOn)
1418        {
1419                if (fDebugIsOn)
1420                {
1421                        stringstream str;
1422                        str << "Updating files service " << service->getName() << "with code: " << type << " and file: " << name;
1423                        Debug(str.str());
1424                        str.str("");
1425                        str << "Num subs: " << fNumSubAndFitsData.numSubscriptions << " Num open FITS: " << fNumSubAndFitsData.numOpenFits;
1426                        Debug(str.str());
1427                }
1428                OpenFileToDim fToDim;
1429                fToDim.code = type;
1430                memcpy(fToDim.fileName, name.c_str(), name.size()+1);
1431                service->setData(reinterpret_cast<void*>(&fToDim), name.size()+1+sizeof(int));
1432                service->setQuality(0);
1433                service->updateService();
1434        }
1435}
1436// --------------------------------------------------------------------------
1437//
1438//! Implements the Start transition.
1439//! Concatenates the given path for the Nightly file and the filename itself (based on the day),
1440//! and tries to open it.
1441//! @returns
1442//!             kSM_NightlyOpen if success, kSM_BadNightlyConfig if failure
1443int DataLogger::StartPlease()
1444{
1445        if (fDebugIsOn)
1446        {
1447                Debug("Starting...");   
1448        }
1449        Time time;
1450        std::stringstream sTime;
1451        sTime << time.Y() << "_" << time.M() << "_" << time.D();
1452
1453        fFullNightlyLogFileName = fNightlyFileName + '/' + sTime.str() + ".log"; 
1454        fNightlyLogFile.open(fFullNightlyLogFileName.c_str(), std::ios_base::out | std::ios_base::app); 
1455        if (errno != 0)
1456        {
1457                std::stringstream str;
1458                str << "Unable to open Nightly Log " << fFullNightlyLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1459                Error(str);     
1460        }
1461        fFullNightlyReportFileName = fNightlyFileName + '/' + sTime.str() + ".rep";
1462        fNightlyReportFile.open(fFullNightlyReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1463        if (errno != 0)
1464        {
1465                std::stringstream str;
1466                str << "Unable to open Nightly Report " << fFullNightlyReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1467                Error(str);     
1468        }
1469
1470        if (!fNightlyLogFile.is_open() || !fNightlyReportFile.is_open())
1471        {       
1472                //TODO send an error message   
1473            return kSM_BadNightlyConfig;
1474        }
1475        //get the size of the newly opened file.
1476        struct stat st;
1477        stat(fFullNightlyLogFileName.c_str(), &st);
1478        fBaseSizeNightly = st.st_size; 
1479        stat(fFullNightlyReportFileName.c_str(), &st);
1480        fBaseSizeNightly += st.st_size;
1481        fFileSizesMap.clear();
1482        fBaseSizeRun = 0;
1483        fPreviousSize = 0;
1484        //notify that files were opened
1485        std::string actualTargetDir;
1486        if (fNightlyFileName == ".")
1487        {
1488                char currentPath[FILENAME_MAX];
1489                if (!getcwd(currentPath, sizeof(currentPath)))
1490                {
1491                    if (errno != 0)
1492                    {
1493                        std::stringstream str;
1494                        str << "Unable retrieve current path" << ". Reason: " << strerror(errno) << " [" << errno << "]";
1495                        Error(str);
1496                    }
1497                }
1498                actualTargetDir = currentPath;
1499        }
1500        else
1501        {
1502                actualTargetDir = fNightlyFileName;     
1503        }
1504        //notify that a new file has been opened.
1505        NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 3, fOpenedNightlyFiles);
1506       
1507        return kSM_NightlyOpen;         
1508}
1509
1510#ifdef HAS_FITS
1511// --------------------------------------------------------------------------
1512//
1513//! open if required a the FITS files corresponding to a given subscription
1514//! @param sub
1515//!     the current DimInfo subscription being examined
1516void DataLogger::OpenFITSFilesPlease(SubscriptionType& sub)
1517{
1518        std::string serviceName(sub.dimInfo->getName());
1519        for (unsigned int i=0;i<serviceName.size(); i++)
1520        {
1521                if (serviceName[i] == '/')
1522                {
1523                        serviceName[i] = '_';
1524                        break; 
1525                }       
1526        }
1527        Time time;
1528        std::stringstream sTime;
1529        sTime << time.Y() << "_" << time.M() << "_" << time.D();
1530        //we open the NightlyFile anyway, otherwise this function shouldn't have been called.
1531        if (!sub.nightlyFile.IsOpen())
1532        {
1533                std::string partialName = fNightlyFileName + '/' + sTime.str() + '_' + serviceName + ".fits";
1534                AllocateFITSBuffers(sub);
1535                //get the size of the file we're about to open
1536                if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1537                {
1538                        struct stat st;
1539                        if (!stat(partialName.c_str(), &st))
1540                                fBaseSizeNightly += st.st_size;
1541                        fFileSizesMap[partialName] = 0;
1542                }
1543                sub.nightlyFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, Out());
1544                //notify the opening
1545                std::string actualTargetDir;
1546                if (fNightlyFileName == ".")
1547                {
1548                        char currentPath[FILENAME_MAX];
1549                        if (getcwd(currentPath, sizeof(currentPath)))
1550                            actualTargetDir = currentPath;
1551                }
1552                else
1553                {
1554                        actualTargetDir = fNightlyFileName;     
1555                }               
1556                NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 4, fOpenedNightlyFiles);
1557                if (fNumSubAndFitsIsOn)
1558                        fNumSubAndFits->updateService();
1559                if (fDebugIsOn)
1560                {
1561                        stringstream str;
1562                        str << "Opened Nightly FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits;
1563                        Debug(str.str());       
1564                }
1565        }
1566        if (!sub.runFile.IsOpen() && (GetCurrentState() == kSM_Logging))
1567        {//buffer for the run file have already been allocated when doing the Nightly file
1568                std::stringstream sRun;
1569                sRun << fRunNumber;
1570#ifdef ONE_RUN_FITS_ONLY
1571                std::string partialName = fRunFileName + '/' + sRun.str() + ".fits";
1572                if (fRunFitsFile == NULL)
1573                {
1574#else
1575                std::string partialName = fRunFileName + '/' + sRun.str() + '_' + serviceName + ".fits";
1576#endif
1577                        //get the size of the file we're about to open
1578                        if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1579                        {
1580                                struct stat st;
1581                                if (!stat(partialName.c_str(), &st))
1582                                        fBaseSizeRun += st.st_size;
1583                                else
1584                                        fBaseSizeRun = 0;
1585                                fFileSizesMap[partialName] = 0; 
1586                        }
1587#ifdef ONE_RUN_FITS_ONLY
1588                        try
1589                        {
1590                                fRunFitsFile = new FITS(partialName, RWmode::Write);   
1591                                (fNumSubAndFitsData.numOpenFits)++;
1592                        }       
1593                        catch (CCfits::FitsError e)
1594                        {
1595                                std::stringstream str;
1596                                str << "Could not open FITS Run file " << partialName << " reason: " << e.message();
1597                                Error(str);
1598                                fRunFitsFile = NULL;
1599                        }
1600#endif
1601                        std::string actualTargetDir;
1602                        if (fRunFileName == ".")
1603                        {
1604                                char currentPath[FILENAME_MAX];
1605                                if (getcwd(currentPath, sizeof(currentPath)))
1606                                    actualTargetDir = currentPath;
1607                        }
1608                        else
1609                        {
1610                                actualTargetDir = fRunFileName; 
1611                        }               
1612                        NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 4, fOpenedRunFiles);// + '_' + serviceName, 4);
1613#ifdef ONE_RUN_FITS_ONLY
1614                }
1615                sub.runFile.Open(partialName, serviceName, fRunFitsFile, &fNumSubAndFitsData.numOpenFits, Out());
1616#else
1617                sub.runFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, Out());
1618#endif //one_run_fits_only
1619           if (fNumSubAndFitsIsOn)
1620                   fNumSubAndFits->updateService();
1621                if (fDebugIsOn)
1622                {
1623                        stringstream str;
1624                        str << "Opened Run FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits;
1625                        Debug(str.str());       
1626                }
1627        }
1628}       
1629// --------------------------------------------------------------------------
1630//
1631void DataLogger::AllocateFITSBuffers(SubscriptionType& sub)
1632{
1633        int size = sub.dimInfo->getSize();
1634         
1635        //Init the time columns of the file
1636        Description dateDesc(std::string("Time"), std::string("Modified Julian Date"), std::string("MjD"));
1637        sub.nightlyFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1638        sub.runFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1639
1640        Description QoSDesc("Qos", "Quality of service", "None");
1641        sub.nightlyFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1642        sub.runFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1643
1644        const Converter::FormatList flist = sub.fConv->GetList();
1645    // Compilation failed
1646    if (flist.empty() || flist.back().first.second!=0)
1647    {
1648        Error("Compilation of format string failed.");
1649        return;
1650    }
1651
1652        //we've got a nice structure describing the format of this service's messages.
1653        //Let's create the appropriate FITS columns
1654        std::vector<std::string> dataFormatsLocal;
1655        for (unsigned int i=0;i<flist.size()-1;i++)
1656        {
1657                std::stringstream dataQualifier; 
1658
1659                dataQualifier << flist[i].second.first;
1660                switch (flist[i].first.first->name()[0])
1661                {//TODO handle all the data format cases
1662                        case 'c':
1663                        case 'C':
1664                                dataQualifier.str("S");
1665                        break;
1666                        case 's':
1667                                dataQualifier << "I";
1668                        break;
1669                        case 'i':
1670                        case 'I':
1671                                dataQualifier << "J";
1672                        break;
1673                        case 'l':
1674                        case 'L':
1675                                dataQualifier << "J";
1676                                //TODO triple check that in FITS, long = int
1677                        break;
1678                        case 'f':
1679                        case 'F':
1680                                dataQualifier << "E";
1681                        break;
1682                        case 'd':
1683                        case 'D':
1684                                dataQualifier << "D";
1685                        break;
1686                        case 'x':
1687                        case 'X':
1688                                dataQualifier << "K";
1689                        break;
1690                        case 'S':
1691                                //for strings, the number of elements I get is wrong. Correct it
1692                                dataQualifier.str(""); //clear
1693                                dataQualifier << size-1 <<  "A";
1694                                size = size-1;
1695                        break;
1696                       
1697                        default:
1698                                Error("THIS SHOULD NEVER BE REACHED. dataLogger.cc ln 1198.");
1699                };
1700                //we skip the variable length strings for now (in fits only)
1701                if (dataQualifier.str() != "S")
1702                        dataFormatsLocal.push_back(dataQualifier.str());
1703         }
1704         sub.nightlyFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1705         sub.runFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1706}
1707// --------------------------------------------------------------------------
1708//
1709//! write a dimInfo data to its corresponding FITS files
1710//
1711void DataLogger::WriteToFITS(SubscriptionType& sub)
1712{
1713                //nightly File status (open or not) already checked
1714                if (sub.nightlyFile.IsOpen())
1715                {
1716                        sub.nightlyFile.Write(sub.fConv);
1717                        if (fDebugIsOn)
1718                        {
1719                                Debug("Writing to nightly FITS " + sub.nightlyFile.fFileName); 
1720                        }
1721                }
1722                if (sub.runFile.IsOpen())
1723                {
1724                        sub.runFile.Write(sub.fConv);
1725                        if (fDebugIsOn)
1726                        {
1727                                Debug("Writing to Run FITS " + sub.runFile.fFileName); 
1728                        }
1729                }
1730}
1731#endif //if has_fits
1732// --------------------------------------------------------------------------
1733//
1734//! Implements the StartRun transition.
1735//! Concatenates the given path for the run file and the filename itself (based on the run number),
1736//! and tries to open it.
1737//! @returns
1738//!             kSM_Logging if success, kSM_BadRunConfig if failure.
1739int DataLogger::StartRunPlease()
1740{
1741        if (fDebugIsOn)
1742        {
1743                Debug("Starting Run Logging...");       
1744        }
1745        //attempt to open run file with current parameters
1746        if (fRunNumber == -1)
1747                return kSM_BadRunConfig;
1748        std::stringstream sRun;
1749        sRun << fRunNumber;
1750        fFullRunLogFileName = fRunFileName + '/' + sRun.str() + ".log";
1751        fRunLogFile.open(fFullRunLogFileName.c_str(), std::ios_base::out | std::ios_base::app); //maybe should be app instead of ate
1752        if (errno != 0)
1753        {
1754                std::stringstream str;
1755                str << "Unable to open run Log " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1756                Error(str);     
1757        }
1758        fFullRunReportFileName = fRunFileName + '/' + sRun.str() + ".rep";
1759        fRunReportFile.open(fFullRunReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1760        if (errno != 0)
1761        {
1762                std::stringstream str;
1763                str << "Unable to open run report " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1764                Error(str);     
1765        }
1766       
1767        if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1768        {
1769                //TODO send an error message
1770                return kSM_BadRunConfig;       
1771        }
1772        //get the size of the newly opened file.
1773        struct stat st;
1774        fBaseSizeRun = 0;
1775        if (fFileSizesMap.find(fFullRunLogFileName) == fFileSizesMap.end())
1776        {
1777                stat(fFullRunLogFileName.c_str(), &st);
1778                if (errno != 0)
1779                {
1780                        std::stringstream str;
1781                        str << "Unable to stat " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1782                        Error(str);     
1783                }
1784                else
1785                        fBaseSizeRun += st.st_size;
1786                fFileSizesMap[fFullRunLogFileName] = 0;
1787        }
1788        if (fFileSizesMap.find(fFullRunReportFileName) == fFileSizesMap.end())
1789        {
1790                stat(fFullRunReportFileName.c_str(), &st);
1791                if (errno != 0)
1792                {
1793                        std::stringstream str;
1794                        str << "Unable to stat " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1795                        Error(str);     
1796                }
1797                else
1798                        fBaseSizeRun += st.st_size;
1799                fFileSizesMap[fFullRunReportFileName] = 0;
1800        }
1801        std::string actualTargetDir;
1802        if (fRunFileName == ".")
1803        {
1804                char currentPath[FILENAME_MAX];
1805                if (!getcwd(currentPath, sizeof(currentPath)))
1806                {
1807                    if (errno != 0)
1808                    {
1809                        std::stringstream str;
1810                        str << "Unable to retrieve the current path" << ". Reason: " << strerror(errno) << " [" << errno << "]";
1811                        Error(str);
1812                    }
1813                }
1814                actualTargetDir = currentPath;
1815        }
1816        else
1817        {
1818                actualTargetDir = fRunFileName; 
1819        }               
1820        NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 3, fOpenedRunFiles);
1821       
1822        return kSM_Logging;
1823}
1824// --------------------------------------------------------------------------
1825//
1826//! Implements the StopRun transition.
1827//! Attempts to close the run file.
1828//! @returns
1829//!             kSM_WaitingRun if success, kSM_FatalError otherwise
1830int DataLogger::StopRunPlease()
1831{
1832        if (fDebugIsOn)
1833        {
1834                Debug("Stopping Run Logging...");       
1835        }
1836        if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1837                return kSM_FatalError;
1838       
1839        fRunLogFile.close();
1840        fRunReportFile.close();
1841#ifdef HAS_FITS
1842        for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
1843                for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
1844                {
1845                                if (j->second.runFile.IsOpen())
1846                                        j->second.runFile.Close();     
1847                }
1848#ifdef ONE_RUN_FITS_ONLY
1849        if (fRunFitsFile != NULL)
1850        {
1851                delete fRunFitsFile;
1852                fRunFitsFile = NULL;   
1853                (fNumSubAndFitsData.numOpenFits)--;
1854        }
1855#endif
1856#endif
1857        NotifyOpenedFile("", 0, fOpenedRunFiles);
1858        if (fNumSubAndFitsIsOn)
1859                fNumSubAndFits->updateService();
1860        return kSM_WaitingRun;
1861
1862}
1863// --------------------------------------------------------------------------
1864//
1865//! Implements the Stop and Reset transitions.
1866//! Attempts to close any openned file.
1867//! @returns
1868//!     kSM_Ready
1869int DataLogger::GoToReadyPlease()
1870{
1871        if (fDebugIsOn)
1872        {
1873                Debug("Going to the Ready state...");
1874        }       
1875        if (fNightlyLogFile.is_open())
1876                fNightlyLogFile.close();
1877        if (fNightlyReportFile.is_open())
1878                fNightlyReportFile.close();
1879
1880        if (fRunLogFile.is_open())
1881                fRunLogFile.close();
1882        if (fRunReportFile.is_open())
1883                fRunReportFile.close();
1884               
1885#ifdef HAS_FITS
1886        for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
1887                for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
1888                {
1889                                if (j->second.nightlyFile.IsOpen())
1890                                        j->second.nightlyFile.Close();
1891                                if (j->second.runFile.IsOpen())
1892                                        j->second.runFile.Close();     
1893                }
1894#ifdef ONE_RUN_FITS_ONLY
1895        if (fRunFitsFile != NULL)
1896        {
1897                delete fRunFitsFile;
1898                fRunFitsFile = NULL;
1899                (fNumSubAndFitsData.numOpenFits)--;
1900        }
1901#endif
1902#endif
1903        if (GetCurrentState() == kSM_Logging)
1904                NotifyOpenedFile("", 0, fOpenedRunFiles);
1905        if (GetCurrentState() == kSM_Logging || 
1906            GetCurrentState() == kSM_WaitingRun || 
1907            GetCurrentState() == kSM_NightlyOpen)
1908        { 
1909                NotifyOpenedFile("", 0, fOpenedNightlyFiles);
1910                if (fNumSubAndFitsIsOn)
1911                        fNumSubAndFits->updateService();
1912        }
1913        return kSM_Ready;
1914}
1915// --------------------------------------------------------------------------
1916//
1917//! Implements the transition towards kSM_WaitingRun
1918//! Does nothing really.
1919//!     @returns
1920//!             kSM_WaitingRun
1921int DataLogger::NightlyToWaitRunPlease()
1922{
1923        if (fDebugIsOn)
1924        {
1925                Debug("Going to Wait Run Number state...");     
1926        }
1927        return kSM_WaitingRun; 
1928}
1929
1930void DataLogger::setBlackWhiteList(const std::string& black, bool isBlack)
1931{
1932        if (fDebugIsOn)
1933        {
1934                if (isBlack)
1935                        Debug("Setting BLACK list: " + black); 
1936                else
1937                        Debug("Setting WHITE list: " + black);
1938        }
1939        fGreyList.clear();
1940        stringstream stream(black);
1941
1942        string buffer;
1943        while (getline(stream, buffer, '|')) {
1944                fGreyList.insert(buffer);       
1945        }
1946        fIsBlackList = isBlack;
1947}
1948
1949// --------------------------------------------------------------------------
1950
1951int RunDim(Configuration &conf)
1952{
1953    WindowLog wout;
1954
1955    //log.SetWindow(stdscr);
1956    if (conf.Has("log"))
1957        if (!wout.OpenLogFile(conf.Get<std::string>("log")))
1958            wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
1959
1960    // Start io_service.Run to use the StateMachineImp::Run() loop
1961    // Start io_service.run to only use the commandHandler command detaching
1962    DataLogger logger(wout);
1963    logger.Run(true);
1964
1965    return 0;
1966}
1967
1968void RunThread(DataLogger* logger)
1969{
1970        // This is necessary so that the StateMachine Thread can signal the
1971        // Readline thread to exit
1972        logger->Run(true);
1973        Readline::Stop();       
1974}
1975
1976template<class T>
1977int RunShell(Configuration &conf)
1978{
1979    static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1980
1981    WindowLog &win  = shell.GetStreamIn();
1982    WindowLog &wout = shell.GetStreamOut();
1983
1984    if (conf.Has("log"))
1985        if (!wout.OpenLogFile(conf.Get<std::string>("log")))
1986            win << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
1987
1988    DataLogger logger(wout);
1989   
1990    if (conf.Has("black-list"))
1991    {   if (conf.Get<std::string>("black-list") != "")
1992                logger.setBlackWhiteList(conf.Get<std::string>("black-list"), true);
1993            else if (conf.Has("white-list"))
1994                {
1995                        if (conf.Get<std::string>("white-list") != "")
1996                                logger.setBlackWhiteList(conf.Get<std::string>("white-list"), false);
1997                }
1998    }
1999    shell.SetReceiver(logger);
2000
2001        boost::thread t(boost::bind(RunThread, &logger));
2002       
2003        shell.Run(); // Run the shell
2004       
2005        logger.Stop();
2006       
2007        //Wait until the StateMachine has finished its thread
2008        //before returning and destroyinng the dim objects which might
2009        //still be in use.
2010        t.join();
2011
2012    return 0;
2013}
2014
2015/*
2016 Extract usage clause(s) [if any] for SYNOPSIS.
2017 Translators: "Usage" and "or" here are patterns (regular expressions) which
2018 are used to match the usage synopsis in program output.  An example from cp
2019 (GNU coreutils) which contains both strings:
2020  Usage: cp [OPTION]... [-T] SOURCE DEST
2021    or:  cp [OPTION]... SOURCE... DIRECTORY
2022    or:  cp [OPTION]... -t DIRECTORY SOURCE...
2023 */
2024void PrintUsage()
2025{
2026    cout << "\n"
2027        "The data logger connects to all available Dim services and "
2028        "writes them to ascii and fits files.\n"
2029        "\n"
2030        "Usage: dataLogger [-c type] [OPTIONS]\n"
2031        "  or:  dataLogger [OPTIONS]\n"
2032        "\n"
2033        "Options:\n"
2034        "The following describes the available commandline options. "
2035        "For further details on how command line option are parsed "
2036        "and in which order which configuration sources are accessed "
2037        "please refer to the class reference of the Configuration class.";
2038    cout << endl;
2039
2040}
2041
2042void PrintHelp()
2043{
2044    cout << "\n"
2045        "The default is that the program is started without user interaction. "
2046        "All actions are supposed to arrive as DimCommands. Using the -c "
2047        "option, a local shell can be initialized. With h or help a short "
2048        "help message about the usuage can be brought to the screen."
2049        << endl;
2050}
2051
2052/*
2053 The first line of the --version information is assumed to be in one
2054 of the following formats:
2055
2056   <version>
2057   <program> <version>
2058   {GNU,Free} <program> <version>
2059   <program> ({GNU,Free} <package>) <version>
2060   <program> - {GNU,Free} <package> <version>
2061
2062 and separated from any copyright/author details by a blank line.
2063
2064 Handle multi-line bug reporting sections of the form:
2065
2066   Report <program> bugs to <addr>
2067   GNU <package> home page: <url>
2068   ...
2069*/
2070void PrintVersion(const char *name)
2071{
2072    cout <<
2073        name << " - "PACKAGE_STRING"\n"
2074        "\n"
2075        "Written by Thomas Bretz et al.\n"
2076        "\n"
2077        "Report bugs to <"PACKAGE_BUGREPORT">\n"
2078        "Home page: "PACKAGE_URL"\n"
2079        "\n"
2080        "Copyright (C) 2011 by the FACT Collaboration.\n"
2081        "This is free software; see the source for copying conditions.\n"
2082        << endl;
2083}
2084
2085
2086void SetupConfiguration(Configuration &conf)
2087{
2088    const string n = conf.GetName()+".log";
2089
2090    po::options_description config("Program options");
2091    config.add_options()
2092        ("dns",       var<string>("localhost"),  "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
2093        ("log,l",     var<string>(n), "Write log-file")
2094        ("console,c", var<int>(),     "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
2095        ("black-list,b", var<string>(""), "Black-list of services")
2096        ("white-list,w", var<string>(""), "White-list of services")
2097        ;
2098
2099    conf.AddEnv("dns", "DIM_DNS_NODE");
2100
2101    conf.AddOptions(config);
2102}
2103
2104int main(int argc, const char* argv[])
2105{
2106    Configuration conf(argv[0]);
2107    conf.SetPrintUsage(PrintUsage);
2108    SetupConfiguration(conf);
2109
2110    po::variables_map vm;
2111    try
2112    {
2113        vm = conf.Parse(argc, argv);
2114    }
2115    catch (std::exception &e)
2116    {
2117#if BOOST_VERSION > 104000
2118        po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
2119        if (MO)
2120            cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
2121        else
2122#endif
2123            cout << "Error: " << e.what() << endl;
2124        cout << endl;
2125
2126        return -1;
2127    }
2128
2129    if (conf.HasPrint())
2130        return -1;
2131
2132    if (conf.HasVersion())
2133    {
2134        PrintVersion(argv[0]);
2135        return -1;
2136    }
2137
2138    if (conf.HasHelp())
2139    {
2140        PrintHelp();
2141        return -1;
2142    }
2143
2144    setenv("DIM_DNS_NODE", conf.Get<string>("dns").c_str(), 1);
2145
2146    try
2147    {
2148        // No console access at all
2149        if (!conf.Has("console"))
2150            return RunDim(conf);
2151
2152        // Console access w/ and w/o Dim
2153        if (conf.Get<int>("console")==0)
2154            return RunShell<LocalShell>(conf);
2155        else
2156            return RunShell<LocalConsole>(conf);
2157    }
2158    catch (std::exception& e)
2159    {
2160        cerr << "Exception: " << e.what() << endl;
2161        return -1;
2162    }
2163
2164    return 0;
2165}
Note: See TracBrowser for help on using the repository browser.