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

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