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

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