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

Last change on this file since 10463 was 10453, checked in by tbretz, 14 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.