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

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