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

Last change on this file since 10453 was 10453, checked in by tbretz, 9 years ago
Commented unused functions; fixed a bug in the naming of the services; replaced DimService by DimDescribedService; added dummy descriptions to states and events.
File size: 45.6 KB
Line 
1//****************************************************************
2/** @class DataLogger
3 
4  @brief Logs all message and infos between the services
5 
6  This is the main logging class facility.
7  It derives from StateMachineDim and DimInfoHandler. the first parent is here to enforce
8  a state machine behaviour, while the second one is meant to make the dataLogger receive
9  dim services to which it subscribed from.
10  The possible states and transitions of the machine are:
11  \dot
12  digraph datalogger {
13                node [shape=record, fontname=Helvetica, fontsize=10];
14        e [label="Error" color="red"];
15   r [label="Ready"]
16   d [label="DailyOpen"]
17   w [label="WaitingRun"]
18        l [label="Logging"]
19   b [label="BadDailyconfig" 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//for getting stat of opened files
58#include <unistd.h>
59//for getting disk free space
60#include <sys/statvfs.h>
61//for getting files sizes
62#include <sys/stat.h>
63
64//#define HAS_FITS
65
66#include <fstream>
67
68#include <boost/bind.hpp>
69#include <boost/thread.hpp>
70
71#ifdef HAS_FITS
72//#include <astroroot.h>
73#include "Fits.h"
74#endif
75
76class DataLogger : public StateMachineDim, DimInfoHandler
77{
78public:
79        /// The list of existing states specific to the DataLogger
80        enum
81        {
82                kSM_DailyOpen = 20, ///< Daily file openned and writing
83                kSM_WaitingRun = 30, ///< waiting for the run number to open the run file
84                kSM_Logging = 40, ///< both files openned and writing
85                kSM_BadDailyConfig = 0x101, ///< the folder specified for daily logging does not exist or has bad permissions
86                kSM_BadRunConfig = 0x102, ///<  the folder specified for the run logging does not exist or has wrong permissions or no run number
87        } localstates_t;
88       
89        DataLogger(std::ostream &out);
90        ~DataLogger(); 
91       
92private:
93        //Define all the data structure specific to the DataLogger here
94        /// ofstream for the dailyLogfile
95        std::ofstream fDailyLogFile;
96        /// ofstream for the run-specific Log file
97        std::ofstream fRunLogFile; 
98
99        /// ofstream for the daily report file
100        std::ofstream fDailyReportFile;
101        /// ofstream for the run-specific report file
102        std::ofstream fRunReportFile;
103        /// base path of the dailyfile
104        std::string fDailyFileName; 
105        ///base path of the run file
106        std::string fRunFileName; 
107        ///run number (-1 means no run number specified)
108        int fRunNumber; 
109        ///Current year
110//      short fYear;
111        ///Current Month
112//      short fMonth;
113        ///Current Day
114//      short fDay;
115        ///Current Hour
116//      short fHour;
117        ///Current Minute
118//      short fMin;
119        ///Current Second
120//      short fSec;
121        ///Current Milliseconds
122//      int fMs;
123        ///Current Service Quality
124        int fQuality;
125        ///Modified Julian Date
126        double fMjD;
127       
128        ///Define all the static names
129        static const char* fConfigDay;
130        static const char* fConfigRun;
131        static const char* fConfigRunNumber;
132        static const char* fConfigLog;
133        static const char* fTransStart;
134        static const char* fTransStop;
135        static const char* fTransStartRun;
136        static const char* fTransStopRun;
137        static const char* fTransReset;
138        static const char* fTransWait;
139        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
140        ///Inherited from state machine impl
141        //int Execute();
142       
143        ///Inherited from state machine impl
144        //int Transition(const Event& evt);
145       
146        ///Inherited from state machine impl
147        //int Configure(const Event& evt);
148       
149        //overloading of DIM's infoHandler function
150        void infoHandler(); 
151       
152        ///for obtaining the name of the existing services
153        ServiceList fServiceList;
154       
155       
156        ///A std pair to store both the DimInfo name and the actual DimInfo pointer
157//      typedef std::pair<std::string, DimStampedInfo*> subscriptionType;
158        ///All the services to which we've subscribed to. Sorted by server name
159//      std::map<const std::string, std::vector<subscriptionType > > fServiceSubscriptions;
160
161        ///A std pair to store both the DimInfo pointer and the corresponding outputted fits file
162        struct SubscriptionType
163        { 
164#ifdef HAS_FITS
165                ///daily FITS output file
166                Fits    dailyFile;
167                ///run-specific FITS output file
168                Fits    runFile;
169#endif
170                ///the actual dimInfo pointer
171                DimStampedInfo* dimInfo;
172                ///the converter for outputting the data according to the format
173                Converter* fConv;
174                ///the number of existing handlers to this structure.
175                ///This is required otherwise I MUST handle the deleting of dimInfo outside from the destructor
176                int* numCopies;
177                void operator = (const SubscriptionType& other)
178                {
179#ifdef HAS_FITS
180                        dailyFile = other.dailyFile;
181                        runFile = other.runFile;
182#endif
183                        dimInfo = other.dimInfo;       
184                        numCopies = other.numCopies;
185                        fConv = other.fConv;
186                        (*numCopies)++;
187                }
188                SubscriptionType(const SubscriptionType& other)
189                {
190#ifdef HAS_FITS
191                        dailyFile = other.dailyFile;
192                        runFile = other.runFile;
193#endif
194                        dimInfo = other.dimInfo;
195                        numCopies = other.numCopies;
196                        fConv = other.fConv;
197                        (*numCopies)++; 
198                }
199                SubscriptionType(DimStampedInfo* info)
200                {
201                        dimInfo = info; 
202                        fConv = NULL;
203                        numCopies = new int(1);
204                }
205                SubscriptionType()
206                {
207                        dimInfo = NULL;
208                        fConv = NULL;
209                        numCopies = new int(1);
210                }
211                ~SubscriptionType()
212                {
213                        if (numCopies)
214                        (*numCopies)--;
215                        if (numCopies)
216                        if (*numCopies < 1)
217                        {
218#ifdef HAS_FITS
219                                if (dailyFile.IsOpen())
220                                        dailyFile.Close();
221                                if (runFile.IsOpen())
222                                        runFile.Close();
223#endif
224                                if (dimInfo)
225                                delete dimInfo;
226                                if (numCopies) 
227                                delete numCopies;
228                                delete fConv;
229                                fConv = NULL;
230                                dimInfo = NULL;
231                                numCopies = NULL;
232                        }
233                }
234        };
235        typedef std::map<const std::string, std::map<std::string, SubscriptionType>> SubscriptionsListType;
236        ///All the services to which we have subscribed to, sorted by server name.
237        SubscriptionsListType fServiceSubscriptions;
238
239
240        ///Reporting method for the services info received
241        void ReportPlease(DimInfo* I, SubscriptionType& sub); 
242
243        ///Configuration of the daily file path
244        int ConfigureDailyFileName(const Event& evt); 
245        ///Configuration fo the file name
246        int ConfigureRunFileName(const Event& evt); 
247        ///DEPREC - configuration of the run number
248        int ConfigureRunNumber(const Event& evt); 
249        ///logging method for the messages
250        int LogMessagePlease(const Event& evt); 
251        ///checks whether or not the current info being treated is a run number
252        void CheckForRunNumber(DimInfo* I); 
253        /// start transition
254        int StartPlease(); 
255        ///from waiting to logging transition
256        int StartRunPlease(); 
257        /// from logging to waiting transition
258        int StopRunPlease(); 
259        ///stop and reset transition
260        int GoToReadyPlease(); 
261        ///from dailyOpen to waiting transition
262        int DailyToWaitRunPlease(); 
263#ifdef HAS_FITS
264        ///Open fits files
265        void OpenFITSFilesPlease(SubscriptionType& sub);
266        ///Write data to FITS files
267        void WriteToFITS(SubscriptionType& sub);
268        ///Allocate the buffers required for fits
269        void AllocateFITSBuffers(SubscriptionType& sub);
270        ///FITS file for runs. only one, hence dealt with in the dataLogger itself
271        FITS* fRunFitsFile;
272#endif
273public: 
274        ///checks with fServiceList whether or not the services got updated
275        void CheckForServicesUpdate(); 
276
277private:       
278        ///monitoring notification loop
279        void ServicesMonitoring();
280        ///services notification thread
281        boost::thread fMonitoringThread;
282        ///end of the monitoring
283        bool fContinueMonitoring;
284        ///required for accurate monitoring
285        std::map<std::string, long long> fFileSizesMap;
286        std::string fFullDailyLogFileName;
287        std::string fFullDailyReportFileName;
288        std::string fFullRunLogFileName;
289        std::string fFullRunReportFileName;
290        long long fBaseSizeDaily;
291        long long fPreviousSize;
292        long long fBaseSizeRun;
293        ///Service for opened files
294        DimService* fOpenedFiles;
295        char* fDimBuffer;
296        inline void NotifyOpenedFile(std::string name, int type);
297       
298}; //DataLogger
299
300//static members initialization
301//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 ?
302const char* DataLogger::fConfigDay = "CONFIG_DAY";
303const char* DataLogger::fConfigRun = "CONFIG_RUN";
304const char* DataLogger::fConfigRunNumber = "CONFIG_RUN_NUMBER";
305const char* DataLogger::fConfigLog = "LOG";
306const char* DataLogger::fTransStart = "START";
307const char* DataLogger::fTransStop = "STOP";
308const char* DataLogger::fTransStartRun = "START_RUN";
309const char* DataLogger::fTransStopRun = "STOP_RUN";
310const char* DataLogger::fTransReset = "RESET";
311const char* DataLogger::fTransWait = "WAIT_RUN_NUMBER";
312const char* DataLogger::fRunNumberInfo = "RUN_NUMBER";
313
314void DataLogger::ServicesMonitoring()
315{
316                //create the DIM service
317                int dataSize = 2*sizeof(long long) + sizeof(long);
318                char* data = new char[dataSize];
319                memset(data, 0, dataSize);
320                DimDescribedService srvc((GetName()+"/STATS").c_str(), "x:2;l:1", static_cast<void*>(data), dataSize,
321                                        "Add description here");
322                double deltaT = 1;
323                fPreviousSize = 0;
324
325                long long& targetSize  = reinterpret_cast<long long*>(data)[0];
326                long long& targetFreeSpace  = reinterpret_cast<long long*>(data)[1];
327                long& targetRate = reinterpret_cast<long*>(data + 2*sizeof(long long))[0];
328                //loop-wait for broadcast
329                while (fContinueMonitoring)
330                {
331                        sleep(deltaT);
332                        //update the fits files sizes
333#ifdef HAS_FITS
334                        SubscriptionsListType::iterator x;
335                        std::map<std::string, SubscriptionType>::iterator y;
336                        bool runFileDone = false;
337                        for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
338                        {
339                                for (y=x->second.begin(); y != x->second.end(); y++)
340                                {
341                                        if (y->second.runFile.IsOpen() && !runFileDone)
342                                        {
343                                                        fFileSizesMap[y->second.runFile.fFileName] = y->second.runFile.GetWrittenSize();
344                                                        runFileDone = true;
345                                        }
346                                        if (y->second.dailyFile.IsOpen())
347                                                fFileSizesMap[y->second.dailyFile.fFileName] = y->second.dailyFile.GetWrittenSize();
348                                }
349                        }
350#endif
351                        struct stat st;
352                        //gather log and report files sizes on disk
353                        if (fDailyLogFile.is_open())
354                        {
355                                stat(fFullDailyLogFileName.c_str(), &st);
356                                fFileSizesMap[fFullDailyLogFileName] = st.st_size;     
357                        }
358                        if (fDailyReportFile.is_open())
359                        {
360                                stat(fFullDailyReportFileName.c_str(), &st);
361                                fFileSizesMap[fFullDailyReportFileName] = st.st_size;   
362                        }
363                        if (fRunLogFile.is_open())
364                        {
365                                stat(fFullRunLogFileName.c_str(), &st);
366                                fFileSizesMap[fFullRunLogFileName] = st.st_size;       
367                        }
368                        if (fRunReportFile.is_open())
369                        {
370                                stat(fFullRunReportFileName.c_str(), &st);
371                                fFileSizesMap[fFullRunReportFileName] = st.st_size;
372                        }       
373                        if (fDailyLogFile.is_open())
374                        {
375                                struct statvfs vfs;
376                                statvfs(fDailyFileName.c_str(), &vfs);
377                                targetFreeSpace = vfs.f_bsize*vfs.f_bavail;
378                        }
379                        //sum up all the file sizes. past and present
380                        targetSize = 0;
381                        for (std::map<std::string, long long>::iterator it=fFileSizesMap.begin(); it != fFileSizesMap.end();  it++)
382                                targetSize += it->second;
383                        targetSize -= fBaseSizeDaily;
384                        targetSize -= fBaseSizeRun;
385                        //FIXME get the actual time elapsed
386                        targetRate = (targetSize - fPreviousSize)/deltaT; 
387                        fPreviousSize = targetSize;
388//                      if (targetRate != 0) //if data has been written
389                        {
390std::cout << "fBaseSizeDaily: " << fBaseSizeDaily << " fBaseSizeRun: " << fBaseSizeRun << std::endl;
391//std::cout << "Written Size: " << targetSize << ", free space: " << targetFreeSpace << ", data rate: " << targetRate << " Bytes/s" << std::endl;
392
393                                srvc.updateService(static_cast<void*>(data), dataSize);
394                        }
395                }
396                delete[] data;
397}
398
399
400// --------------------------------------------------------------------------
401//
402//! Default constructor. The name of the machine is given DATA_LOGGER
403//! and the state is set to kSM_Ready at the end of the function.
404//
405//!Setup the allows states, configs and transitions for the data logger
406//
407DataLogger::DataLogger(std::ostream &out) : StateMachineDim(out, "DATA_LOGGER")
408{       
409                //initialize member data
410                fDailyFileName = ".";
411                fRunFileName = ".";
412                fRunNumber = 12345;
413#ifdef HAS_FITS
414                fRunFitsFile = NULL;
415#endif
416                //Give a name to this machine's specific states
417                AddStateName(kSM_DailyOpen,      "DailyFileOpen",  "Add description here");
418                AddStateName(kSM_WaitingRun,     "WaitForRun",     "Add description here");
419                AddStateName(kSM_Logging,        "Logging",        "Add description here");
420                AddStateName(kSM_BadDailyConfig, "ErrDailyFolder", "Add description here");
421                AddStateName(kSM_BadRunConfig,   "ErrRunFolder",   "Add description here");
422
423        /*Add the possible transitions for this machine*/
424
425                AddTransition(kSM_DailyOpen, fTransStart, kSM_Ready, kSM_BadDailyConfig)
426                    (boost::bind(&DataLogger::StartPlease, this))
427                    ("start the daily logging. daily file location must be specified already");
428
429                AddTransition(kSM_Ready, fTransStop, kSM_DailyOpen, kSM_WaitingRun, kSM_Logging)
430                    (boost::bind(&DataLogger::GoToReadyPlease, this))
431                    ("stop the data logging");
432
433                AddTransition(kSM_Logging, fTransStartRun, kSM_WaitingRun, kSM_BadRunConfig)
434                    (boost::bind(&DataLogger::StartRunPlease, this))
435                    ("start the run logging. run file location must be specified already.");
436
437                AddTransition(kSM_WaitingRun, fTransStopRun, kSM_Logging)
438                    (boost::bind(&DataLogger::StopRunPlease, this))
439                    ("");
440
441                AddTransition(kSM_Ready, fTransReset, kSM_Error, kSM_BadDailyConfig, kSM_BadRunConfig, kSM_Error)
442                    (boost::bind(&DataLogger::GoToReadyPlease, this))
443                    ("transition to exit error states. dunno if required or not, would close the daily file if already openned.");
444
445                AddTransition(kSM_WaitingRun, fTransWait, kSM_DailyOpen)
446                    (boost::bind(&DataLogger::DailyToWaitRunPlease, this));
447
448        /*Add the possible configurations for this machine*/
449       
450                AddConfiguration(fConfigDay, "C", kSM_Ready, kSM_BadDailyConfig)
451                    (boost::bind(&DataLogger::ConfigureDailyFileName, this, _1))
452                    ("configure the daily file location. cannot be done before the file is actually opened");
453
454                AddConfiguration(fConfigRun, "C", kSM_Ready, kSM_BadDailyConfig, kSM_DailyOpen, kSM_WaitingRun, kSM_BadRunConfig)
455                    (boost::bind(&DataLogger::ConfigureRunFileName, this, _1))
456                    ("configure the run file location. cannot be done before the file is actually opened, and not in a dailly related error.");
457
458                //Provide a logging command
459                //I get the feeling that I should be going through the EventImp
460                //instead of DimCommand directly, mainly because the commandHandler
461                //is already done in StateMachineImp.cc
462                //Thus I'll simply add a configuration, which I will treat as the logging command
463                AddConfiguration(fConfigLog, "C", kSM_DailyOpen, kSM_Logging, kSM_WaitingRun, kSM_BadRunConfig)
464                    (boost::bind(&DataLogger::LogMessagePlease, this, _1));
465
466                fServiceList.SetHandler(this);
467                CheckForServicesUpdate();
468               
469                //start the monitoring service
470                fContinueMonitoring = true;
471                fMonitoringThread = boost::thread(boost::bind(&DataLogger::ServicesMonitoring, this));
472                fBaseSizeDaily = 0;
473                fBaseSizeRun = 0;
474                //start the open files service
475                fDimBuffer = new char[256];
476                memset(fDimBuffer, 0, sizeof(int));
477                fDimBuffer[sizeof(int)] = '\0';
478                //gives the entire buffer size. Otherwise, dim overwrites memory at bizarre locations if smaller size is given at creation time.
479                fOpenedFiles =  new DimDescribedService((GetName()+"/FILENAME").c_str(), "i:1;C", static_cast<void*>(fDimBuffer), 256,
480                                                        "Add description here");
481               
482               
483}
484// --------------------------------------------------------------------------
485//
486//! Checks for changes in the existing services.
487//! Any new service will be added to the service list, while the ones which disappeared are removed.
488//! @todo
489//!     add the configuration (using the conf class ?)
490//
491//FIXME The service must be udpated so that I get the first notification. This should not be
492void DataLogger::CheckForServicesUpdate()
493{ 
494
495        //get the current server list
496        const std::vector<std::string> serverList = fServiceList.GetServerList();
497        //first let's remove the servers that may have disapeared
498        //can't treat the erase on maps the same way as for vectors. Do it the safe way instead
499        std::vector<std::string> toBeDeleted;
500        for (SubscriptionsListType::iterator cListe = fServiceSubscriptions.begin(); cListe != fServiceSubscriptions.end(); cListe++)
501        {
502                std::vector<std::string>::const_iterator givenServers;
503                for (givenServers=serverList.begin(); givenServers!= serverList.end(); givenServers++)
504                        if (cListe->first == *givenServers)
505                                break;
506                if (givenServers == serverList.end())//server vanished. Remove it
507                        toBeDeleted.push_back(cListe->first);
508        }
509        for (std::vector<std::string>::const_iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); it++)
510                fServiceSubscriptions.erase(*it);
511
512        //now crawl through the list of servers, and see if there was some updates
513        for (std::vector<std::string>::const_iterator i=serverList.begin(); i!=serverList.end();i++)
514        {
515                //skip the two obvious excluded services
516                if ((i->find("DIS_DNS") != std::string::npos) ||
517                    (i->find("DATA_LOGGER") != std::string::npos))
518                        continue;
519                //find the current server in our subscription list     
520                SubscriptionsListType::iterator cSubs = fServiceSubscriptions.find(*i);
521                //get the service list of the current server
522                std::vector<std::string> cServicesList = fServiceList.GetServiceList(*i);
523                if (cSubs != fServiceSubscriptions.end())//if the current server already is in our subscriptions
524                {                                                                                //then check and update our list of subscriptions
525                        //first, remove the services that may have dissapeared.
526                        std::map<std::string, SubscriptionType>::iterator serverSubs;
527                        std::vector<std::string>::const_iterator givenSubs;
528                        toBeDeleted.clear();
529                        for (serverSubs=cSubs->second.begin(); serverSubs != cSubs->second.end(); serverSubs++)
530                        {
531                                for (givenSubs = cServicesList.begin(); givenSubs != cServicesList.end(); givenSubs++)
532                                        if (serverSubs->first == *givenSubs)
533                                                break;
534                                if (givenSubs == cServicesList.end())
535                                {
536                                        toBeDeleted.push_back(serverSubs->first);
537                                }       
538                        }
539                        for (std::vector<std::string>::const_iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); it++)
540                                cSubs->second.erase(*it);
541                        //now check for new services
542                        for (givenSubs = cServicesList.begin(); givenSubs != cServicesList.end(); givenSubs++)
543                        {
544                                if (*givenSubs == "SERVICE_LIST")
545                                        continue;
546                                if (cSubs->second.find(*givenSubs) == cSubs->second.end())
547                                {//service not found. Add it
548                                        cSubs->second[*givenSubs].dimInfo = new DimStampedInfo(((*i) + "/" + *givenSubs).c_str(), const_cast<char*>(""), this);
549                                }       
550                        }
551                }
552                else //server not found in our list. Create its entry
553                {
554                        fServiceSubscriptions[*i] = std::map<std::string, SubscriptionType>();
555                        std::map<std::string, SubscriptionType>& liste = fServiceSubscriptions[*i];
556                        for (std::vector<std::string>::const_iterator j = cServicesList.begin(); j!= cServicesList.end(); j++)
557                        {
558                                if (*j == "SERVICE_LIST")
559                                        continue;
560                                liste[*j].dimInfo = new DimStampedInfo(((*i) + "/" + (*j)).c_str(), const_cast<char*>(""), this);
561                        }
562                }       
563        }
564}
565// --------------------------------------------------------------------------
566//
567//! Destructor
568//
569DataLogger::~DataLogger()
570{
571        //exit the monitoring loop
572        fContinueMonitoring = false;
573        delete[] fDimBuffer;
574        delete fOpenedFiles;
575        fMonitoringThread.join();
576        //close the files
577        if (fDailyLogFile.is_open())
578                fDailyLogFile.close();
579        if (fDailyReportFile.is_open())
580                fDailyReportFile.close();
581        if (fRunLogFile.is_open())
582                fRunLogFile.close();
583        if (fRunReportFile.is_open())
584                fRunReportFile.close();
585        //release the services subscriptions
586        fServiceSubscriptions.clear();
587#ifdef HAS_FITS
588        if (fRunFitsFile != NULL)
589                delete fRunFitsFile;
590        fRunFitsFile = NULL;
591#endif
592}
593/*
594// --------------------------------------------------------------------------
595//
596//! Execute
597//! Shouldn't be run as we use callbacks instead
598//
599int DataLogger::Execute()
600{
601        //due to the callback mecanism, this function should never be called
602        return kSM_FatalError;
603       
604        switch (GetCurrentState())
605        {
606        case kSM_Error:
607        case kSM_Ready:
608        case kSM_DailyOpen:
609        case kSM_WaitingRun:
610        case kSM_Logging:
611        case kSM_BadDailyConfig:
612        case kSM_BadRunConfig:
613                return GetCurrentState();
614        }
615        //this line below should never be hit. It here mainly to remove warnings at compilation
616        return kSM_FatalError;
617}
618// --------------------------------------------------------------------------
619//
620//! Shouldn't be run as we use callbacks instead
621//
622 int DataLogger::Transition(const Event& evt)
623{
624        //due to the callback mecanism, this function should never be called
625        return kSM_FatalError;
626       
627        switch (evt.GetTargetState())
628        {
629                case kSM_Ready:
630                //here we must figure out whether the STOP or RESET command was sent
631                //close opened files and go back to ready state
632                        switch (GetCurrentState())
633                        {
634                                case kSM_BadDailyConfig:
635                                case kSM_BadRunConfig:
636                                case kSM_Error:
637                                        return GoToReadyPlease();
638                                       
639                                case kSM_Logging:
640                                case kSM_WaitingRun:
641                                case kSM_DailyOpen:
642                                        return GoToReadyPlease();
643                        }
644                break;
645               
646                case kSM_DailyOpen:
647                        //Attempt to open the daily file
648                        switch (GetCurrentState())
649                        {
650                                case kSM_Ready:
651                                case kSM_BadDailyConfig:
652                                        return StartPlease();   
653                        }
654                break;
655               
656                case kSM_WaitingRun:
657                        //either close the run file, or just go to the waitingrun state (if coming from daily open
658                        switch (GetCurrentState())
659                        {
660                                case kSM_DailyOpen:
661                                        return kSM_WaitingRun;
662                               
663                                case kSM_Logging:
664                                        return StopRunPlease();
665                        }
666                break;
667               
668                case kSM_Logging:
669                        //Attempt to open run file
670                        switch (GetCurrentState())
671                        {
672                                case kSM_WaitingRun:
673                                case kSM_BadRunConfig:
674                                        return StartRunPlease();
675                        }       
676                break;
677        }
678        //Getting here means that an invalid transition has been asked.
679        //TODO Log an error message
680        //and return the fatal error state
681        return kSM_FatalError;
682}
683// --------------------------------------------------------------------------
684//
685//! Shouldn't be run as we use callbacks instead
686//
687 int DataLogger::Configure(const Event& evt)
688{
689        //due to the callback mecanism, this function should never be called
690        return kSM_FatalError;
691
692        switch (evt.GetTargetState())
693        {
694                case kSM_Ready:
695                case kSM_BadDailyConfig:
696                        return ConfigureDailyFileName(evt);
697                break;
698               
699                case kSM_WaitingRun:
700                case kSM_BadRunConfig:
701                        return ConfigureRunFileName(evt);       
702                break;
703               
704                case kSM_Logging:
705                case kSM_DailyOpen:
706                                return 0;
707                break;
708
709        }       
710
711        return kSM_FatalError;
712}
713*/
714// --------------------------------------------------------------------------
715//
716//! Inherited from DimInfo. Handles all the Infos to which we subscribed, and log them
717//
718void DataLogger::infoHandler()
719{
720        DimInfo* I = getInfo();
721        if (I==NULL)
722        {
723                CheckForServicesUpdate();
724                return;
725        }
726        //check if the service pointer corresponds to something that we subscribed to
727        //this is a fix for a bug that provides bad Infos when a server starts
728        bool found = false;
729        SubscriptionsListType::iterator x;
730        std::map<std::string, SubscriptionType>::iterator y;
731        for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
732        {//find current service is subscriptions
733                for (y=x->second.begin(); y!=x->second.end();y++)
734                        if (y->second.dimInfo == I)
735                        {
736                                found = true;   
737                                break;
738                        }
739                if (found)
740                        break;
741        }
742        if (!found)
743                return;
744        if (I->getSize() <= 0)
745                return;
746        //check that the message has been updated by something, i.e. must be different from its initial value
747        if (I->getTimestamp() == 0)
748                return;
749
750        CheckForRunNumber(I);
751        ReportPlease(I, y->second);
752
753}
754
755// --------------------------------------------------------------------------
756//
757//! Checks whether or not the current info is a run number.
758//! If so, then remember it. A run number is required to open the run-log file
759//! @param I
760//!             the current DimInfo
761//
762void DataLogger::CheckForRunNumber(DimInfo* I)
763{
764        if (strstr(I->getName(), fRunNumberInfo) != NULL)
765        {//assumes that the run number is an integer
766                //TODO check the format here
767                fRunNumber = I->getInt();       
768        }
769}
770
771// --------------------------------------------------------------------------
772//
773//! write infos to log files.
774//! @param I
775//!     The current DimInfo
776//
777void DataLogger::ReportPlease(DimInfo* I, SubscriptionType& sub)
778{
779        //should we log or report this info ? (i.e. is it a message ?)
780        bool isItaReport = ((strstr(I->getName(), "Message") == NULL) && (strstr(I->getName(), "MESSAGE") == NULL));
781       
782        //TODO add service exclusion
783       
784        if (!fDailyReportFile.is_open())
785                return;
786
787        //create the converter for that service
788        if (sub.fConv == NULL)
789        {
790                sub.fConv = new Converter(Out(), I->getFormat());       
791                if (!sub.fConv)
792                {
793                        Error("Couldn't properly parse the format... service ignored.");
794                        return; 
795                }
796        }
797               
798        //construct the header
799        std::stringstream header;
800        Time cTime(I->getTimestamp(), I->getTimestampMillisecs()*1000);
801        fQuality = I->getQuality();
802        fMjD = cTime.Mjd();
803
804        if (isItaReport)
805        {
806                //write text header
807                header << I->getName() << " " << fQuality << " ";
808                header << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
809                header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
810                header << cTime.ms() << " " << I->getTimestamp() << " ";
811
812                std::string text;
813        try
814        {
815                text = sub.fConv->GetString(I->getData(), I->getSize());
816        }
817        catch (const std::runtime_error &e)
818        {
819                Out() << kRed << e.what() << endl;
820            Error("Couldn't properly parse the data... ignored.");
821            return;
822        }
823
824                if (text.empty())
825                return;
826
827        //replace bizarre characters by white space
828        replace(text.begin(), text.end(), '\n', '\\');
829        replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');
830       
831                if (fDailyReportFile.is_open())
832                        fDailyReportFile << header.str();
833                if (fRunReportFile.is_open())
834                        fRunReportFile << header.str();
835
836        if (fDailyReportFile.is_open())
837                        fDailyReportFile << text << std::endl;
838                if (fRunReportFile.is_open())
839                        fRunReportFile << text << std::endl;
840        }
841        else
842        {
843                std::string n = I->getName();
844                std::stringstream msg;
845                msg << n.substr(0, n.find_first_of('/')) << ": " << I->getString();
846                MessageImp dailyMess(fDailyLogFile);
847                dailyMess.Write(cTime, msg.str().c_str(), fQuality);
848                if (fRunLogFile.is_open())
849                {
850                        MessageImp runMess(fRunLogFile);
851                        runMess.Write(cTime, msg.str().c_str(), fQuality);
852                }
853        }
854
855#ifdef HAS_FITS
856        if (!sub.dailyFile.IsOpen() || !sub.runFile.IsOpen())
857                OpenFITSFilesPlease(sub);       
858        WriteToFITS(sub);
859               
860#endif
861
862}
863
864// --------------------------------------------------------------------------
865//
866//! write messages to logs.
867//! @param evt
868//!             the current event to log
869//! @returns
870//!             the new state. Currently, always the current state
871//!
872//! @deprecated
873//!    I guess that this function should not be any longer
874//
875//TODO isn't that function not used any longer ? If so I guess that we should get rid of it...
876int DataLogger::LogMessagePlease(const Event& evt)
877{
878        if (!fDailyLogFile.is_open())
879                return GetCurrentState();
880       
881        std::stringstream header;
882        const Time& cTime = evt.GetTime();
883        header << evt.GetName() << " " << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
884        header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
885        header << cTime.ms() << " ";
886               
887    const Converter conv(Out(), evt.GetFormat());
888    if (!conv)
889    {
890        Error("Couldn't properly parse the format... ignored.");
891        return GetCurrentState();
892    }
893
894    std::string text;
895    try
896    {
897        text = conv.GetString(evt.GetData(), evt.GetSize());
898    }
899    catch (const std::runtime_error &e)
900    {
901        Out() << kRed << e.what() << endl;
902        Error("Couldn't properly parse the data... ignored.");
903        return GetCurrentState();
904    }
905
906        if (text.empty())
907        return GetCurrentState();
908
909    //replace bizarre characters by white space
910    replace(text.begin(), text.end(), '\n', '\\');
911    replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');
912
913        if (fDailyLogFile.is_open())
914                fDailyLogFile << header;
915        if (fRunLogFile.is_open())
916                fRunLogFile << header;
917
918        if (fDailyLogFile.is_open())
919                fDailyLogFile << text;
920        if (fRunLogFile.is_open())
921                fRunLogFile << text;
922
923        return GetCurrentState();
924}
925// --------------------------------------------------------------------------
926//
927//!     Sets the path to use for the daily log file.
928//! @param evt
929//!     the event transporting the path
930//! @returns
931//!             currently only the current state.
932//
933int DataLogger::ConfigureDailyFileName(const Event& evt)
934{
935        if (evt.GetText() != NULL)
936                fDailyFileName = std::string(evt.GetText());   
937        else
938                Error("Empty daily folder");
939
940        return GetCurrentState();
941}
942// --------------------------------------------------------------------------
943//
944//! Sets the path to use for the run log file.
945//! @param evt
946//!             the event transporting the path
947//! @returns
948//!     currently only the current state
949int DataLogger::ConfigureRunFileName(const Event& evt)
950{
951        if (evt.GetText() != NULL)
952                fRunFileName = std::string(evt.GetText());
953        else
954                Error("Empty daily folder");
955
956        return GetCurrentState();
957}
958// --------------------------------------------------------------------------
959//
960//! Sets the run number.
961//! @param evt
962//!             the event transporting the run number
963//! @returns
964//!     currently only the current state
965int DataLogger::ConfigureRunNumber(const Event& evt)
966{
967        fRunNumber = evt.GetInt();
968
969        return GetCurrentState();
970}
971// --------------------------------------------------------------------------
972//
973//! Notifies the DIM service that a particular file was opened
974//! @ param name the base name of the opened file, i.e. without path nor extension.
975//!     WARNING: use string instead of string& because I pass values that do not convert to string&.
976//!             this is not a problem though because file are not opened so often.
977//! @ param type the type of the opened file. 0 = none open, 1 = log, 2 = text, 4 = fits
978inline void DataLogger::NotifyOpenedFile(std::string name, int type)
979{
980//std::cout << "name: " << name << " size: " << name.size() << std::endl;
981        reinterpret_cast<int*>(fDimBuffer)[0] = type;
982        strcpy(&fDimBuffer[sizeof(int)], name.c_str());
983        fOpenedFiles->updateService(static_cast<void*>(fDimBuffer), name.size() + 1 + sizeof(int));
984}
985// --------------------------------------------------------------------------
986//
987//! Implements the Start transition.
988//! Concatenates the given path for the daily file and the filename itself (based on the day),
989//! and tries to open it.
990//! @returns
991//!             kSM_DailyOpen if success, kSM_BadDailyConfig if failure
992int DataLogger::StartPlease()
993{
994        //TODO concatenate the dailyFileName and the formatted date and extension to obtain the full file name
995        Time time;//(Time::utc);
996        std::stringstream sTime;
997        sTime << time.Y() << "_" << time.M() << "_" << time.D();
998        fFullDailyLogFileName = fDailyFileName + '/' + sTime.str() + ".log"; 
999       
1000        fDailyLogFile.open(fFullDailyLogFileName.c_str(), std::ios_base::out | std::ios_base::app); //maybe should be "app" instead of "ate" ??
1001        fFullDailyReportFileName = fDailyFileName + '/' + sTime.str() + ".rep";
1002        fDailyReportFile.open(fFullDailyReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1003       
1004        if (!fDailyLogFile.is_open() || !fDailyReportFile.is_open())
1005        {       
1006                //TODO send an error message   
1007            return kSM_BadDailyConfig;
1008        }
1009        //get the size of the newly opened file.
1010        struct stat st;
1011        stat(fFullDailyLogFileName.c_str(), &st);
1012        fBaseSizeDaily = st.st_size;   
1013        stat(fFullDailyReportFileName.c_str(), &st);
1014        fBaseSizeDaily += st.st_size;
1015        fFileSizesMap.clear();
1016        fBaseSizeRun = 0;
1017        fPreviousSize = 0;
1018        //notify that files were opened
1019        NotifyOpenedFile(sTime.str(), 3);
1020       
1021       
1022        return kSM_DailyOpen;   
1023}
1024
1025#ifdef HAS_FITS
1026// --------------------------------------------------------------------------
1027//
1028//! open if required a the FITS files corresponding to a given subscription
1029//! @param sub
1030//!     the current DimInfo subscription being examined
1031void DataLogger::OpenFITSFilesPlease(SubscriptionType& sub)
1032{
1033        std::string serviceName(sub.dimInfo->getName());
1034        for (unsigned int i=0;i<serviceName.size(); i++)
1035        {
1036                if (serviceName[i] == '/')
1037                {
1038                        serviceName[i] = '_';
1039                        break; 
1040                }       
1041        }
1042        Time time;
1043        std::stringstream sTime;
1044        sTime << time.Y() << "_" << time.M() << "_" << time.D();
1045        //we open the dailyFile anyway, otherwise this function shouldn't have been called.
1046        if (!sub.dailyFile.IsOpen())
1047        {
1048                std::string partialName = fDailyFileName + '/' + sTime.str() + '_' + serviceName + ".fits";
1049                AllocateFITSBuffers(sub);
1050                //get the size of the file we're about to open
1051                if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1052                {
1053                        struct stat st;
1054                        if (!stat(partialName.c_str(), &st))
1055                                fBaseSizeDaily += st.st_size;
1056                        fFileSizesMap[partialName] = 0;
1057                }
1058                sub.dailyFile.Open(partialName, serviceName, NULL);
1059                //notify the opening
1060                NotifyOpenedFile(sTime.str() + '_' + serviceName, 4);
1061               
1062        }
1063        if (!sub.runFile.IsOpen() && (GetCurrentState() == kSM_Logging))
1064        {//buffer for the run file have already been allocated when doing the daily file
1065                std::stringstream sRun;
1066                sRun << fRunNumber;
1067                std::string partialName = fRunFileName + '/' + sRun.str() + ".fits";//'_' + serviceName + ".fits";
1068                if (fRunFitsFile == NULL)
1069                {
1070                        //get the size of the file we're about to open
1071                        if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1072                        {
1073                                struct stat st;
1074                                if (!stat(partialName.c_str(), &st))
1075                                        fBaseSizeRun += st.st_size;
1076                                else
1077                                        fBaseSizeRun = 0;
1078                                fFileSizesMap[partialName] = 0; 
1079                        }
1080                        try
1081                        {
1082                                fRunFitsFile = new FITS(partialName, RWmode::Write);   
1083                        }       
1084                        catch (CCfits::FitsError e)
1085                        {
1086                                std::ostringstream err;
1087                                err << "Could not open run file " << partialName;
1088                                throw runtime_error(err.str()); 
1089                        }
1090                        NotifyOpenedFile(sRun.str(), 4);// + '_' + serviceName, 4);
1091                }
1092                sub.runFile.Open(partialName, serviceName, fRunFitsFile);
1093        }
1094}       
1095// --------------------------------------------------------------------------
1096//
1097void DataLogger::AllocateFITSBuffers(SubscriptionType& sub)
1098{
1099        int size = sub.dimInfo->getSize();
1100         
1101        //Init the time columns of the file
1102        Description dateDesc(std::string("Time"), std::string("Modified Julian Date"), std::string("MjD"));
1103        sub.dailyFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1104        sub.runFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1105
1106        Description QoSDesc("Qos", "Quality of service", "None");
1107        sub.dailyFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1108        sub.runFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1109
1110        const Converter::FormatList flist = sub.fConv->GetList();
1111    // Compilation failed
1112    if (flist.empty() || flist.back().first.second!=0)
1113    {
1114        Error("Compilation of format string failed.");
1115        return;
1116    }
1117
1118        //we've got a nice structure describing the format of this service's messages.
1119        //Let's create the appropriate FITS columns
1120        std::vector<std::string> dataFormatsLocal;
1121        for (unsigned int i=0;i<flist.size()-1;i++)
1122        {
1123                std::stringstream dataQualifier; 
1124
1125                dataQualifier << flist[i].second.first;
1126                switch (flist[i].first.first->name()[0])
1127                {//TODO handle all the data format cases
1128                        case 'c':
1129                                dataQualifier <<  "S";
1130                        break;
1131                        case 's':
1132                                dataQualifier << "I";
1133                        break;
1134                        case 'i':
1135                                dataQualifier << "J";
1136                        break;
1137                        case 'l':
1138                                dataQualifier << "J";
1139                                //TODO triple check that in FITS, long = int
1140                        break;
1141                        case 'f':
1142                                dataQualifier << "E";
1143                        break;
1144                        case 'd':
1145                                dataQualifier << "D";
1146                        break;
1147                        case 'x':
1148                        case 'X':
1149                                dataQualifier << "K";
1150                        break;
1151                        case 'S':
1152                                //for strings, the number of elements I get is wrong. Correct it
1153                                dataQualifier.str(""); //clear
1154                                dataQualifier << size-1 <<  "A";
1155                                size = size-1;
1156                        break;
1157                       
1158                        default:
1159                                Error("THIS SHOULD NEVER BE REACHED. dataLogger.cc ln 948.");
1160                };
1161                dataFormatsLocal.push_back(dataQualifier.str());
1162         }
1163
1164         sub.dailyFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1165         sub.runFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1166}
1167// --------------------------------------------------------------------------
1168//
1169//! write a dimInfo data to its corresponding FITS files
1170//
1171void DataLogger::WriteToFITS(SubscriptionType& sub)
1172{
1173                //dailyFile status (open or not) already checked
1174                if (sub.dailyFile.IsOpen())
1175                        sub.dailyFile.Write(sub.fConv);
1176                if (sub.runFile.IsOpen())
1177                        sub.runFile.Write(sub.fConv);
1178}
1179#endif //if has_fits
1180// --------------------------------------------------------------------------
1181//
1182//! Implements the StartRun transition.
1183//! Concatenates the given path for the run file and the filename itself (based on the run number),
1184//! and tries to open it.
1185//! @returns
1186//!             kSM_Logging if success, kSM_BadRunConfig if failure.
1187int DataLogger::StartRunPlease()
1188{
1189        //attempt to open run file with current parameters
1190        if (fRunNumber == -1)
1191                return kSM_BadRunConfig;
1192        std::stringstream sRun;
1193        sRun << fRunNumber;
1194        fFullRunLogFileName = fRunFileName + '/' + sRun.str() + ".log";
1195        fRunLogFile.open(fFullRunLogFileName.c_str(), std::ios_base::out | std::ios_base::app); //maybe should be app instead of ate
1196
1197        fFullRunReportFileName = fRunFileName + '/' + sRun.str() + ".rep";
1198        fRunReportFile.open(fFullRunReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1199       
1200        if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1201        {
1202                //TODO send an error message
1203                return kSM_BadRunConfig;       
1204        }
1205        //get the size of the newly opened file.
1206        struct stat st;
1207        fBaseSizeRun = 0;
1208        if (fFileSizesMap.find(fFullRunLogFileName) == fFileSizesMap.end())
1209        {
1210                stat(fFullRunLogFileName.c_str(), &st);
1211                fBaseSizeRun += st.st_size;
1212                fFileSizesMap[fFullRunLogFileName] = 0;
1213        }
1214        if (fFileSizesMap.find(fFullRunReportFileName) == fFileSizesMap.end())
1215        {
1216                stat(fFullRunReportFileName.c_str(), &st);
1217                fBaseSizeRun += st.st_size;
1218                fFileSizesMap[fFullRunReportFileName] = 0;
1219        }
1220        NotifyOpenedFile(sRun.str(), 3);
1221       
1222        return kSM_Logging;
1223}
1224// --------------------------------------------------------------------------
1225//
1226//! Implements the StopRun transition.
1227//! Attempts to close the run file.
1228//! @returns
1229//!             kSM_WaitingRun if success, kSM_FatalError otherwise
1230int DataLogger::StopRunPlease()
1231{
1232        if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1233                return kSM_FatalError;
1234       
1235        fRunLogFile.close();
1236        fRunReportFile.close();
1237#ifdef HAS_FITS
1238        for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
1239                for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
1240                {
1241                                if (j->second.runFile.IsOpen())
1242                                        j->second.runFile.Close();     
1243                }
1244        if (fRunFitsFile != NULL)
1245        {
1246                delete fRunFitsFile;
1247                fRunFitsFile = NULL;   
1248        }
1249#endif
1250        return kSM_WaitingRun;
1251
1252}
1253// --------------------------------------------------------------------------
1254//
1255//! Implements the Stop and Reset transitions.
1256//! Attempts to close any openned file.
1257//! @returns
1258//!     kSM_Ready
1259int DataLogger::GoToReadyPlease()
1260{
1261        if (fDailyLogFile.is_open())
1262                fDailyLogFile.close();
1263        if (fDailyReportFile.is_open())
1264                fDailyReportFile.close();
1265
1266        if (fRunLogFile.is_open())
1267                fRunLogFile.close();
1268        if (fRunReportFile.is_open())
1269                fRunReportFile.close();
1270               
1271#ifdef HAS_FITS
1272        for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
1273                for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
1274                {
1275                                if (j->second.dailyFile.IsOpen())
1276                                        j->second.dailyFile.Close();
1277                                if (j->second.runFile.IsOpen())
1278                                        j->second.runFile.Close();     
1279                }
1280        if (fRunFitsFile != NULL)
1281        {
1282                delete fRunFitsFile;
1283                fRunFitsFile = NULL;   
1284        }
1285#endif
1286        return kSM_Ready;
1287}
1288// --------------------------------------------------------------------------
1289//
1290//! Implements the transition towards kSM_WaitingRun
1291//! Does nothing really.
1292//!     @returns
1293//!             kSM_WaitingRun
1294int DataLogger::DailyToWaitRunPlease()
1295{
1296        return kSM_WaitingRun; 
1297}
1298
1299// --------------------------------------------------------------------------
1300
1301int RunDim(Configuration &conf)
1302{
1303    WindowLog wout;
1304
1305    //log.SetWindow(stdscr);
1306    if (conf.Has("log"))
1307        if (!wout.OpenLogFile(conf.Get<std::string>("log")))
1308            wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
1309
1310    // Start io_service.Run to use the StateMachineImp::Run() loop
1311    // Start io_service.run to only use the commandHandler command detaching
1312    DataLogger logger(wout);
1313    logger.Run(true);
1314
1315    return 0;
1316}
1317
1318template<class T>
1319int RunShell(Configuration &conf)
1320{
1321    static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1322
1323    WindowLog &win  = shell.GetStreamIn();
1324    WindowLog &wout = shell.GetStreamOut();
1325
1326    if (conf.Has("log"))
1327        if (!wout.OpenLogFile(conf.Get<std::string>("log")))
1328            win << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
1329
1330    DataLogger logger(wout);
1331
1332    shell.SetReceiver(logger);
1333
1334    logger.SetReady();
1335 //  logger.StartPlease();
1336    shell.Run();                 // Run the shell
1337     logger.SetNotReady();
1338
1339    return 0;
1340}
1341
1342/*
1343 Extract usage clause(s) [if any] for SYNOPSIS.
1344 Translators: "Usage" and "or" here are patterns (regular expressions) which
1345 are used to match the usage synopsis in program output.  An example from cp
1346 (GNU coreutils) which contains both strings:
1347  Usage: cp [OPTION]... [-T] SOURCE DEST
1348    or:  cp [OPTION]... SOURCE... DIRECTORY
1349    or:  cp [OPTION]... -t DIRECTORY SOURCE...
1350 */
1351void PrintUsage()
1352{
1353    cout << "\n"
1354        "The data logger connects to all available Dim services and "
1355        "writes them to ascii and fits files.\n"
1356        "\n"
1357        "Usage: dataLogger [-c type] [OPTIONS]\n"
1358        "  or:  dataLogger [OPTIONS]\n"
1359        "\n"
1360        "Options:\n"
1361        "The following describes the available commandline options. "
1362        "For further details on how command line option are parsed "
1363        "and in which order which configuration sources are accessed "
1364        "please refer to the class reference of the Configuration class.";
1365    cout << endl;
1366
1367}
1368
1369void PrintHelp()
1370{
1371    cout << "\n"
1372        "The default is that the program is started without user interaction. "
1373        "All actions are supposed to arrive as DimCommands. Using the -c "
1374        "option, a local shell can be initialized. With h or help a short "
1375        "help message about the usuage can be brought to the screen."
1376        << endl;
1377
1378    /*
1379     cout << "bla bla bla" << endl << endl;
1380     cout << endl;
1381     cout << "Environment:" << endl;
1382     cout << "environment" << endl;
1383     cout << endl;
1384     cout << "Examples:" << endl;
1385     cout << "test exam" << endl;
1386     cout << endl;
1387     cout << "Files:" << endl;
1388     cout << "files" << endl;
1389     cout << endl;
1390     */
1391}
1392
1393/*
1394 The first line of the --version information is assumed to be in one
1395 of the following formats:
1396
1397   <version>
1398   <program> <version>
1399   {GNU,Free} <program> <version>
1400   <program> ({GNU,Free} <package>) <version>
1401   <program> - {GNU,Free} <package> <version>
1402
1403 and separated from any copyright/author details by a blank line.
1404
1405 Handle multi-line bug reporting sections of the form:
1406
1407   Report <program> bugs to <addr>
1408   GNU <package> home page: <url>
1409   ...
1410*/
1411void PrintVersion(const char *name)
1412{
1413    cout <<
1414        name << " - "PACKAGE_STRING"\n"
1415        "\n"
1416        "Written by Thomas Bretz et al.\n"
1417        "\n"
1418        "Report bugs to <"PACKAGE_BUGREPORT">\n"
1419        "Home page: "PACKAGE_URL"\n"
1420        "\n"
1421        "Copyright (C) 2011 by the FACT Collaboration.\n"
1422        "This is free software; see the source for copying conditions.\n"
1423        << endl;
1424}
1425
1426
1427void SetupConfiguration(Configuration &conf)
1428{
1429    const string n = conf.GetName()+".log";
1430
1431    po::options_description config("Program options");
1432    config.add_options()
1433        ("dns",       var<string>("localhost"),  "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1434        ("log,l",     var<string>(n), "Write log-file")
1435        ("console,c", var<int>(),     "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1436        ;
1437
1438    conf.AddEnv("dns", "DIM_DNS_NODE");
1439
1440    conf.AddOptions(config);
1441}
1442
1443int main(int argc, const char* argv[])
1444{
1445    Configuration conf(argv[0]);
1446    conf.SetPrintUsage(PrintUsage);
1447    SetupConfiguration(conf);
1448
1449    po::variables_map vm;
1450    try
1451    {
1452        vm = conf.Parse(argc, argv);
1453    }
1454    catch (std::exception &e)
1455    {
1456#if BOOST_VERSION > 104000
1457        po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
1458        if (MO)
1459            cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
1460        else
1461#endif
1462            cout << "Error: " << e.what() << endl;
1463        cout << endl;
1464
1465        return -1;
1466    }
1467
1468    if (conf.HasPrint())
1469        return -1;
1470
1471    if (conf.HasVersion())
1472    {
1473        PrintVersion(argv[0]);
1474        return -1;
1475    }
1476
1477    if (conf.HasHelp())
1478    {
1479        PrintHelp();
1480        return -1;
1481    }
1482
1483    setenv("DIM_DNS_NODE", conf.Get<string>("dns").c_str(), 1);
1484
1485    try
1486    {
1487        // No console access at all
1488        if (!conf.Has("console"))
1489            return RunDim(conf);
1490
1491        // Console access w/ and w/o Dim
1492        if (conf.Get<int>("console")==0)
1493            return RunShell<LocalShell>(conf);
1494        else
1495            return RunShell<LocalConsole>(conf);
1496    }
1497    catch (std::exception& e)
1498    {
1499        cerr << "Exception: " << e.what() << endl;
1500        return -1;
1501    }
1502
1503    return 0;
1504}
Note: See TracBrowser for help on using the repository browser.