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

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