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

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