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

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