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

Last change on this file since 10570 was 10570, checked in by tbretz, 10 years ago
Improved/fixed the retrieval of times from Dim once again.
File size: 66.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="NightlyOpen"]
17 w [label="WaitingRun"]
18 l [label="Logging"]
19 b [label="BadNightlyconfig" color="red"]
20 c [label="BadRunConfig" color="red"]
21
22 e -> r
23 r -> e
24 r -> d
25 r -> b
26 d -> w
27 d -> r
28 w -> r
29 l -> r
30 l -> w
31 b -> d
32 w -> c
33 w -> l
34 b -> r
35 c -> r
36 c -> l
37 }
38 \enddot
39
40 @todo
41 - Retrieve also the messages, not only the infos
42 */
43 //****************************************************************
44#include "Event.h"
45#include "Time.h"
46#include "StateMachineDim.h"
47#include "WindowLog.h"
48#include "Configuration.h"
49#include "ServiceList.h"
50#include "Converter.h"
51#include "MessageImp.h"
52#include "LocalControl.h"
53#include "DimDescriptionService.h"
54
55#include "Description.h"
56
57#include "DimServiceInfoList.h"
58
59//for getting stat of opened files
60#include <unistd.h>
61//for getting disk free space
62#include <sys/statvfs.h>
63//for getting files sizes
64#include <sys/stat.h>
65
66#define HAS_FITS
67//#define ONE_RUN_FITS_ONLY
68
69#include <fstream>
70
71#include <boost/bind.hpp>
72#include <boost/thread.hpp>
73
74#ifdef HAS_FITS
75#include "Fits.h"
76#endif
77
78//Dim structures
79struct DataLoggerStats {
80 long sizeWritten;
81 long freeSpace;
82 long writingRate;
83};
84
85struct NumSubAndFitsType {
86 int numSubscriptions;
87 int numOpenFits;
88};
89
90struct OpenFileToDim {
91 int code;
92 char fileName[FILENAME_MAX];
93};
94//For debugging DIM's services
95class MyService
96{
97public:
98 MyService(){};
99 MyService(std::string, std::string, void*, int){};
100 MyService(std::string, const char*){};
101 void updateService(){};
102 void updateService(void*, int){};
103 void setQuality(int){};
104};
105class DataLogger : public StateMachineDim, DimInfoHandler//, DimServiceInfoList //,DimInfoHandler
106{
107public:
108 /// The list of existing states specific to the DataLogger
109 enum
110 {
111 kSM_NightlyOpen = 20, ///< Nightly file openned and writing
112 kSM_WaitingRun = 30, ///< waiting for the run number to open the run file
113 kSM_Logging = 40, ///< both files openned and writing
114 kSM_BadNightlyConfig = 0x101, ///< the folder specified for Nightly logging does not exist or has bad permissions
115 kSM_BadRunConfig = 0x102, ///< the folder specified for the run logging does not exist or has wrong permissions or no run number
116 } localstates_t;
117
118 DataLogger(std::ostream &out);
119 ~DataLogger();
120
121private:
122 //Define all the data structure specific to the DataLogger here
123 /// ofstream for the NightlyLogfile
124 std::ofstream fNightlyLogFile;
125 /// ofstream for the run-specific Log file
126 std::ofstream fRunLogFile;
127
128 /// ofstream for the Nightly report file
129 std::ofstream fNightlyReportFile;
130 /// ofstream for the run-specific report file
131 std::ofstream fRunReportFile;
132 /// base path of the Nightlyfile
133 std::string fNightlyFileName;
134 ///base path of the run file
135 std::string fRunFileName;
136 ///run number (-1 means no run number specified)
137 int fRunNumber;
138 ///Current Service Quality
139 int fQuality;
140 ///Modified Julian Date
141 double fMjD;
142
143 ///Define all the static names
144 static const char* fConfigDay;
145 static const char* fConfigRun;
146 static const char* fConfigRunNumber;
147 static const char* fConfigLog;
148 static const char* fTransStart;
149 static const char* fTransStop;
150 static const char* fTransStartRun;
151 static const char* fTransStopRun;
152 static const char* fTransReset;
153 static const char* fTransWait;
154 static const char* fRunNumberInfo; ///< This is the name of the dimInfo received to specify the run number. It must be updated once the final name will be defined
155 static const char* fPrintCommand;
156 static const char* fDebugOnOff;
157 static const char* fStatsPeriod;
158 static const char* fStartStopOpenedFiles;
159 static const char* fStartStopNumSubsAndFits;
160 //overloading of DIM's infoHandler function
161 void infoHandler();
162
163 ///for obtaining the name of the existing services
164 ServiceList fServiceList;
165
166 ///A std pair to store both the DimInfo pointer and the corresponding outputted fits file
167 struct SubscriptionType
168 {
169#ifdef HAS_FITS
170 ///Nightly FITS output file
171 Fits nightlyFile;
172 ///run-specific FITS output file
173 Fits runFile;
174#endif
175 ///the actual dimInfo pointer
176 DimStampedInfo* dimInfo;
177 ///the converter for outputting the data according to the format
178 Converter* fConv;
179 ///the number of existing handlers to this structure.
180 ///This is required otherwise I MUST handle the deleting of dimInfo outside from the destructor
181 int* numCopies;
182 void operator = (const SubscriptionType& other)
183 {
184#ifdef HAS_FITS
185 nightlyFile = other.nightlyFile;
186 runFile = other.runFile;
187#endif
188 dimInfo = other.dimInfo;
189 numCopies = other.numCopies;
190 fConv = other.fConv;
191 (*numCopies)++;
192 }
193 SubscriptionType(const SubscriptionType& other)
194 {
195#ifdef HAS_FITS
196 nightlyFile = other.nightlyFile;
197 runFile = other.runFile;
198#endif
199 dimInfo = other.dimInfo;
200 numCopies = other.numCopies;
201 fConv = other.fConv;
202 (*numCopies)++;
203 }
204 SubscriptionType(DimStampedInfo* info)
205 {
206 dimInfo = info;
207 fConv = NULL;
208 numCopies = new int(1);
209 }
210 SubscriptionType()
211 {
212 dimInfo = NULL;
213 fConv = NULL;
214 numCopies = new int(1);
215 }
216 ~SubscriptionType()
217 {
218 if (numCopies)
219 (*numCopies)--;
220 if (numCopies)
221 if (*numCopies < 1)
222 {
223 if (dimInfo)
224 delete dimInfo;
225#ifdef HAS_FITS
226 if (nightlyFile.IsOpen())
227 nightlyFile.Close();
228 if (runFile.IsOpen())
229 runFile.Close();
230#endif
231 if (numCopies)
232 delete numCopies;
233 delete fConv;
234 fConv = NULL;
235 dimInfo = NULL;
236 numCopies = NULL;
237 }
238 }
239 };
240 typedef std::map<const std::string, std::map<std::string, SubscriptionType>> SubscriptionsListType;
241 ///All the services to which we have subscribed to, sorted by server name.
242 SubscriptionsListType fServiceSubscriptions;
243
244 ///Reporting method for the services info received
245 void ReportPlease(DimInfo* I, SubscriptionType& sub);
246
247 ///Configuration of the nightly file path
248 int ConfigureNightlyFileName(const Event& evt);
249 ///Configuration fo the file name
250 int ConfigureRunFileName(const Event& evt);
251 ///DEPREC - configuration of the run number
252 int ConfigureRunNumber(const Event& evt);
253 ///logging method for the messages
254 int LogMessagePlease(const Event& evt);
255 ///print the current state of the dataLogger
256 int PrintStatePlease(const Event& evt);
257 ///checks whether or not the current info being treated is a run number
258 void CheckForRunNumber(DimInfo* I);
259 /// start transition
260 int StartPlease();
261 ///from waiting to logging transition
262 int StartRunPlease();
263 /// from logging to waiting transition
264 int StopRunPlease();
265 ///stop and reset transition
266 int GoToReadyPlease();
267 ///from NightlyOpen to waiting transition
268 int NightlyToWaitRunPlease();
269#ifdef HAS_FITS
270 ///Open fits files
271 void OpenFITSFilesPlease(SubscriptionType& sub);
272 ///Write data to FITS files
273 void WriteToFITS(SubscriptionType& sub);
274 ///Allocate the buffers required for fits
275 void AllocateFITSBuffers(SubscriptionType& sub);
276
277#ifdef ONE_RUN_FITS_ONLY
278 ///FITS file for runs. only one, hence dealt with in the dataLogger itself
279 FITS* fRunFitsFile;
280#endif //one_run_fits_only
281#endif//has_fits
282public:
283 ///checks with fServiceList whether or not the services got updated
284 bool CheckForServicesUpdate();
285
286private:
287 ///monitoring notification loop
288 void ServicesMonitoring();
289 ///services notification thread
290 boost::thread fMonitoringThread;
291 ///end of the monitoring
292 bool fContinueMonitoring;
293 ///required for accurate monitoring
294 std::map<std::string, long> fFileSizesMap;
295 std::string fFullNightlyLogFileName;
296 std::string fFullNightlyReportFileName;
297 std::string fFullRunLogFileName;
298 std::string fFullRunReportFileName;
299 long fBaseSizeNightly;
300 long fPreviousSize;
301 long fBaseSizeRun;
302 ///Service for opened files
303 DimDescribedService* fOpenedNightlyFiles;
304 DimDescribedService* fOpenedRunFiles;
305 DimDescribedService* fNumSubAndFits;
306 NumSubAndFitsType fNumSubAndFitsData;
307
308 inline void NotifyOpenedFile(std::string name, int type, DimDescribedService* service);
309public:
310 void setBlackWhiteList(const std::string& , bool);
311private:
312 std::set<std::string> fGreyList;
313 bool fIsBlackList;
314 bool fDebugIsOn;
315 float fStatsPeriodDuration;
316 bool fOpenedFilesIsOn;
317 bool fNumSubAndFitsIsOn;
318 //functions for controlling the services behavior
319 int SetDebugOnOff(const Event& evt);
320 int SetStatsPeriod(const Event& evt);
321 int SetOpenedFilesOnOff(const Event& evt);
322 int SetNumSubsAndFitsOnOff(const Event& evt);
323 ///boolean to prevent DIM update while desctructing the dataLogger
324 bool fDestructing;
325}; //DataLogger
326
327//static members initialization
328//since I do not check the transition/config names any longer, indeed maybe these could be hard-coded... but who knows what will happen in the future ?
329const char* DataLogger::fConfigDay = "CONFIG_DAY";
330const char* DataLogger::fConfigRun = "CONFIG_RUN";
331const char* DataLogger::fConfigRunNumber = "CONFIG_RUN_NUMBER";
332const char* DataLogger::fConfigLog = "LOG";
333const char* DataLogger::fTransStart = "START";
334const char* DataLogger::fTransStop = "STOP";
335const char* DataLogger::fTransStartRun = "START_RUN";
336const char* DataLogger::fTransStopRun = "STOP_RUN";
337const char* DataLogger::fTransReset = "RESET";
338const char* DataLogger::fTransWait = "WAIT_RUN_NUMBER";
339const char* DataLogger::fRunNumberInfo = "RUN_NUMBER";
340const char* DataLogger::fPrintCommand = "PRINT";
341const char* DataLogger::fDebugOnOff = "DEBUG";
342const char* DataLogger::fStatsPeriod = "STATS_PERIOD";
343const char* DataLogger::fStartStopOpenedFiles = "OPENED_FILES_SRVC";
344const char* DataLogger::fStartStopNumSubsAndFits = "NUM_SUBS_SRVC";
345
346void DataLogger::ServicesMonitoring()
347{
348 //create the DIM service
349 int dataSize = 2*sizeof(long) + sizeof(long);
350
351 DataLoggerStats statVar;
352 statVar.sizeWritten = 0;
353 statVar.freeSpace = 0;
354 statVar.writingRate = 0;
355
356 struct statvfs vfs;
357 if (!statvfs(fNightlyFileName.c_str(), &vfs))
358 statVar.freeSpace = vfs.f_bsize*vfs.f_bavail;
359 else
360 statVar.freeSpace = -1;
361
362 DimDescribedService srvc ("DATA_LOGGER/STATS", "X:3", &statVar, dataSize, "Add description here");
363 fPreviousSize = 0;
364 bool statWarning = false;
365 //loop-wait for broadcast
366 while (fContinueMonitoring)
367 {
368 if (fStatsPeriodDuration == 0.0f)
369 {
370 sleep(0.1f);
371 continue;
372 }
373 else
374 sleep(fStatsPeriodDuration);
375 //update the fits files sizes
376#ifdef HAS_FITS
377 SubscriptionsListType::iterator x;
378 std::map<std::string, SubscriptionType>::iterator y;
379 bool runFileDone = false;
380 for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
381 {
382 for (y=x->second.begin(); y != x->second.end(); y++)
383 {
384 if (y->second.runFile.IsOpen() && !runFileDone)
385 {
386 fFileSizesMap[y->second.runFile.fFileName] = y->second.runFile.GetWrittenSize();
387#ifdef ONE_FITS_ONLY
388 runFileDone = true;
389#endif
390 }
391 if (y->second.nightlyFile.IsOpen())
392 fFileSizesMap[y->second.nightlyFile.fFileName] = y->second.nightlyFile.GetWrittenSize();
393 }
394 }
395#endif
396 struct stat st;
397 //gather log and report files sizes on disk
398 if (fNightlyLogFile.is_open())
399 {
400 stat(fFullNightlyLogFileName.c_str(), &st);
401 fFileSizesMap[fFullNightlyLogFileName] = st.st_size;
402 }
403 if (fNightlyReportFile.is_open())
404 {
405 stat(fFullNightlyReportFileName.c_str(), &st);
406 fFileSizesMap[fFullNightlyReportFileName] = st.st_size;
407 }
408 if (fRunLogFile.is_open())
409 {
410 stat(fFullRunLogFileName.c_str(), &st);
411 fFileSizesMap[fFullRunLogFileName] = st.st_size;
412 }
413 if (fRunReportFile.is_open())
414 {
415 stat(fFullRunReportFileName.c_str(), &st);
416 fFileSizesMap[fFullRunReportFileName] = st.st_size;
417 }
418
419 if (!statvfs(fNightlyFileName.c_str(), &vfs))
420 {
421 statVar.freeSpace = vfs.f_bsize*vfs.f_bavail;
422 statWarning = false;
423 }
424 else
425 {
426 std::stringstream str;
427 str << "Unable to retrieve stats for " << fNightlyFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
428 if (!statWarning)
429 Error(str);
430 statWarning = true;
431 statVar.freeSpace = -1;
432 }
433
434 //sum up all the file sizes. past and present
435 statVar.sizeWritten = 0;
436 for (std::map<std::string, long>::iterator it=fFileSizesMap.begin(); it != fFileSizesMap.end(); it++)
437 statVar.sizeWritten += it->second;
438 statVar.sizeWritten -= fBaseSizeNightly;
439 statVar.sizeWritten -= fBaseSizeRun;
440 if (fStatsPeriodDuration == 0.0f)
441 continue;
442 statVar.writingRate = (statVar.sizeWritten - fPreviousSize)/fStatsPeriodDuration;
443
444 fPreviousSize = statVar.sizeWritten;
445 if (statVar.writingRate != 0) //if data has been written
446 {
447 srvc.updateService();
448 if(fDebugIsOn)
449 {
450 stringstream str;
451 str << "Size written: " << statVar.sizeWritten/1024 << " KB; writting rate: ";
452 str << statVar.writingRate/1024 << " KB/s; free space: ";
453 str << statVar.freeSpace/(1024*1024) << " MB";
454 Debug(str.str());
455 }
456 }
457 }
458}
459
460
461// --------------------------------------------------------------------------
462//
463//! Default constructor. The name of the machine is given DATA_LOGGER
464//! and the state is set to kSM_Ready at the end of the function.
465//
466//!Setup the allows states, configs and transitions for the data logger
467//
468DataLogger::DataLogger(std::ostream &out) : StateMachineDim(out, "DATA_LOGGER")
469{
470 dic_disable_padding();
471 dis_disable_padding();
472
473 //initialize member data
474 fNightlyFileName = ".";//"/home/lyard/log";//
475 fRunFileName = ".";//"/home/lyard/log";
476 fRunNumber = 12345;
477#ifdef HAS_FITS
478#ifdef ONE_RUN_FITS_ONLY
479 fRunFitsFile = NULL;
480#endif
481#endif
482
483 //Give a name to this machine's specific states
484 AddStateName(kSM_NightlyOpen, "NightlyFileOpen", "Add description here");
485 AddStateName(kSM_WaitingRun, "WaitForRun", "Add description here");
486 AddStateName(kSM_Logging, "Logging", "Add description here");
487 AddStateName(kSM_BadNightlyConfig, "ErrNightlyFolder", "Add description here");
488 AddStateName(kSM_BadRunConfig, "ErrRunFolder", "Add description here");
489
490 /*Add the possible transitions for this machine*/
491 AddTransition(kSM_NightlyOpen, fTransStart, kSM_Ready, kSM_BadNightlyConfig)
492 (boost::bind(&DataLogger::StartPlease, this))
493 ("start the Nightly logging. Nightly file location must be specified already");
494
495 AddTransition(kSM_Ready, fTransStop, kSM_NightlyOpen, kSM_WaitingRun, kSM_Logging)
496 (boost::bind(&DataLogger::GoToReadyPlease, this))
497 ("stop the data logging");
498
499 AddTransition(kSM_Logging, fTransStartRun, kSM_WaitingRun, kSM_BadRunConfig)
500 (boost::bind(&DataLogger::StartRunPlease, this))
501 ("start the run logging. run file location must be specified already.");
502
503 AddTransition(kSM_WaitingRun, fTransStopRun, kSM_Logging)
504 (boost::bind(&DataLogger::StopRunPlease, this))
505 ("");
506
507 AddTransition(kSM_Ready, fTransReset, kSM_Error, kSM_BadNightlyConfig, kSM_BadRunConfig, kSM_Error)
508 (boost::bind(&DataLogger::GoToReadyPlease, this))
509 ("transition to exit error states. dunno if required or not, would close the Nightly file if already openned.");
510
511 AddTransition(kSM_WaitingRun, fTransWait, kSM_NightlyOpen)
512 (boost::bind(&DataLogger::NightlyToWaitRunPlease, this));
513
514 /*Add the possible configurations for this machine*/
515 AddConfiguration(fConfigDay, "C", kSM_Ready, kSM_BadNightlyConfig)
516 (boost::bind(&DataLogger::ConfigureNightlyFileName, this, _1))
517 ("configure the Nightly file location. cannot be done before the file is actually opened");
518
519 AddConfiguration(fConfigRun, "C", kSM_Ready, kSM_BadNightlyConfig, kSM_NightlyOpen, kSM_WaitingRun, kSM_BadRunConfig)
520 (boost::bind(&DataLogger::ConfigureRunFileName, this, _1))
521 ("configure the run file location. cannot be done before the file is actually opened, and not in a dailly related error.");
522 AddConfiguration(fConfigRunNumber, "I", kSM_Ready, kSM_BadNightlyConfig, kSM_NightlyOpen, kSM_WaitingRun, kSM_BadRunConfig)
523 (boost::bind(&DataLogger::ConfigureRunNumber, this, _1))
524 ("configure the run number. cannot be done in logging state");
525 //Provide a logging command
526 //I get the feeling that I should be going through the EventImp
527 //instead of DimCommand directly, mainly because the commandHandler
528 //is already done in StateMachineImp.cc
529 //Thus I'll simply add a configuration, which I will treat as the logging command
530 AddConfiguration(fConfigLog, "C", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_BadRunConfig)
531 (boost::bind(&DataLogger::LogMessagePlease, this, _1));
532
533 //Provide a print command
534 AddConfiguration(fPrintCommand, "", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_BadNightlyConfig, kSM_BadRunConfig)
535 (boost::bind(&DataLogger::PrintStatePlease, this, _1));
536
537 fServiceList.SetHandler(this);
538 CheckForServicesUpdate();
539
540 //start the monitoring service
541 fContinueMonitoring = true;
542 fMonitoringThread = boost::thread(boost::bind(&DataLogger::ServicesMonitoring, this));
543 fBaseSizeNightly = 0;
544 fBaseSizeRun = 0;
545 OpenFileToDim fToDim;
546 fToDim.code = 0;
547 fToDim.fileName[0] = '\0';
548 fOpenedNightlyFiles = new DimDescribedService((GetName() + "/FILENAME_NIGHTLY").c_str(), "I:1;C", &fToDim, sizeof(int)+1, "Add description here");//"i:1;C", static_cast<void*>(fDimBuffer), 256);
549 fOpenedRunFiles = new DimDescribedService((GetName() + "/FILENAME_RUN").c_str(), "I:1;C", &fToDim, sizeof(int)+1, "Add description here");
550 fNumSubAndFitsData.numSubscriptions = 0;
551 fNumSubAndFitsData.numOpenFits = 0;
552 fNumSubAndFits = new DimDescribedService((GetName() + "/NUM_SUBS").c_str(), "I:2", &fNumSubAndFitsData, sizeof(NumSubAndFitsType), "Add description here");
553 //black/white list
554 fIsBlackList = true;
555 fGreyList.clear();
556
557 //services parameters
558 fDebugIsOn = false;
559 fStatsPeriodDuration = 1.0f;
560 fOpenedFilesIsOn = true;
561 fNumSubAndFitsIsOn = true;
562 //provide services control commands
563 AddConfiguration(fDebugOnOff, "B:1", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready)
564 (boost::bind(&DataLogger::SetDebugOnOff, this, _1));
565 AddConfiguration(fStatsPeriod, "F", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready)
566 (boost::bind(&DataLogger::SetStatsPeriod, this, _1));
567 AddConfiguration(fStartStopOpenedFiles, "B:1", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready)
568 (boost::bind(&DataLogger::SetOpenedFilesOnOff ,this, _1));
569 AddConfiguration(fStartStopNumSubsAndFits, "B:1", kSM_NightlyOpen, kSM_Logging, kSM_WaitingRun, kSM_Ready)
570 (boost::bind(&DataLogger::SetNumSubsAndFitsOnOff, this, _1));
571 fDestructing = false;
572 if(fDebugIsOn)
573 {
574 Debug("DataLogger Init Done.");
575 }
576}
577// --------------------------------------------------------------------------
578//
579//! Checks for changes in the existing services.
580//! Any new service will be added to the service list, while the ones which disappeared are removed.
581//! @todo
582//! add the configuration (using the conf class ?)
583//
584//FIXME The service must be udpated so that I get the first notification. This should not be
585bool DataLogger::CheckForServicesUpdate()
586{
587 bool serviceUpdated = false;
588 //get the current server list
589 const std::vector<std::string> serverList = fServiceList.GetServerList();
590 //first let's remove the servers that may have disapeared
591 //can't treat the erase on maps the same way as for vectors. Do it the safe way instead
592 std::vector<std::string> toBeDeleted;
593 for (SubscriptionsListType::iterator cListe = fServiceSubscriptions.begin(); cListe != fServiceSubscriptions.end(); cListe++)
594 {
595 std::vector<std::string>::const_iterator givenServers;
596 for (givenServers=serverList.begin(); givenServers!= serverList.end(); givenServers++)
597 if (cListe->first == *givenServers)
598 break;
599 if (givenServers == serverList.end())//server vanished. Remove it
600 {
601 toBeDeleted.push_back(cListe->first);
602 serviceUpdated = true;
603 }
604
605 }
606 for (std::vector<std::string>::const_iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); it++)
607 fServiceSubscriptions.erase(*it);
608 //now crawl through the list of servers, and see if there was some updates
609 for (std::vector<std::string>::const_iterator i=serverList.begin(); i!=serverList.end();i++)
610 {
611 //skip the two de-fact excluded services
612 //Dim crashes if the publisher subscribes to its own service. This sounds weird, I agree.
613 if ((i->find("DIS_DNS") != std::string::npos) ||
614 (i->find("DATA_LOGGER") != std::string::npos))
615 continue;
616 if (fIsBlackList && (fGreyList.find(*i) != fGreyList.end()))
617 continue;
618 //find the current server in our subscription list
619 SubscriptionsListType::iterator cSubs = fServiceSubscriptions.find(*i);
620 //get the service list of the current server
621 std::vector<std::string> cServicesList = fServiceList.GetServiceList(*i);
622 if (cSubs != fServiceSubscriptions.end())//if the current server already is in our subscriptions
623 { //then check and update our list of subscriptions
624 //first, remove the services that may have dissapeared.
625 std::map<std::string, SubscriptionType>::iterator serverSubs;
626 std::vector<std::string>::const_iterator givenSubs;
627 toBeDeleted.clear();
628 for (serverSubs=cSubs->second.begin(); serverSubs != cSubs->second.end(); serverSubs++)
629 {
630 for (givenSubs = cServicesList.begin(); givenSubs != cServicesList.end(); givenSubs++)
631 if (serverSubs->first == *givenSubs)
632 break;
633 if (givenSubs == cServicesList.end())
634 {
635 toBeDeleted.push_back(serverSubs->first);
636 serviceUpdated = true;
637 }
638 }
639 for (std::vector<std::string>::const_iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); it++)
640 cSubs->second.erase(*it);
641 //now check for new services
642 for (givenSubs = cServicesList.begin(); givenSubs != cServicesList.end(); givenSubs++)
643 {
644 if (*givenSubs == "SERVICE_LIST")
645 continue;
646 if (fIsBlackList && fGreyList.find(*givenSubs) != fGreyList.end())
647 continue;
648
649 if (fIsBlackList && fGreyList.find((*i) + "/" + (*givenSubs)) != fGreyList.end())
650 continue;
651 else if (!fIsBlackList &&
652 (fGreyList.find((*i) + "/" + (*givenSubs)) == fGreyList.end()) &&
653 (fGreyList.find(*i) == fGreyList.end()) &&
654 (fGreyList.find(*givenSubs) == fGreyList.end()))
655 continue;
656 if (cSubs->second.find(*givenSubs) == cSubs->second.end())
657 {//service not found. Add it
658 cSubs->second[*givenSubs].dimInfo = new DimStampedInfo(((*i) + "/" + *givenSubs).c_str(), const_cast<char*>(""), this);
659 serviceUpdated = true;
660 if(fDebugIsOn)
661 {
662 stringstream str;
663 str << "Subscribing to service " << *i << "/" << *givenSubs;
664 Debug(str.str());
665 }
666 }
667 }
668 }
669 else //server not found in our list. Create its entry
670 {
671 fServiceSubscriptions[*i] = std::map<std::string, SubscriptionType>();
672 std::map<std::string, SubscriptionType>& liste = fServiceSubscriptions[*i];
673 for (std::vector<std::string>::const_iterator j = cServicesList.begin(); j!= cServicesList.end(); j++)
674 {
675 if (*j == "SERVICE_LIST")
676 continue;
677 if (fIsBlackList && fGreyList.find(*j) != fGreyList.end())
678 continue;
679
680 if (fIsBlackList && fGreyList.find((*i) + "/" + (*j)) != fGreyList.end())
681 continue;
682 else if (!fIsBlackList &&
683 (fGreyList.find((*i) + "/" + (*j)) == fGreyList.end()) &&
684 (fGreyList.find(*i) == fGreyList.end()) &&
685 (fGreyList.find(*j) == fGreyList.end()))
686 continue;
687
688 liste[*j].dimInfo = new DimStampedInfo(((*i) + "/" + (*j)).c_str(), const_cast<char*>(""), this);
689 serviceUpdated = true;
690 if(fDebugIsOn)
691 {
692 stringstream str;
693 str << "Subscribing to service " << *i << "/" << *j;
694 Debug(str.str());
695 }
696 }
697 }
698 }
699 return serviceUpdated;
700}
701// --------------------------------------------------------------------------
702//
703//! Destructor
704//
705DataLogger::~DataLogger()
706{
707 if (fDebugIsOn)
708 {
709 Debug("DataLogger destruction starts");
710 }
711 fDestructing = true;
712 //first let's go to the ready state
713 //TODO some closing done below has already been executed by GoToReady. figure out what should be removed.
714 GoToReadyPlease();
715 //release the services subscriptions
716 fServiceSubscriptions.clear();
717 //exit the monitoring loop
718 fContinueMonitoring = false;
719// delete[] fDimBuffer;
720 fMonitoringThread.join();
721 //close the files
722 if (fNightlyLogFile.is_open())
723 fNightlyLogFile.close();
724 if (fNightlyReportFile.is_open())
725 fNightlyReportFile.close();
726 if (fRunLogFile.is_open())
727 fRunLogFile.close();
728 if (fRunReportFile.is_open())
729 fRunReportFile.close();
730 delete fOpenedNightlyFiles;
731 delete fOpenedRunFiles;
732 delete fNumSubAndFits;
733//TODO notify that all files were closed
734#ifdef HAS_FITS
735#ifdef ONE_RUN_FITS_ONLY
736 if (fRunFitsFile != NULL)
737 delete fRunFitsFile;
738 fRunFitsFile = NULL;
739#endif
740#endif
741 if (fDebugIsOn)
742 {
743 Debug("DataLogger desctruction ends");
744 }
745}
746
747// --------------------------------------------------------------------------
748//
749//! Inherited from DimInfo. Handles all the Infos to which we subscribed, and log them
750//
751void DataLogger::infoHandler()
752{
753 // Make sure getTimestamp is called _before_ getTimestampMillisecs
754 if (fDestructing)
755 return;
756
757 DimInfo* I = getInfo();
758 SubscriptionsListType::iterator x;
759 std::map<std::string, SubscriptionType>::iterator y;
760 if (I==NULL)
761 {
762 if (CheckForServicesUpdate())
763 {
764 //services were updated. Notify
765 fNumSubAndFitsData.numSubscriptions = 0;
766 for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
767 fNumSubAndFitsData.numSubscriptions += x->second.size();
768 if (fNumSubAndFitsIsOn)
769 {
770 if (fDebugIsOn)
771 {
772 stringstream str;
773 str << "Updating number of subscriptions service: Num Subs=" << fNumSubAndFitsData.numSubscriptions << " Num open FITS=" << fNumSubAndFitsData.numOpenFits;
774 Debug(str.str());
775 }
776 fNumSubAndFits->updateService();
777 }
778 }
779 return;
780 }
781 //check if the service pointer corresponds to something that we subscribed to
782 //this is a fix for a bug that provides bad Infos when a server starts
783 bool found = false;
784 for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
785 {//find current service is subscriptions
786 for (y=x->second.begin(); y!=x->second.end();y++)
787 if (y->second.dimInfo == I)
788 {
789 found = true;
790 break;
791 }
792 if (found)
793 break;
794 }
795 if (!found)
796 return;
797 if (I->getSize() <= 0)
798 return;
799
800 // Make sure that getTimestampMillisecs is NEVER called before
801 // getTimestamp is properly called
802 // check that the message has been updated by something, i.e. must be different from its initial value
803 if (I->getTimestamp() == 0)
804 return;
805
806 CheckForRunNumber(I);
807 ReportPlease(I, y->second);
808
809}
810
811// --------------------------------------------------------------------------
812//
813//! Checks whether or not the current info is a run number.
814//! If so, then remember it. A run number is required to open the run-log file
815//! @param I
816//! the current DimInfo
817//
818void DataLogger::CheckForRunNumber(DimInfo* I)
819{
820 if (strstr(I->getName(), fRunNumberInfo) != NULL)
821 {//assumes that the run number is an integer
822 //TODO check the format here
823 fRunNumber = I->getInt();
824 stringstream str;
825 str << "New run number is " << fRunNumber;
826 Message(str.str());
827 }
828}
829
830// --------------------------------------------------------------------------
831//
832//! write infos to log files.
833//! @param I
834//! The current DimInfo
835//
836void DataLogger::ReportPlease(DimInfo* I, SubscriptionType& sub)
837{
838 //should we log or report this info ? (i.e. is it a message ?)
839 bool isItaReport = ((strstr(I->getName(), "Message") == NULL) && (strstr(I->getName(), "MESSAGE") == NULL));
840 if (I->getFormat()[0] == 'C')
841 isItaReport = false;
842 //TODO add service exclusion
843
844 if (!fNightlyReportFile.is_open())
845 return;
846
847 //create the converter for that service
848 if (sub.fConv == NULL && isItaReport)
849 {
850 //trick the converter in case of 'C'. why do I do this ? well simple: the converter checks that the right number
851 //of bytes was written. because I skip 'C' with fits, the bytes will not be allocated, hence the "size copied ckeck"
852 //of the converter will fail, hence throwing an exception.
853 std::string fakeFormat(I->getFormat());
854 if (fakeFormat[fakeFormat.size()-1] == 'C')
855 fakeFormat = fakeFormat.substr(0, fakeFormat.size()-1);
856 sub.fConv = new Converter(Out(), I->getFormat());
857 if (!sub.fConv)
858 {
859 std::stringstream str;
860 str << "Couldn't properly parse the format... service " << sub.dimInfo->getName() << " ignored.";
861 Error(str);
862 return;
863 }
864 }
865
866 //construct the header
867 std::stringstream header;
868 Time cTime(I->getTimestamp(), I->getTimestampMillisecs()*1000);
869 fQuality = I->getQuality();
870 fMjD = cTime.Mjd();
871
872 if (isItaReport)
873 {
874 //write text header
875 header << I->getName() << " " << fQuality << " ";
876 header << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
877 header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
878 header << cTime.ms() << " " << I->getTimestamp() << " ";
879
880 std::string text;
881 try
882 {
883 text = sub.fConv->GetString(I->getData(), I->getSize());
884 }
885 catch (const std::runtime_error &e)
886 {
887 Out() << kRed << e.what() << endl;
888 std::stringstream str;
889 str << "Could not properly parse the data for service " << sub.dimInfo->getName();
890 str << " reason: " << e.what() << ". Entry ignored";
891 Error(str);
892 return;
893 }
894
895 if (text.empty())
896 {
897 std::stringstream str;
898 str << "Service " << sub.dimInfo->getName() << " sent an empty string";
899 Info(str);
900 return;
901 }
902 //replace bizarre characters by white space
903 replace(text.begin(), text.end(), '\n', '\\');
904 replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');
905
906 //write entry to Nightly report
907 if (fNightlyReportFile.is_open())
908 {
909 if (fDebugIsOn)
910 {
911 stringstream str;
912 str << "Writing: \"" << header.str() << text << "\" to Nightly report file";
913 Debug(str.str());
914 }
915 fNightlyReportFile << header.str() << text << std::endl;
916 //check if either eof, bailbit or batbit are set
917 if (!fNightlyReportFile.good())
918 {
919 Error("An error occured while writing to the nightly report file. Closing it");
920 if (fNightlyReportFile.is_open())
921 fNightlyReportFile.close();
922 }
923 }
924 //write entry to run-report
925 if (fRunReportFile.is_open())
926 {
927 if (fDebugIsOn)
928 {
929 stringstream str;
930 str << "Writing: \"" << header.str() << text << "\" to Run report file";
931 Debug(str.str());
932 }
933 fRunReportFile << header.str() << text << std::endl;
934 if (!fRunReportFile.good())
935 {
936 Error("An error occured while writing to the run report file. Closing it.");
937 if (fRunReportFile.is_open())
938 fRunReportFile.close();
939 }
940 }
941 }
942 else
943 {//write entry to both Nightly and run logs
944 std::string n = I->getName();
945 std::stringstream msg;
946 msg << n.substr(0, n.find_first_of('/')) << ": " << I->getString();
947
948 if (fNightlyLogFile.is_open())
949 {
950 if (fDebugIsOn)
951 {
952 stringstream str;
953 str << "Writing: \"" << msg.str() << "\" to Nightly log file";
954 Debug(str.str());
955 }
956 MessageImp nightlyMess(fNightlyLogFile);
957 nightlyMess.Write(cTime, msg.str().c_str(), fQuality);
958 if (!fNightlyLogFile.good())
959 {
960 Error("An error occured while writing to the nightly log file. Closing it.");
961 if (fNightlyLogFile.is_open())
962 fNightlyLogFile.close();
963 }
964 }
965 if (fRunLogFile.is_open())
966 {
967 if (fDebugIsOn)
968 {
969 stringstream str;
970 str << "Writing: \"" << msg.str() << "\" to Run log file";
971 Debug(str.str());
972 }
973 MessageImp runMess(fRunLogFile);
974 runMess.Write(cTime, msg.str().c_str(), fQuality);
975 if (!fRunLogFile.good())
976 {
977 Error("An error occured while writing to the run log file. Closing it.");
978 if (fRunLogFile.is_open())
979 fRunLogFile.close();
980 }
981 }
982 }
983
984#ifdef HAS_FITS
985 if (isItaReport)
986 {
987 if (!sub.nightlyFile.IsOpen() || !sub.runFile.IsOpen())
988 OpenFITSFilesPlease(sub);
989 WriteToFITS(sub);
990 }
991#endif
992
993}
994
995// --------------------------------------------------------------------------
996//
997//! write messages to logs.
998//! @param evt
999//! the current event to log
1000//! @returns
1001//! the new state. Currently, always the current state
1002//!
1003//! @deprecated
1004//! I guess that this function should not be any longer
1005//
1006//TODO isn't that function not used any longer ? If so I guess that we should get rid of it...
1007//Otherwise re-write it properly with the MessageImp class
1008int DataLogger::LogMessagePlease(const Event& evt)
1009{
1010 if (!fNightlyLogFile.is_open())
1011 return GetCurrentState();
1012
1013 std::stringstream header;
1014 const Time& cTime = evt.GetTime();
1015 header << evt.GetName() << " " << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
1016 header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
1017 header << cTime.ms() << " ";
1018
1019 const Converter conv(Out(), evt.GetFormat());
1020 if (!conv)
1021 {
1022 Error("Couldn't properly parse the format... ignored.");
1023 return GetCurrentState();
1024 }
1025
1026 std::string text;
1027 try
1028 {
1029 text = conv.GetString(evt.GetData(), evt.GetSize());
1030 }
1031 catch (const std::runtime_error &e)
1032 {
1033 Out() << kRed << e.what() << endl;
1034 Error("Couldn't properly parse the data... ignored.");
1035 return GetCurrentState();
1036 }
1037
1038 if (text.empty())
1039 return GetCurrentState();
1040
1041 //replace bizarre characters by white space
1042 replace(text.begin(), text.end(), '\n', '\\');
1043 replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');
1044 if (fDebugIsOn)
1045 {
1046 stringstream str;
1047 str << "Logging: \"" << header << text << "\"";
1048 Debug(str.str());
1049 }
1050
1051 if (fNightlyLogFile.is_open())
1052 {
1053 fNightlyLogFile << header;
1054 if (!fNightlyLogFile.good())
1055 {
1056 Error("An error occured while writing to the run log file. Closing it.");
1057 if (fNightlyLogFile.is_open())
1058 fNightlyLogFile.close();
1059 }
1060 }
1061 if (fRunLogFile.is_open())
1062 {
1063 fRunLogFile << header;
1064 if (!fRunLogFile.good())
1065 {
1066 Error("An error occured while writing to the run log file. Closing it.");
1067 if (fRunLogFile.is_open())
1068 fRunLogFile.close();
1069 }
1070 }
1071 if (fNightlyLogFile.is_open())
1072 {
1073 fNightlyLogFile << text;
1074 if (!fNightlyLogFile.good())
1075 {
1076 Error("An error occured while writing to the run log file. Closing it.");
1077 if (fNightlyLogFile.is_open())
1078 fNightlyLogFile.close();
1079 }
1080 }
1081 if (fRunLogFile.is_open())
1082 {
1083 fRunLogFile << text;
1084 if (!fRunLogFile.good())
1085 {
1086 Error("An error occured while writing to the run log file. Closing it.");
1087 if (fRunLogFile.is_open())
1088 fRunLogFile.close();
1089 }
1090 }
1091 return GetCurrentState();
1092}
1093// --------------------------------------------------------------------------
1094//
1095//! print the dataLogger's current state. invoked by the PRINT command
1096//! @param evt
1097//! the current event. Not used by the method
1098//! @returns
1099//! the new state. Which, in that case, is the current state
1100//!
1101int DataLogger::PrintStatePlease(const Event& )
1102{
1103 Message("-----------------------------------------");
1104 Message("------DATA LOGGER CURRENT STATE----------");
1105 Message("-----------------------------------------");
1106 //print the path configuration
1107 std::string actualTargetDir;
1108 if (fNightlyFileName == ".")
1109 {
1110 char currentPath[FILENAME_MAX];
1111 if (getcwd(currentPath, sizeof(currentPath)))
1112 actualTargetDir = currentPath;
1113 }
1114 else
1115 actualTargetDir = fNightlyFileName;
1116 Message("Nightly Path: " + actualTargetDir);
1117 if (fRunFileName == ".")
1118 {
1119 char currentPath[FILENAME_MAX];
1120 if (getcwd(currentPath, sizeof(currentPath)))
1121 actualTargetDir = currentPath;
1122 }
1123 else
1124 actualTargetDir = fRunFileName;
1125 Message("Run Path: " + actualTargetDir);
1126 stringstream str;
1127 str << "Run Number: " << fRunFileName;
1128 Message(str.str());
1129 Message("-----------OPENED FILES------------------");
1130 //print all the open files.
1131 if (fNightlyLogFile.is_open())
1132 Message("Nightly Log..........OPEN");
1133 else
1134 Message("Nightly log........CLOSED");
1135 if (fNightlyReportFile.is_open())
1136 Message("Nightly Report.......OPEN");
1137 else
1138 Message("Nightly Report.....CLOSED");
1139 if (fRunLogFile.is_open())
1140 Message("Run Log..............OPEN");
1141 else
1142 Message("Run Log............CLOSED");
1143 if (fRunReportFile.is_open())
1144 Message("Run Report...........OPEN");
1145 else
1146 Message("Run Report.........CLOSED");
1147#ifdef HAS_FITS
1148 str.str("");
1149 str << "There are " << fNumSubAndFitsData.numOpenFits << " FITS files open:";
1150 Message(str.str());
1151 SubscriptionsListType::iterator x;
1152 std::map<std::string, SubscriptionType>::iterator y;
1153 bool runFileDone = false;
1154 for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
1155 {
1156 for (y=x->second.begin(); y != x->second.end(); y++)
1157 {
1158 if (y->second.runFile.IsOpen() && !runFileDone)
1159 {
1160 fFileSizesMap[y->second.runFile.fFileName] = y->second.runFile.GetWrittenSize();
1161 str.str("");
1162 str << ">>>" << y->second.runFile.fFileName;
1163 Message(str.str());
1164#ifdef ONE_FITS_ONLY
1165 runFileDone = true;
1166#endif
1167 }
1168 if (y->second.nightlyFile.IsOpen())
1169 {
1170 fFileSizesMap[y->second.nightlyFile.fFileName] = y->second.nightlyFile.GetWrittenSize();
1171 str.str("");
1172 str << ">>>" << y->second.nightlyFile.fFileName;
1173 Message(str.str());
1174 }
1175 }
1176 }
1177#else
1178 Message("FITS output disabled at compilation");
1179#endif
1180 struct stat st;
1181 DataLoggerStats statVar;
1182 //gather log and report files sizes on disk
1183 if (fNightlyLogFile.is_open())
1184 {
1185 stat(fFullNightlyLogFileName.c_str(), &st);
1186 fFileSizesMap[fFullNightlyLogFileName] = st.st_size;
1187 }
1188 if (fNightlyReportFile.is_open())
1189 {
1190 stat(fFullNightlyReportFileName.c_str(), &st);
1191 fFileSizesMap[fFullNightlyReportFileName] = st.st_size;
1192 }
1193 if (fRunLogFile.is_open())
1194 {
1195 stat(fFullRunLogFileName.c_str(), &st);
1196 fFileSizesMap[fFullRunLogFileName] = st.st_size;
1197 }
1198 if (fRunReportFile.is_open())
1199 {
1200 stat(fFullRunReportFileName.c_str(), &st);
1201 fFileSizesMap[fFullRunReportFileName] = st.st_size;
1202 }
1203 struct statvfs vfs;
1204 if (!statvfs(fNightlyFileName.c_str(), &vfs))
1205 {
1206 statVar.freeSpace = vfs.f_bsize*vfs.f_bavail;
1207 }
1208 else
1209 {
1210 str.str("");
1211 str << "Unable to retrieve stats for " << fNightlyFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1212 Error(str);;
1213 statVar.freeSpace = -1;
1214 }
1215
1216 //sum up all the file sizes. past and present
1217 statVar.sizeWritten = 0;
1218 for (std::map<std::string, long>::iterator it=fFileSizesMap.begin(); it != fFileSizesMap.end(); it++)
1219 statVar.sizeWritten += it->second;
1220 statVar.sizeWritten -= fBaseSizeNightly;
1221 statVar.sizeWritten -= fBaseSizeRun;
1222 str.str("");
1223 str << "Total Size written: " << statVar.sizeWritten;
1224 str << " Disk free space: " << statVar.freeSpace;
1225 Message("-----------------STATS-------------------");
1226 Message(str.str());
1227 Message("------------DIM SUBSCRIPTIONS------------");
1228 str.str("");
1229 str << "There are " << fNumSubAndFitsData.numSubscriptions << " active DIM subscriptions:";
1230 Message(str.str());
1231 str.str("");
1232 for (std::map<const std::string, std::map<std::string, SubscriptionType>>::const_iterator it=fServiceSubscriptions.begin(); it!= fServiceSubscriptions.end();it++)
1233 {
1234 str << "Server " << it->first;
1235 Message(str.str());
1236 for (std::map<std::string, SubscriptionType>::const_iterator it2=it->second.begin(); it2!=it->second.end(); it2++)
1237 {
1238 str.str("");
1239 str << " " << it2->first;
1240 Message(str.str());
1241 }
1242 }
1243 Message("-----------------------------------------");
1244
1245 return GetCurrentState();
1246}
1247
1248// --------------------------------------------------------------------------
1249//
1250//! turn debug mode on and off
1251//! @param evt
1252//! the current event. contains the instruction string: On, Off, on, off, ON, OFF, 0 or 1
1253//! @returns
1254//! the new state. Which, in that case, is the current state
1255//!
1256int DataLogger::SetDebugOnOff(const Event& evt)
1257{
1258 bool backupDebug = fDebugIsOn;
1259 fDebugIsOn = evt.GetBool();
1260 if (fDebugIsOn == backupDebug)
1261 Warn("Warning: debug mode was already in the requested state");
1262 else
1263 {
1264 stringstream str;
1265 str << "Debug mode is now " << fDebugIsOn;
1266 Message(str.str());
1267 }
1268 return GetCurrentState();
1269}
1270// --------------------------------------------------------------------------
1271//
1272//! set the statistics update period duration. 0 disables the statistics
1273//! @param evt
1274//! the current event. contains the new duration.
1275//! @returns
1276//! the new state. Which, in that case, is the current state
1277//!
1278int DataLogger::SetStatsPeriod(const Event& evt)
1279{
1280 float backupDuration = fStatsPeriodDuration;
1281 fStatsPeriodDuration = evt.GetFloat();
1282 if (fStatsPeriodDuration < 0)
1283 {
1284 Error("Statistics period duration should be greater than zero. Discarding provided value.");
1285 fStatsPeriodDuration = backupDuration;
1286 return GetCurrentState();
1287 }
1288 if (fStatsPeriodDuration != fStatsPeriodDuration)
1289 {
1290 Error("Provided duration does not appear to be a valid float. discarding it.");
1291 fStatsPeriodDuration = backupDuration;
1292 return GetCurrentState();
1293 }
1294 if (backupDuration == fStatsPeriodDuration)
1295 Warn("Warning: statistics period was not modified: supplied value already in use");
1296 else
1297 {
1298 if (fStatsPeriodDuration == 0.0f)
1299 Message("Statistics are now OFF");
1300 else
1301 {
1302 stringstream str;
1303 str << "Statistics period is now " << fStatsPeriodDuration << " seconds";
1304 Message(str.str());
1305 }
1306 }
1307 return GetCurrentState();
1308}
1309// --------------------------------------------------------------------------
1310//
1311//! set the opened files service on or off.
1312//! @param evt
1313//! the current event. contains the instruction string. similar to setdebugonoff
1314//! @returns
1315//! the new state. Which, in that case, is the current state
1316//!
1317int DataLogger::SetOpenedFilesOnOff(const Event& evt)
1318{
1319 bool backupOpened = fOpenedFilesIsOn;
1320 fOpenedFilesIsOn = evt.GetBool();
1321 if (fOpenedFilesIsOn == backupOpened)
1322 Warn("Warning: opened files service mode was already in the requested state");
1323 else
1324 {
1325 stringstream str;
1326 str << "Opened files service mode is now " << fOpenedFilesIsOn;
1327 Message(str.str());
1328 }
1329 return GetCurrentState();
1330
1331}
1332// --------------------------------------------------------------------------
1333//
1334//! set the number of subscriptions and opened fits on and off
1335//! @param evt
1336//! the current event. contains the instruction string. similar to setdebugonoff
1337//! @returns
1338//! the new state. Which, in that case, is the current state
1339//!
1340int DataLogger::SetNumSubsAndFitsOnOff(const Event& evt)
1341{
1342 bool backupSubs = fNumSubAndFitsIsOn;
1343 fNumSubAndFitsIsOn = evt.GetBool();
1344 if (fNumSubAndFitsIsOn == backupSubs)
1345 Warn("Warning: Number of subscriptions service mode was already in the requested state");
1346 else
1347 {
1348 stringstream str;
1349 str << "Number of subscriptions service mode is now " << fNumSubAndFitsIsOn;
1350 Message(str.str());
1351 }
1352 return GetCurrentState();
1353}
1354// --------------------------------------------------------------------------
1355//
1356//! Sets the path to use for the Nightly log file.
1357//! @param evt
1358//! the event transporting the path
1359//! @returns
1360//! currently only the current state.
1361//
1362int DataLogger::ConfigureNightlyFileName(const Event& evt)
1363{
1364 if (evt.GetText() != NULL)
1365 {
1366 fNightlyFileName = std::string(evt.GetText());
1367 Message("New Nightly folder specified: " + fNightlyFileName);
1368 }
1369 else
1370 Error("Empty Nightly folder given. Please specify a valid path.");
1371
1372 return GetCurrentState();
1373}
1374// --------------------------------------------------------------------------
1375//
1376//! Sets the path to use for the run log file.
1377//! @param evt
1378//! the event transporting the path
1379//! @returns
1380//! currently only the current state
1381int DataLogger::ConfigureRunFileName(const Event& evt)
1382{
1383 if (evt.GetText() != NULL)
1384 {
1385 fRunFileName = std::string(evt.GetText());
1386 Message("New Run folder specified: " + fRunFileName);
1387 }
1388 else
1389 Error("Empty Nightly folder given. Please specify a valid path");
1390
1391 return GetCurrentState();
1392}
1393// --------------------------------------------------------------------------
1394//
1395//! Sets the run number.
1396//! @param evt
1397//! the event transporting the run number
1398//! @returns
1399//! currently only the current state
1400//TODO remove this function as the run numbers will be distributed through a dedicated service
1401int DataLogger::ConfigureRunNumber(const Event& evt)
1402{
1403 fRunNumber = evt.GetInt();
1404 std::stringstream str;
1405 str << "The new run number is: " << fRunNumber;
1406 Message(str.str());
1407 return GetCurrentState();
1408}
1409// --------------------------------------------------------------------------
1410//
1411//! Notifies the DIM service that a particular file was opened
1412//! @ param name the base name of the opened file, i.e. without path nor extension.
1413//! WARNING: use string instead of string& because I pass values that do not convert to string&.
1414//! this is not a problem though because file are not opened so often.
1415//! @ param type the type of the opened file. 0 = none open, 1 = log, 2 = text, 4 = fits
1416inline void DataLogger::NotifyOpenedFile(std::string name, int type, DimDescribedService* service)
1417{
1418 if (fOpenedFilesIsOn)
1419 {
1420 if (fDebugIsOn)
1421 {
1422 stringstream str;
1423 str << "Updating files service " << service->getName() << "with code: " << type << " and file: " << name;
1424 Debug(str.str());
1425 str.str("");
1426 str << "Num subs: " << fNumSubAndFitsData.numSubscriptions << " Num open FITS: " << fNumSubAndFitsData.numOpenFits;
1427 Debug(str.str());
1428 }
1429 OpenFileToDim fToDim;
1430 fToDim.code = type;
1431 memcpy(fToDim.fileName, name.c_str(), name.size()+1);
1432 service->setData(reinterpret_cast<void*>(&fToDim), name.size()+1+sizeof(int));
1433 service->setQuality(0);
1434 service->updateService();
1435 }
1436}
1437// --------------------------------------------------------------------------
1438//
1439//! Implements the Start transition.
1440//! Concatenates the given path for the Nightly file and the filename itself (based on the day),
1441//! and tries to open it.
1442//! @returns
1443//! kSM_NightlyOpen if success, kSM_BadNightlyConfig if failure
1444int DataLogger::StartPlease()
1445{
1446 if (fDebugIsOn)
1447 {
1448 Debug("Starting...");
1449 }
1450 Time time;
1451 std::stringstream sTime;
1452 sTime << time.Y() << "_" << time.M() << "_" << time.D();
1453
1454 fFullNightlyLogFileName = fNightlyFileName + '/' + sTime.str() + ".log";
1455 fNightlyLogFile.open(fFullNightlyLogFileName.c_str(), std::ios_base::out | std::ios_base::app);
1456 if (errno != 0)
1457 {
1458 std::stringstream str;
1459 str << "Unable to open Nightly Log " << fFullNightlyLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1460 Error(str);
1461 }
1462 fFullNightlyReportFileName = fNightlyFileName + '/' + sTime.str() + ".rep";
1463 fNightlyReportFile.open(fFullNightlyReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1464 if (errno != 0)
1465 {
1466 std::stringstream str;
1467 str << "Unable to open Nightly Report " << fFullNightlyReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1468 Error(str);
1469 }
1470
1471 if (!fNightlyLogFile.is_open() || !fNightlyReportFile.is_open())
1472 {
1473 //TODO send an error message
1474 return kSM_BadNightlyConfig;
1475 }
1476 //get the size of the newly opened file.
1477 struct stat st;
1478 stat(fFullNightlyLogFileName.c_str(), &st);
1479 fBaseSizeNightly = st.st_size;
1480 stat(fFullNightlyReportFileName.c_str(), &st);
1481 fBaseSizeNightly += st.st_size;
1482 fFileSizesMap.clear();
1483 fBaseSizeRun = 0;
1484 fPreviousSize = 0;
1485 //notify that files were opened
1486 std::string actualTargetDir;
1487 if (fNightlyFileName == ".")
1488 {
1489 char currentPath[FILENAME_MAX];
1490 if (!getcwd(currentPath, sizeof(currentPath)))
1491 {
1492 if (errno != 0)
1493 {
1494 std::stringstream str;
1495 str << "Unable retrieve current path" << ". Reason: " << strerror(errno) << " [" << errno << "]";
1496 Error(str);
1497 }
1498 }
1499 actualTargetDir = currentPath;
1500 }
1501 else
1502 {
1503 actualTargetDir = fNightlyFileName;
1504 }
1505 //notify that a new file has been opened.
1506 NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 3, fOpenedNightlyFiles);
1507
1508 return kSM_NightlyOpen;
1509}
1510
1511#ifdef HAS_FITS
1512// --------------------------------------------------------------------------
1513//
1514//! open if required a the FITS files corresponding to a given subscription
1515//! @param sub
1516//! the current DimInfo subscription being examined
1517void DataLogger::OpenFITSFilesPlease(SubscriptionType& sub)
1518{
1519 std::string serviceName(sub.dimInfo->getName());
1520 for (unsigned int i=0;i<serviceName.size(); i++)
1521 {
1522 if (serviceName[i] == '/')
1523 {
1524 serviceName[i] = '_';
1525 break;
1526 }
1527 }
1528 Time time;
1529 std::stringstream sTime;
1530 sTime << time.Y() << "_" << time.M() << "_" << time.D();
1531 //we open the NightlyFile anyway, otherwise this function shouldn't have been called.
1532 if (!sub.nightlyFile.IsOpen())
1533 {
1534 std::string partialName = fNightlyFileName + '/' + sTime.str() + '_' + serviceName + ".fits";
1535 AllocateFITSBuffers(sub);
1536 //get the size of the file we're about to open
1537 if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1538 {
1539 struct stat st;
1540 if (!stat(partialName.c_str(), &st))
1541 fBaseSizeNightly += st.st_size;
1542 fFileSizesMap[partialName] = 0;
1543 }
1544 sub.nightlyFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, Out());
1545 //notify the opening
1546 std::string actualTargetDir;
1547 if (fNightlyFileName == ".")
1548 {
1549 char currentPath[FILENAME_MAX];
1550 if (getcwd(currentPath, sizeof(currentPath)))
1551 actualTargetDir = currentPath;
1552 }
1553 else
1554 {
1555 actualTargetDir = fNightlyFileName;
1556 }
1557 NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 7, fOpenedNightlyFiles);
1558 if (fNumSubAndFitsIsOn)
1559 fNumSubAndFits->updateService();
1560 if (fDebugIsOn)
1561 {
1562 stringstream str;
1563 str << "Opened Nightly FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits;
1564 Debug(str.str());
1565 }
1566 }
1567 if (!sub.runFile.IsOpen() && (GetCurrentState() == kSM_Logging))
1568 {//buffer for the run file have already been allocated when doing the Nightly file
1569 std::stringstream sRun;
1570 sRun << fRunNumber;
1571#ifdef ONE_RUN_FITS_ONLY
1572 std::string partialName = fRunFileName + '/' + sRun.str() + ".fits";
1573 if (fRunFitsFile == NULL)
1574 {
1575#else
1576 std::string partialName = fRunFileName + '/' + sRun.str() + '_' + serviceName + ".fits";
1577#endif
1578 //get the size of the file we're about to open
1579 if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1580 {
1581 struct stat st;
1582 if (!stat(partialName.c_str(), &st))
1583 fBaseSizeRun += st.st_size;
1584 else
1585 fBaseSizeRun = 0;
1586 fFileSizesMap[partialName] = 0;
1587 }
1588#ifdef ONE_RUN_FITS_ONLY
1589 try
1590 {
1591 fRunFitsFile = new FITS(partialName, RWmode::Write);
1592 (fNumSubAndFitsData.numOpenFits)++;
1593 }
1594 catch (CCfits::FitsError e)
1595 {
1596 std::stringstream str;
1597 str << "Could not open FITS Run file " << partialName << " reason: " << e.message();
1598 Error(str);
1599 fRunFitsFile = NULL;
1600 }
1601#endif
1602 std::string actualTargetDir;
1603 if (fRunFileName == ".")
1604 {
1605 char currentPath[FILENAME_MAX];
1606 if (getcwd(currentPath, sizeof(currentPath)))
1607 actualTargetDir = currentPath;
1608 }
1609 else
1610 {
1611 actualTargetDir = fRunFileName;
1612 }
1613 NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 7, fOpenedRunFiles);// + '_' + serviceName, 4);
1614#ifdef ONE_RUN_FITS_ONLY
1615 }
1616 sub.runFile.Open(partialName, serviceName, fRunFitsFile, &fNumSubAndFitsData.numOpenFits, Out());
1617#else
1618 sub.runFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, Out());
1619#endif //one_run_fits_only
1620 if (fNumSubAndFitsIsOn)
1621 fNumSubAndFits->updateService();
1622 if (fDebugIsOn)
1623 {
1624 stringstream str;
1625 str << "Opened Run FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits;
1626 Debug(str.str());
1627 }
1628 }
1629}
1630// --------------------------------------------------------------------------
1631//
1632void DataLogger::AllocateFITSBuffers(SubscriptionType& sub)
1633{
1634 int size = sub.dimInfo->getSize();
1635
1636 //Init the time columns of the file
1637 Description dateDesc(std::string("Time"), std::string("Modified Julian Date"), std::string("MjD"));
1638 sub.nightlyFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1639 sub.runFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1640
1641 Description QoSDesc("Qos", "Quality of service", "None");
1642 sub.nightlyFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1643 sub.runFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1644
1645 const Converter::FormatList flist = sub.fConv->GetList();
1646 // Compilation failed
1647 if (flist.empty() || flist.back().first.second!=0)
1648 {
1649 Error("Compilation of format string failed.");
1650 return;
1651 }
1652
1653 //we've got a nice structure describing the format of this service's messages.
1654 //Let's create the appropriate FITS columns
1655 std::vector<std::string> dataFormatsLocal;
1656 for (unsigned int i=0;i<flist.size()-1;i++)
1657 {
1658 std::stringstream dataQualifier;
1659
1660 dataQualifier << flist[i].second.first;
1661 switch (flist[i].first.first->name()[0])
1662 {//TODO handle all the data format cases
1663 case 'c':
1664 case 'C':
1665 dataQualifier.str("S");
1666 break;
1667 case 's':
1668 dataQualifier << "I";
1669 break;
1670 case 'i':
1671 case 'I':
1672 dataQualifier << "J";
1673 break;
1674 case 'l':
1675 case 'L':
1676 dataQualifier << "J";
1677 //TODO triple check that in FITS, long = int
1678 break;
1679 case 'f':
1680 case 'F':
1681 dataQualifier << "E";
1682 break;
1683 case 'd':
1684 case 'D':
1685 dataQualifier << "D";
1686 break;
1687 case 'x':
1688 case 'X':
1689 dataQualifier << "K";
1690 break;
1691 case 'S':
1692 //for strings, the number of elements I get is wrong. Correct it
1693 dataQualifier.str(""); //clear
1694 dataQualifier << size-1 << "A";
1695 size = size-1;
1696 break;
1697
1698 default:
1699 Error("THIS SHOULD NEVER BE REACHED. dataLogger.cc ln 1198.");
1700 };
1701 //we skip the variable length strings for now (in fits only)
1702 if (dataQualifier.str() != "S")
1703 dataFormatsLocal.push_back(dataQualifier.str());
1704 }
1705 sub.nightlyFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1706 sub.runFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1707}
1708// --------------------------------------------------------------------------
1709//
1710//! write a dimInfo data to its corresponding FITS files
1711//
1712void DataLogger::WriteToFITS(SubscriptionType& sub)
1713{
1714 //nightly File status (open or not) already checked
1715 if (sub.nightlyFile.IsOpen())
1716 {
1717 sub.nightlyFile.Write(sub.fConv);
1718 if (fDebugIsOn)
1719 {
1720 Debug("Writing to nightly FITS " + sub.nightlyFile.fFileName);
1721 }
1722 }
1723 if (sub.runFile.IsOpen())
1724 {
1725 sub.runFile.Write(sub.fConv);
1726 if (fDebugIsOn)
1727 {
1728 Debug("Writing to Run FITS " + sub.runFile.fFileName);
1729 }
1730 }
1731}
1732#endif //if has_fits
1733// --------------------------------------------------------------------------
1734//
1735//! Implements the StartRun transition.
1736//! Concatenates the given path for the run file and the filename itself (based on the run number),
1737//! and tries to open it.
1738//! @returns
1739//! kSM_Logging if success, kSM_BadRunConfig if failure.
1740int DataLogger::StartRunPlease()
1741{
1742 if (fDebugIsOn)
1743 {
1744 Debug("Starting Run Logging...");
1745 }
1746 //attempt to open run file with current parameters
1747 if (fRunNumber == -1)
1748 return kSM_BadRunConfig;
1749 std::stringstream sRun;
1750 sRun << fRunNumber;
1751 fFullRunLogFileName = fRunFileName + '/' + sRun.str() + ".log";
1752 fRunLogFile.open(fFullRunLogFileName.c_str(), std::ios_base::out | std::ios_base::app); //maybe should be app instead of ate
1753 if (errno != 0)
1754 {
1755 std::stringstream str;
1756 str << "Unable to open run Log " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1757 Error(str);
1758 }
1759 fFullRunReportFileName = fRunFileName + '/' + sRun.str() + ".rep";
1760 fRunReportFile.open(fFullRunReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1761 if (errno != 0)
1762 {
1763 std::stringstream str;
1764 str << "Unable to open run report " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1765 Error(str);
1766 }
1767
1768 if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1769 {
1770 //TODO send an error message
1771 return kSM_BadRunConfig;
1772 }
1773 //get the size of the newly opened file.
1774 struct stat st;
1775 fBaseSizeRun = 0;
1776 if (fFileSizesMap.find(fFullRunLogFileName) == fFileSizesMap.end())
1777 {
1778 stat(fFullRunLogFileName.c_str(), &st);
1779 if (errno != 0)
1780 {
1781 std::stringstream str;
1782 str << "Unable to stat " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1783 Error(str);
1784 }
1785 else
1786 fBaseSizeRun += st.st_size;
1787 fFileSizesMap[fFullRunLogFileName] = 0;
1788 }
1789 if (fFileSizesMap.find(fFullRunReportFileName) == fFileSizesMap.end())
1790 {
1791 stat(fFullRunReportFileName.c_str(), &st);
1792 if (errno != 0)
1793 {
1794 std::stringstream str;
1795 str << "Unable to stat " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1796 Error(str);
1797 }
1798 else
1799 fBaseSizeRun += st.st_size;
1800 fFileSizesMap[fFullRunReportFileName] = 0;
1801 }
1802 std::string actualTargetDir;
1803 if (fRunFileName == ".")
1804 {
1805 char currentPath[FILENAME_MAX];
1806 if (!getcwd(currentPath, sizeof(currentPath)))
1807 {
1808 if (errno != 0)
1809 {
1810 std::stringstream str;
1811 str << "Unable to retrieve the current path" << ". Reason: " << strerror(errno) << " [" << errno << "]";
1812 Error(str);
1813 }
1814 }
1815 actualTargetDir = currentPath;
1816 }
1817 else
1818 {
1819 actualTargetDir = fRunFileName;
1820 }
1821 NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 3, fOpenedRunFiles);
1822
1823 return kSM_Logging;
1824}
1825// --------------------------------------------------------------------------
1826//
1827//! Implements the StopRun transition.
1828//! Attempts to close the run file.
1829//! @returns
1830//! kSM_WaitingRun if success, kSM_FatalError otherwise
1831int DataLogger::StopRunPlease()
1832{
1833 if (fDebugIsOn)
1834 {
1835 Debug("Stopping Run Logging...");
1836 }
1837 if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1838 return kSM_FatalError;
1839
1840 fRunLogFile.close();
1841 fRunReportFile.close();
1842#ifdef HAS_FITS
1843 for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
1844 for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
1845 {
1846 if (j->second.runFile.IsOpen())
1847 j->second.runFile.Close();
1848 }
1849#ifdef ONE_RUN_FITS_ONLY
1850 if (fRunFitsFile != NULL)
1851 {
1852 delete fRunFitsFile;
1853 fRunFitsFile = NULL;
1854 (fNumSubAndFitsData.numOpenFits)--;
1855 }
1856#endif
1857#endif
1858 NotifyOpenedFile("", 0, fOpenedRunFiles);
1859 if (fNumSubAndFitsIsOn)
1860 fNumSubAndFits->updateService();
1861 return kSM_WaitingRun;
1862
1863}
1864// --------------------------------------------------------------------------
1865//
1866//! Implements the Stop and Reset transitions.
1867//! Attempts to close any openned file.
1868//! @returns
1869//! kSM_Ready
1870int DataLogger::GoToReadyPlease()
1871{
1872 if (fDebugIsOn)
1873 {
1874 Debug("Going to the Ready state...");
1875 }
1876 if (fNightlyLogFile.is_open())
1877 fNightlyLogFile.close();
1878 if (fNightlyReportFile.is_open())
1879 fNightlyReportFile.close();
1880
1881 if (fRunLogFile.is_open())
1882 fRunLogFile.close();
1883 if (fRunReportFile.is_open())
1884 fRunReportFile.close();
1885
1886#ifdef HAS_FITS
1887 for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
1888 for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
1889 {
1890 if (j->second.nightlyFile.IsOpen())
1891 j->second.nightlyFile.Close();
1892 if (j->second.runFile.IsOpen())
1893 j->second.runFile.Close();
1894 }
1895#ifdef ONE_RUN_FITS_ONLY
1896 if (fRunFitsFile != NULL)
1897 {
1898 delete fRunFitsFile;
1899 fRunFitsFile = NULL;
1900 (fNumSubAndFitsData.numOpenFits)--;
1901 }
1902#endif
1903#endif
1904 if (GetCurrentState() == kSM_Logging)
1905 NotifyOpenedFile("", 0, fOpenedRunFiles);
1906 if (GetCurrentState() == kSM_Logging ||
1907 GetCurrentState() == kSM_WaitingRun ||
1908 GetCurrentState() == kSM_NightlyOpen)
1909 {
1910 NotifyOpenedFile("", 0, fOpenedNightlyFiles);
1911 if (fNumSubAndFitsIsOn)
1912 fNumSubAndFits->updateService();
1913 }
1914 return kSM_Ready;
1915}
1916// --------------------------------------------------------------------------
1917//
1918//! Implements the transition towards kSM_WaitingRun
1919//! Does nothing really.
1920//! @returns
1921//! kSM_WaitingRun
1922int DataLogger::NightlyToWaitRunPlease()
1923{
1924 if (fDebugIsOn)
1925 {
1926 Debug("Going to Wait Run Number state...");
1927 }
1928 return kSM_WaitingRun;
1929}
1930
1931void DataLogger::setBlackWhiteList(const std::string& black, bool isBlack)
1932{
1933 if (fDebugIsOn)
1934 {
1935 if (isBlack)
1936 Debug("Setting BLACK list: " + black);
1937 else
1938 Debug("Setting WHITE list: " + black);
1939 }
1940 fGreyList.clear();
1941 stringstream stream(black);
1942
1943 string buffer;
1944 while (getline(stream, buffer, '|')) {
1945 fGreyList.insert(buffer);
1946 }
1947 fIsBlackList = isBlack;
1948}
1949
1950// --------------------------------------------------------------------------
1951
1952int RunDim(Configuration &conf)
1953{
1954 WindowLog wout;
1955
1956 //log.SetWindow(stdscr);
1957 if (conf.Has("log"))
1958 if (!wout.OpenLogFile(conf.Get<std::string>("log")))
1959 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
1960
1961 // Start io_service.Run to use the StateMachineImp::Run() loop
1962 // Start io_service.run to only use the commandHandler command detaching
1963 DataLogger logger(wout);
1964 logger.Run(true);
1965
1966 return 0;
1967}
1968
1969void RunThread(DataLogger* logger)
1970{
1971 // This is necessary so that the StateMachine Thread can signal the
1972 // Readline thread to exit
1973 logger->Run(true);
1974 Readline::Stop();
1975}
1976
1977template<class T>
1978int RunShell(Configuration &conf)
1979{
1980 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1981
1982 WindowLog &win = shell.GetStreamIn();
1983 WindowLog &wout = shell.GetStreamOut();
1984
1985 if (conf.Has("log"))
1986 if (!wout.OpenLogFile(conf.Get<std::string>("log")))
1987 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
1988
1989 DataLogger logger(wout);
1990
1991 if (conf.Has("black-list"))
1992 { if (conf.Get<std::string>("black-list") != "")
1993 logger.setBlackWhiteList(conf.Get<std::string>("black-list"), true);
1994 else if (conf.Has("white-list"))
1995 {
1996 if (conf.Get<std::string>("white-list") != "")
1997 logger.setBlackWhiteList(conf.Get<std::string>("white-list"), false);
1998 }
1999 }
2000 shell.SetReceiver(logger);
2001
2002 boost::thread t(boost::bind(RunThread, &logger));
2003
2004 shell.Run(); // Run the shell
2005
2006 logger.Stop();
2007
2008 //Wait until the StateMachine has finished its thread
2009 //before returning and destroyinng the dim objects which might
2010 //still be in use.
2011 t.join();
2012
2013 return 0;
2014}
2015
2016/*
2017 Extract usage clause(s) [if any] for SYNOPSIS.
2018 Translators: "Usage" and "or" here are patterns (regular expressions) which
2019 are used to match the usage synopsis in program output. An example from cp
2020 (GNU coreutils) which contains both strings:
2021 Usage: cp [OPTION]... [-T] SOURCE DEST
2022 or: cp [OPTION]... SOURCE... DIRECTORY
2023 or: cp [OPTION]... -t DIRECTORY SOURCE...
2024 */
2025void PrintUsage()
2026{
2027 cout << "\n"
2028 "The data logger connects to all available Dim services and "
2029 "writes them to ascii and fits files.\n"
2030 "\n"
2031 "Usage: dataLogger [-c type] [OPTIONS]\n"
2032 " or: dataLogger [OPTIONS]\n"
2033 "\n"
2034 "Options:\n"
2035 "The following describes the available commandline options. "
2036 "For further details on how command line option are parsed "
2037 "and in which order which configuration sources are accessed "
2038 "please refer to the class reference of the Configuration class.";
2039 cout << endl;
2040
2041}
2042
2043void PrintHelp()
2044{
2045 cout << "\n"
2046 "The default is that the program is started without user interaction. "
2047 "All actions are supposed to arrive as DimCommands. Using the -c "
2048 "option, a local shell can be initialized. With h or help a short "
2049 "help message about the usuage can be brought to the screen."
2050 << endl;
2051}
2052
2053/*
2054 The first line of the --version information is assumed to be in one
2055 of the following formats:
2056
2057 <version>
2058 <program> <version>
2059 {GNU,Free} <program> <version>
2060 <program> ({GNU,Free} <package>) <version>
2061 <program> - {GNU,Free} <package> <version>
2062
2063 and separated from any copyright/author details by a blank line.
2064
2065 Handle multi-line bug reporting sections of the form:
2066
2067 Report <program> bugs to <addr>
2068 GNU <package> home page: <url>
2069 ...
2070*/
2071void PrintVersion(const char *name)
2072{
2073 cout <<
2074 name << " - "PACKAGE_STRING"\n"
2075 "\n"
2076 "Written by Thomas Bretz et al.\n"
2077 "\n"
2078 "Report bugs to <"PACKAGE_BUGREPORT">\n"
2079 "Home page: "PACKAGE_URL"\n"
2080 "\n"
2081 "Copyright (C) 2011 by the FACT Collaboration.\n"
2082 "This is free software; see the source for copying conditions.\n"
2083 << endl;
2084}
2085
2086
2087void SetupConfiguration(Configuration &conf)
2088{
2089 const string n = conf.GetName()+".log";
2090
2091 po::options_description config("Program options");
2092 config.add_options()
2093 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
2094 ("log,l", var<string>(n), "Write log-file")
2095 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
2096 ("black-list,b", var<string>(""), "Black-list of services")
2097 ("white-list,w", var<string>(""), "White-list of services")
2098 ;
2099
2100 conf.AddEnv("dns", "DIM_DNS_NODE");
2101
2102 conf.AddOptions(config);
2103}
2104
2105int main(int argc, const char* argv[])
2106{
2107 Configuration conf(argv[0]);
2108 conf.SetPrintUsage(PrintUsage);
2109 SetupConfiguration(conf);
2110
2111 po::variables_map vm;
2112 try
2113 {
2114 vm = conf.Parse(argc, argv);
2115 }
2116 catch (std::exception &e)
2117 {
2118#if BOOST_VERSION > 104000
2119 po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
2120 if (MO)
2121 cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
2122 else
2123#endif
2124 cout << "Error: " << e.what() << endl;
2125 cout << endl;
2126
2127 return -1;
2128 }
2129
2130 if (conf.HasPrint())
2131 return -1;
2132
2133 if (conf.HasVersion())
2134 {
2135 PrintVersion(argv[0]);
2136 return -1;
2137 }
2138
2139 if (conf.HasHelp())
2140 {
2141 PrintHelp();
2142 return -1;
2143 }
2144
2145 setenv("DIM_DNS_NODE", conf.Get<string>("dns").c_str(), 1);
2146
2147 try
2148 {
2149 // No console access at all
2150 if (!conf.Has("console"))
2151 return RunDim(conf);
2152
2153 // Console access w/ and w/o Dim
2154 if (conf.Get<int>("console")==0)
2155 return RunShell<LocalShell>(conf);
2156 else
2157 return RunShell<LocalConsole>(conf);
2158 }
2159 catch (std::exception& e)
2160 {
2161 cerr << "Exception: " << e.what() << endl;
2162 return -1;
2163 }
2164
2165 return 0;
2166}
Note: See TracBrowser for help on using the repository browser.