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

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