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

Last change on this file since 10691 was 10688, checked in by tbretz, 14 years ago
Renamed AddConfiguration and AddTransition to AddEvent
File size: 74.1 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 ///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 HAS_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 HAS_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 HAS_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 HAS_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 HAS_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 void Setup(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 HAS_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 HAS_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 HAS_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 = true;//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 HAS_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//
981void DataLogger::ReportPlease(DimInfo* I, SubscriptionType& sub)
982{
983 //should we log or report this info ? (i.e. is it a message ?)
984 bool isItaReport = ((strstr(I->getName(), "Message") == NULL) && (strstr(I->getName(), "MESSAGE") == NULL));
985 if (I->getFormat()[0] == 'C')
986 isItaReport = false;
987 //TODO add service exclusion
988
989 if (!fNightlyReportFile.is_open())
990 return;
991
992 //create the converter for that service
993 if (sub.fConv == NULL && isItaReport)
994 {
995 //trick the converter in case of 'C'. why do I do this ? well simple: the converter checks that the right number
996 //of bytes was written. because I skip 'C' with fits, the bytes will not be allocated, hence the "size copied ckeck"
997 //of the converter will fail, hence throwing an exception.
998 std::string fakeFormat(I->getFormat());
999 if (fakeFormat[fakeFormat.size()-1] == 'C')
1000 fakeFormat = fakeFormat.substr(0, fakeFormat.size()-1);
1001 sub.fConv = new Converter(Out(), I->getFormat());
1002 if (!sub.fConv)
1003 {
1004 std::stringstream str;
1005 str << "Couldn't properly parse the format... service " << sub.dimInfo->getName() << " ignored.";
1006 Error(str);
1007 return;
1008 }
1009 }
1010
1011 //construct the header
1012 std::stringstream header;
1013 Time cTime(I->getTimestamp(), I->getTimestampMillisecs()*1000);
1014 fQuality = I->getQuality();
1015 fMjD = cTime.Mjd();
1016
1017 if (isItaReport)
1018 {
1019 //write text header
1020 header << I->getName() << " " << fQuality << " ";
1021 header << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
1022 header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
1023 header << cTime.ms() << " " << I->getTimestamp() << " ";
1024
1025 std::string text;
1026 try
1027 {
1028 text = sub.fConv->GetString(I->getData(), I->getSize());
1029 }
1030 catch (const std::runtime_error &e)
1031 {
1032 Out() << kRed << e.what() << endl;
1033 std::stringstream str;
1034 str << "Could not properly parse the data for service " << sub.dimInfo->getName();
1035 str << " reason: " << e.what() << ". Entry ignored";
1036 Error(str);
1037 return;
1038 }
1039
1040 if (text.empty())
1041 {
1042 std::stringstream str;
1043 str << "Service " << sub.dimInfo->getName() << " sent an empty string";
1044 Info(str);
1045 return;
1046 }
1047 //replace bizarre characters by white space
1048 replace(text.begin(), text.end(), '\n', '\\');
1049 replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');
1050
1051 //write entry to Nightly report
1052 if (fNightlyReportFile.is_open())
1053 {
1054 if (fDebugIsOn)
1055 {
1056 stringstream str;
1057 str << "Writing: \"" << header.str() << text << "\" to Nightly report file";
1058 Debug(str.str());
1059 }
1060 fNightlyReportFile << header.str() << text << std::endl;
1061 //check if either eof, bailbit or batbit are set
1062 if (!fNightlyReportFile.good())
1063 {
1064 Error("An error occured while writing to the nightly report file. Closing it");
1065 if (fNightlyReportFile.is_open())
1066 fNightlyReportFile.close();
1067 }
1068 }
1069 //write entry to run-report
1070 if (fRunReportFile.is_open())
1071 {
1072 if (fDebugIsOn)
1073 {
1074 stringstream str;
1075 str << "Writing: \"" << header.str() << text << "\" to Run report file";
1076 Debug(str.str());
1077 }
1078 fRunReportFile << header.str() << text << std::endl;
1079 if (!fRunReportFile.good())
1080 {
1081 Error("An error occured while writing to the run report file. Closing it.");
1082 if (fRunReportFile.is_open())
1083 fRunReportFile.close();
1084 }
1085 }
1086 }
1087 else
1088 {//write entry to both Nightly and run logs
1089 std::string n = I->getName();
1090 std::stringstream msg;
1091 msg << n.substr(0, n.find_first_of('/')) << ": " << I->getString();
1092
1093 if (fNightlyLogFile.is_open())
1094 {
1095 if (fDebugIsOn)
1096 {
1097 stringstream str;
1098 str << "Writing: \"" << msg.str() << "\" to Nightly log file";
1099 Debug(str.str());
1100 }
1101 MessageImp nightlyMess(fNightlyLogFile);
1102 nightlyMess.Write(cTime, msg.str().c_str(), fQuality);
1103 if (!fNightlyLogFile.good())
1104 {
1105 Error("An error occured while writing to the nightly log file. Closing it.");
1106 if (fNightlyLogFile.is_open())
1107 fNightlyLogFile.close();
1108 }
1109 }
1110 if (fRunLogFile.is_open())
1111 {
1112 if (fDebugIsOn)
1113 {
1114 stringstream str;
1115 str << "Writing: \"" << msg.str() << "\" to Run log file";
1116 Debug(str.str());
1117 }
1118 MessageImp runMess(fRunLogFile);
1119 runMess.Write(cTime, msg.str().c_str(), fQuality);
1120 if (!fRunLogFile.good())
1121 {
1122 Error("An error occured while writing to the run log file. Closing it.");
1123 if (fRunLogFile.is_open())
1124 fRunLogFile.close();
1125 }
1126 }
1127 }
1128
1129#ifdef HAS_FITS
1130 if (isItaReport)
1131 {
1132 if (!sub.nightlyFile.IsOpen() || !sub.runFile.IsOpen())
1133 OpenFITSFilesPlease(sub);
1134 WriteToFITS(sub);
1135 }
1136#endif
1137
1138}
1139
1140// --------------------------------------------------------------------------
1141//
1142//! write messages to logs.
1143//! @param evt
1144//! the current event to log
1145//! @returns
1146//! the new state. Currently, always the current state
1147//!
1148//! @deprecated
1149//! I guess that this function should not be any longer
1150//
1151//TODO isn't that function not used any longer ? If so I guess that we should get rid of it...
1152//Otherwise re-write it properly with the MessageImp class
1153int DataLogger::LogMessagePlease(const Event& evt)
1154{
1155 if (!fNightlyLogFile.is_open())
1156 return GetCurrentState();
1157
1158 std::stringstream header;
1159 const Time& cTime = evt.GetTime();
1160 header << evt.GetName() << " " << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
1161 header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
1162 header << cTime.ms() << " ";
1163
1164 const Converter conv(Out(), evt.GetFormat());
1165 if (!conv)
1166 {
1167 Error("Couldn't properly parse the format... ignored.");
1168 return GetCurrentState();
1169 }
1170
1171 std::string text;
1172 try
1173 {
1174 text = conv.GetString(evt.GetData(), evt.GetSize());
1175 }
1176 catch (const std::runtime_error &e)
1177 {
1178 Out() << kRed << e.what() << endl;
1179 Error("Couldn't properly parse the data... ignored.");
1180 return GetCurrentState();
1181 }
1182
1183 if (text.empty())
1184 return GetCurrentState();
1185
1186 //replace bizarre characters by white space
1187 replace(text.begin(), text.end(), '\n', '\\');
1188 replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');
1189 if (fDebugIsOn)
1190 {
1191 stringstream str;
1192 str << "Logging: \"" << header << text << "\"";
1193 Debug(str.str());
1194 }
1195
1196 if (fNightlyLogFile.is_open())
1197 {
1198 fNightlyLogFile << header;
1199 if (!fNightlyLogFile.good())
1200 {
1201 Error("An error occured while writing to the run log file. Closing it.");
1202 if (fNightlyLogFile.is_open())
1203 fNightlyLogFile.close();
1204 }
1205 }
1206 if (fRunLogFile.is_open())
1207 {
1208 fRunLogFile << header;
1209 if (!fRunLogFile.good())
1210 {
1211 Error("An error occured while writing to the run log file. Closing it.");
1212 if (fRunLogFile.is_open())
1213 fRunLogFile.close();
1214 }
1215 }
1216 if (fNightlyLogFile.is_open())
1217 {
1218 fNightlyLogFile << text;
1219 if (!fNightlyLogFile.good())
1220 {
1221 Error("An error occured while writing to the run log file. Closing it.");
1222 if (fNightlyLogFile.is_open())
1223 fNightlyLogFile.close();
1224 }
1225 }
1226 if (fRunLogFile.is_open())
1227 {
1228 fRunLogFile << text;
1229 if (!fRunLogFile.good())
1230 {
1231 Error("An error occured while writing to the run log file. Closing it.");
1232 if (fRunLogFile.is_open())
1233 fRunLogFile.close();
1234 }
1235 }
1236 return GetCurrentState();
1237}
1238// --------------------------------------------------------------------------
1239//
1240//! print the dataLogger's current state. invoked by the PRINT command
1241//! @param evt
1242//! the current event. Not used by the method
1243//! @returns
1244//! the new state. Which, in that case, is the current state
1245//!
1246int DataLogger::PrintStatePlease(const Event& )
1247{
1248 Message("-----------------------------------------");
1249 Message("------ DATA LOGGER CURRENT STATE --------");
1250 Message("-----------------------------------------");
1251 //print the path configuration
1252 std::string actualTargetDir;
1253 if (fNightlyFileName == ".")
1254 {
1255 char currentPath[FILENAME_MAX];
1256 if (getcwd(currentPath, sizeof(currentPath)))
1257 actualTargetDir = currentPath;
1258 }
1259 else
1260 actualTargetDir = fNightlyFileName;
1261 Message("Nightly Path: " + actualTargetDir);
1262 if (fRunFileName == ".")
1263 {
1264 char currentPath[FILENAME_MAX];
1265 if (getcwd(currentPath, sizeof(currentPath)))
1266 actualTargetDir = currentPath;
1267 }
1268 else
1269 actualTargetDir = fRunFileName;
1270 Message("Run Path: " + actualTargetDir);
1271 stringstream str;
1272 str << "Run Number: " << fRunFileName;
1273 Message(str.str());
1274 Message("----------- OPENED FILES ----------------");
1275 //print all the open files.
1276 if (fNightlyLogFile.is_open())
1277 Message("Nightly Log..........OPEN");
1278 else
1279 Message("Nightly log........CLOSED");
1280 if (fNightlyReportFile.is_open())
1281 Message("Nightly Report.......OPEN");
1282 else
1283 Message("Nightly Report.....CLOSED");
1284 if (fRunLogFile.is_open())
1285 Message("Run Log..............OPEN");
1286 else
1287 Message("Run Log............CLOSED");
1288 if (fRunReportFile.is_open())
1289 Message("Run Report...........OPEN");
1290 else
1291 Message("Run Report.........CLOSED");
1292 bool statWarning = false;
1293 DataLoggerStats statVar;
1294 calculateTotalSizeWritten(statVar, statWarning, false);/*
1295#ifdef HAS_FITS
1296 str.str("");
1297 str << "There are " << fNumSubAndFitsData.numOpenFits << " FITS files open:";
1298 Message(str.str());
1299 SubscriptionsListType::iterator x;
1300 std::map<std::string, SubscriptionType>::iterator y;
1301 bool runFileDone = false;
1302 for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
1303 {
1304 for (y=x->second.begin(); y != x->second.end(); y++)
1305 {
1306 if (y->second.runFile.IsOpen() && !runFileDone)
1307 {
1308 fFileSizesMap[y->second.runFile.fFileName] = y->second.runFile.GetWrittenSize();
1309 Message("-> "+y->second.runFile.fFileName);
1310#ifdef ONE_FITS_ONLY
1311 runFileDone = true;
1312#endif
1313 }
1314 if (y->second.nightlyFile.IsOpen())
1315 {
1316 fFileSizesMap[y->second.nightlyFile.fFileName] = y->second.nightlyFile.GetWrittenSize();
1317 Message("-> "+y->second.nightlyFile.fFileName);
1318 }
1319 }
1320 }
1321#else
1322 Message("FITS output disabled at compilation");
1323#endif
1324 struct stat st;
1325 DataLoggerStats statVar;
1326 //gather log and report files sizes on disk
1327 if (fNightlyLogFile.is_open())
1328 {
1329 stat(fFullNightlyLogFileName.c_str(), &st);
1330 fFileSizesMap[fFullNightlyLogFileName] = st.st_size;
1331 }
1332 if (fNightlyReportFile.is_open())
1333 {
1334 stat(fFullNightlyReportFileName.c_str(), &st);
1335 fFileSizesMap[fFullNightlyReportFileName] = st.st_size;
1336 }
1337 if (fRunLogFile.is_open())
1338 {
1339 stat(fFullRunLogFileName.c_str(), &st);
1340 fFileSizesMap[fFullRunLogFileName] = st.st_size;
1341 }
1342 if (fRunReportFile.is_open())
1343 {
1344 stat(fFullRunReportFileName.c_str(), &st);
1345 fFileSizesMap[fFullRunReportFileName] = st.st_size;
1346 }
1347 struct statvfs vfs;
1348 if (!statvfs(fNightlyFileName.c_str(), &vfs))
1349 {
1350 statVar.freeSpace = vfs.f_bsize*vfs.f_bavail;
1351 }
1352 else
1353 {
1354 str.str("");
1355 str << "Unable to retrieve stats for " << fNightlyFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1356 Error(str);;
1357 statVar.freeSpace = -1;
1358 }
1359
1360 //sum up all the file sizes. past and present
1361 statVar.sizeWritten = 0;
1362 for (std::map<std::string, long>::iterator it=fFileSizesMap.begin(); it != fFileSizesMap.end(); it++)
1363 statVar.sizeWritten += it->second;
1364 statVar.sizeWritten -= fBaseSizeNightly;
1365 statVar.sizeWritten -= fBaseSizeRun;
1366 */
1367 Message("---------------- STATS ------------------");
1368 str.str("");
1369 str << "Total Size written: " << statVar.sizeWritten << " bytes.";
1370 Message(str.str());
1371 str.str("");
1372 str << "Disk free space: " << statVar.freeSpace << " bytes.";
1373 Message(str.str());
1374 str.str("");
1375 str << "Statistics are updated every " << fStatsPeriodDuration << " seconds";
1376 if (fStatsPeriodDuration != 0)
1377 Message(str);
1378 else
1379 Message("Statistics updates are currently disabled");
1380 Message("----------- DIM SUBSCRIPTIONS -----------");
1381
1382 str.str("");
1383 str << "There are " << fNumSubAndFitsData.numSubscriptions << " active DIM subscriptions:";
1384 Message(str.str());
1385
1386 for (std::map<const std::string, std::map<std::string, SubscriptionType>>::const_iterator it=fServiceSubscriptions.begin(); it!= fServiceSubscriptions.end();it++)
1387 {
1388 Message("Server "+it->first);
1389 for (std::map<std::string, SubscriptionType>::const_iterator it2=it->second.begin(); it2!=it->second.end(); it2++)
1390 Message("-> "+it2->first);
1391 }
1392 if (fIsBlackList)
1393 Message("------------- BLOCK LIST ----------------");
1394 else
1395 if (fGreyList.size() != 0)
1396 Message("----------- ALLOW LIST ------------------");
1397 for (set<string>::iterator it=fGreyList.begin(); it != fGreyList.end(); it++)
1398 Message(*it);
1399 return GetCurrentState();
1400}
1401
1402// --------------------------------------------------------------------------
1403//
1404//! turn debug mode on and off
1405//! @param evt
1406//! the current event. contains the instruction string: On, Off, on, off, ON, OFF, 0 or 1
1407//! @returns
1408//! the new state. Which, in that case, is the current state
1409//!
1410int DataLogger::SetDebugOnOff(const Event& evt)
1411{
1412 bool backupDebug = fDebugIsOn;
1413 fDebugIsOn = evt.GetBool();
1414 if (fDebugIsOn == backupDebug)
1415 Warn("Warning: debug mode was already in the requested state");
1416 else
1417 {
1418 stringstream str;
1419 str << "Debug mode is now " << fDebugIsOn;
1420 Message(str.str());
1421 }
1422 return GetCurrentState();
1423}
1424// --------------------------------------------------------------------------
1425//
1426//! set the statistics update period duration. 0 disables the statistics
1427//! @param evt
1428//! the current event. contains the new duration.
1429//! @returns
1430//! the new state. Which, in that case, is the current state
1431//!
1432int DataLogger::SetStatsPeriod(const Event& evt)
1433{
1434 float backupDuration = fStatsPeriodDuration;
1435 fStatsPeriodDuration = evt.GetFloat();
1436 if (fStatsPeriodDuration < 0)
1437 {
1438 Error("Statistics period duration should be greater than zero. Discarding provided value.");
1439 fStatsPeriodDuration = backupDuration;
1440 return GetCurrentState();
1441 }
1442 if (fStatsPeriodDuration != fStatsPeriodDuration)
1443 {
1444 Error("Provided duration does not appear to be a valid float. discarding it.");
1445 fStatsPeriodDuration = backupDuration;
1446 return GetCurrentState();
1447 }
1448 if (backupDuration == fStatsPeriodDuration)
1449 Warn("Warning: statistics period was not modified: supplied value already in use");
1450 else
1451 {
1452 if (fStatsPeriodDuration == 0.0f)
1453 Message("Statistics are now OFF");
1454 else
1455 {
1456 stringstream str;
1457 str << "Statistics period is now " << fStatsPeriodDuration << " seconds";
1458 Message(str.str());
1459 }
1460 }
1461 return GetCurrentState();
1462}
1463// --------------------------------------------------------------------------
1464//
1465//! set the opened files service on or off.
1466//! @param evt
1467//! the current event. contains the instruction string. similar to setdebugonoff
1468//! @returns
1469//! the new state. Which, in that case, is the current state
1470//!
1471int DataLogger::SetOpenedFilesOnOff(const Event& evt)
1472{
1473 bool backupOpened = fOpenedFilesIsOn;
1474 fOpenedFilesIsOn = evt.GetBool();
1475 if (fOpenedFilesIsOn == backupOpened)
1476 Warn("Warning: opened files service mode was already in the requested state");
1477 else
1478 {
1479 stringstream str;
1480 str << "Opened files service mode is now " << fOpenedFilesIsOn;
1481 Message(str.str());
1482 }
1483 return GetCurrentState();
1484
1485}
1486// --------------------------------------------------------------------------
1487//
1488//! set the number of subscriptions and opened fits on and off
1489//! @param evt
1490//! the current event. contains the instruction string. similar to setdebugonoff
1491//! @returns
1492//! the new state. Which, in that case, is the current state
1493//!
1494int DataLogger::SetNumSubsAndFitsOnOff(const Event& evt)
1495{
1496 bool backupSubs = fNumSubAndFitsIsOn;
1497 fNumSubAndFitsIsOn = evt.GetBool();
1498 if (fNumSubAndFitsIsOn == backupSubs)
1499 Warn("Warning: Number of subscriptions service mode was already in the requested state");
1500 else
1501 {
1502 stringstream str;
1503 str << "Number of subscriptions service mode is now " << fNumSubAndFitsIsOn;
1504 Message(str.str());
1505 }
1506 return GetCurrentState();
1507}
1508// --------------------------------------------------------------------------
1509//
1510//! Sets the path to use for the Nightly log file.
1511//! @param evt
1512//! the event transporting the path
1513//! @returns
1514//! currently only the current state.
1515//
1516int DataLogger::ConfigureNightlyFileName(const Event& evt)
1517{
1518 if (evt.GetText() != NULL)
1519 {
1520 fNightlyFileName = std::string(evt.GetText());
1521 Message("New Nightly folder specified: " + fNightlyFileName);
1522 }
1523 else
1524 Error("Empty Nightly folder given. Please specify a valid path.");
1525
1526 return GetCurrentState();
1527}
1528// --------------------------------------------------------------------------
1529//
1530//! Sets the path to use for the run log file.
1531//! @param evt
1532//! the event transporting the path
1533//! @returns
1534//! currently only the current state
1535int DataLogger::ConfigureRunFileName(const Event& evt)
1536{
1537 if (evt.GetText() != NULL)
1538 {
1539 fRunFileName = std::string(evt.GetText());
1540 Message("New Run folder specified: " + fRunFileName);
1541 }
1542 else
1543 Error("Empty Nightly folder given. Please specify a valid path");
1544
1545 return GetCurrentState();
1546}
1547// --------------------------------------------------------------------------
1548//
1549//! Sets the run number.
1550//! @param evt
1551//! the event transporting the run number
1552//! @returns
1553//! currently only the current state
1554//TODO remove this function as the run numbers will be distributed through a dedicated service
1555int DataLogger::ConfigureRunNumber(const Event& evt)
1556{
1557 fRunNumber = evt.GetInt();
1558 std::stringstream str;
1559 str << "The new run number is: " << fRunNumber;
1560 Message(str.str());
1561 return GetCurrentState();
1562}
1563// --------------------------------------------------------------------------
1564//
1565//! Notifies the DIM service that a particular file was opened
1566//! @ param name the base name of the opened file, i.e. without path nor extension.
1567//! WARNING: use string instead of string& because I pass values that do not convert to string&.
1568//! this is not a problem though because file are not opened so often.
1569//! @ param type the type of the opened file. 0 = none open, 1 = log, 2 = text, 4 = fits
1570inline void DataLogger::NotifyOpenedFile(std::string name, int type, DimDescribedService* service)
1571{
1572 if (fOpenedFilesIsOn)
1573 {
1574 if (fDebugIsOn)
1575 {
1576 stringstream str;
1577 str << "Updating files service " << service->getName() << "with code: " << type << " and file: " << name;
1578 Debug(str.str());
1579 str.str("");
1580 str << "Num subs: " << fNumSubAndFitsData.numSubscriptions << " Num open FITS: " << fNumSubAndFitsData.numOpenFits;
1581 Debug(str.str());
1582 }
1583 OpenFileToDim fToDim;
1584 fToDim.code = type;
1585 memcpy(fToDim.fileName, name.c_str(), name.size()+1);
1586 service->setData(reinterpret_cast<void*>(&fToDim), name.size()+1+sizeof(int));
1587 service->setQuality(0);
1588 service->updateService();
1589 }
1590}
1591// --------------------------------------------------------------------------
1592//
1593//! Implements the Start transition.
1594//! Concatenates the given path for the Nightly file and the filename itself (based on the day),
1595//! and tries to open it.
1596//! @returns
1597//! kSM_NightlyOpen if success, kSM_BadNightlyConfig if failure
1598int DataLogger::StartPlease()
1599{
1600 if (fDebugIsOn)
1601 {
1602 Debug("Starting...");
1603 }
1604 Time time;
1605 std::stringstream sTime;
1606 sTime << time.Y() << "_" << time.M() << "_" << time.D();
1607
1608 fFullNightlyLogFileName = fNightlyFileName + '/' + sTime.str() + ".log";
1609 fNightlyLogFile.open(fFullNightlyLogFileName.c_str(), std::ios_base::out | std::ios_base::app);
1610 if (errno != 0)
1611 {
1612 std::stringstream str;
1613 str << "Unable to open Nightly Log " << fFullNightlyLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1614 Error(str);
1615 }
1616 fFullNightlyReportFileName = fNightlyFileName + '/' + sTime.str() + ".rep";
1617 fNightlyReportFile.open(fFullNightlyReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1618 if (errno != 0)
1619 {
1620 std::stringstream str;
1621 str << "Unable to open Nightly Report " << fFullNightlyReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1622 Error(str);
1623 }
1624
1625 if (!fNightlyLogFile.is_open() || !fNightlyReportFile.is_open())
1626 {
1627 //TODO send an error message
1628 return kSM_BadNightlyConfig;
1629 }
1630 //get the size of the newly opened file.
1631 struct stat st;
1632 stat(fFullNightlyLogFileName.c_str(), &st);
1633 fBaseSizeNightly = st.st_size;
1634 stat(fFullNightlyReportFileName.c_str(), &st);
1635 fBaseSizeNightly += st.st_size;
1636 fFileSizesMap.clear();
1637 fBaseSizeRun = 0;
1638 fPreviousSize = 0;
1639 //notify that files were opened
1640 std::string actualTargetDir;
1641 if (fNightlyFileName == ".")
1642 {
1643 char currentPath[FILENAME_MAX];
1644 if (!getcwd(currentPath, sizeof(currentPath)))
1645 {
1646 if (errno != 0)
1647 {
1648 std::stringstream str;
1649 str << "Unable retrieve current path" << ". Reason: " << strerror(errno) << " [" << errno << "]";
1650 Error(str);
1651 }
1652 }
1653 actualTargetDir = currentPath;
1654 }
1655 else
1656 {
1657 actualTargetDir = fNightlyFileName;
1658 }
1659 //notify that a new file has been opened.
1660 NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 3, fOpenedNightlyFiles);
1661
1662 return kSM_NightlyOpen;
1663}
1664
1665#ifdef HAS_FITS
1666// --------------------------------------------------------------------------
1667//
1668//! open if required a the FITS files corresponding to a given subscription
1669//! @param sub
1670//! the current DimInfo subscription being examined
1671void DataLogger::OpenFITSFilesPlease(SubscriptionType& sub)
1672{
1673 std::string serviceName(sub.dimInfo->getName());
1674 for (unsigned int i=0;i<serviceName.size(); i++)
1675 {
1676 if (serviceName[i] == '/')
1677 {
1678 serviceName[i] = '_';
1679 break;
1680 }
1681 }
1682 Time time;
1683 std::stringstream sTime;
1684 sTime << time.Y() << "_" << time.M() << "_" << time.D();
1685 //we open the NightlyFile anyway, otherwise this function shouldn't have been called.
1686 if (!sub.nightlyFile.IsOpen())
1687 {
1688 std::string partialName = fNightlyFileName + '/' + sTime.str() + '_' + serviceName + ".fits";
1689 AllocateFITSBuffers(sub);
1690 //get the size of the file we're about to open
1691 if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1692 {
1693 struct stat st;
1694 if (!stat(partialName.c_str(), &st))
1695 fBaseSizeNightly += st.st_size;
1696 fFileSizesMap[partialName] = 0;
1697 }
1698 sub.nightlyFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, Out());
1699 //notify the opening
1700 std::string actualTargetDir;
1701 if (fNightlyFileName == ".")
1702 {
1703 char currentPath[FILENAME_MAX];
1704 if (getcwd(currentPath, sizeof(currentPath)))
1705 actualTargetDir = currentPath;
1706 }
1707 else
1708 {
1709 actualTargetDir = fNightlyFileName;
1710 }
1711 NotifyOpenedFile(actualTargetDir + '/' + sTime.str(), 7, fOpenedNightlyFiles);
1712 if (fNumSubAndFitsIsOn)
1713 fNumSubAndFits->updateService();
1714 if (fDebugIsOn)
1715 {
1716 stringstream str;
1717 str << "Opened Nightly FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits;
1718 Debug(str.str());
1719 }
1720 }
1721 if (!sub.runFile.IsOpen() && (GetCurrentState() == kSM_Logging))
1722 {//buffer for the run file have already been allocated when doing the Nightly file
1723 std::stringstream sRun;
1724 sRun << fRunNumber;
1725#ifdef ONE_RUN_FITS_ONLY
1726 std::string partialName = fRunFileName + '/' + sRun.str() + ".fits";
1727 if (fRunFitsFile == NULL)
1728 {
1729#else
1730 std::string partialName = fRunFileName + '/' + sRun.str() + '_' + serviceName + ".fits";
1731#endif
1732 //get the size of the file we're about to open
1733 if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1734 {
1735 struct stat st;
1736 if (!stat(partialName.c_str(), &st))
1737 fBaseSizeRun += st.st_size;
1738 else
1739 fBaseSizeRun = 0;
1740 fFileSizesMap[partialName] = 0;
1741 }
1742#ifdef ONE_RUN_FITS_ONLY
1743 try
1744 {
1745 fRunFitsFile = new FITS(partialName, RWmode::Write);
1746 (fNumSubAndFitsData.numOpenFits)++;
1747 }
1748 catch (CCfits::FitsError e)
1749 {
1750 std::stringstream str;
1751 str << "Could not open FITS Run file " << partialName << " reason: " << e.message();
1752 Error(str);
1753 fRunFitsFile = NULL;
1754 }
1755#endif
1756 std::string actualTargetDir;
1757 if (fRunFileName == ".")
1758 {
1759 char currentPath[FILENAME_MAX];
1760 if (getcwd(currentPath, sizeof(currentPath)))
1761 actualTargetDir = currentPath;
1762 }
1763 else
1764 {
1765 actualTargetDir = fRunFileName;
1766 }
1767 NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 7, fOpenedRunFiles);// + '_' + serviceName, 4);
1768#ifdef ONE_RUN_FITS_ONLY
1769 }
1770 sub.runFile.Open(partialName, serviceName, fRunFitsFile, &fNumSubAndFitsData.numOpenFits, Out());
1771#else
1772 sub.runFile.Open(partialName, serviceName, NULL, &fNumSubAndFitsData.numOpenFits, Out());
1773#endif //one_run_fits_only
1774 if (fNumSubAndFitsIsOn)
1775 fNumSubAndFits->updateService();
1776 if (fDebugIsOn)
1777 {
1778 stringstream str;
1779 str << "Opened Run FITS: " << partialName << " and table: FACT-" << serviceName << ".current number of opened FITS: " << fNumSubAndFitsData.numOpenFits;
1780 Debug(str.str());
1781 }
1782 }
1783}
1784// --------------------------------------------------------------------------
1785//
1786void DataLogger::AllocateFITSBuffers(SubscriptionType& sub)
1787{
1788 int size = sub.dimInfo->getSize();
1789
1790 //Init the time columns of the file
1791 Description dateDesc(std::string("Time"), std::string("Modified Julian Date"), std::string("MjD"));
1792 sub.nightlyFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1793 sub.runFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1794
1795 Description QoSDesc("Qos", "Quality of service", "None");
1796 sub.nightlyFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1797 sub.runFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1798
1799 const Converter::FormatList flist = sub.fConv->GetList();
1800 // Compilation failed
1801 if (flist.empty() || flist.back().first.second!=0)
1802 {
1803 Error("Compilation of format string failed.");
1804 return;
1805 }
1806
1807 //we've got a nice structure describing the format of this service's messages.
1808 //Let's create the appropriate FITS columns
1809 std::vector<std::string> dataFormatsLocal;
1810 for (unsigned int i=0;i<flist.size()-1;i++)
1811 {
1812 std::stringstream dataQualifier;
1813
1814 dataQualifier << flist[i].second.first;
1815 switch (flist[i].first.first->name()[0])
1816 {//TODO handle all the data format cases
1817 case 'c':
1818 case 'C':
1819 dataQualifier.str("S");
1820 break;
1821 case 's':
1822 dataQualifier << "I";
1823 break;
1824 case 'i':
1825 case 'I':
1826 dataQualifier << "J";
1827 break;
1828 case 'l':
1829 case 'L':
1830 dataQualifier << "J";
1831 //TODO triple check that in FITS, long = int
1832 break;
1833 case 'f':
1834 case 'F':
1835 dataQualifier << "E";
1836 break;
1837 case 'd':
1838 case 'D':
1839 dataQualifier << "D";
1840 break;
1841 case 'x':
1842 case 'X':
1843 dataQualifier << "K";
1844 break;
1845 case 'S':
1846 //for strings, the number of elements I get is wrong. Correct it
1847 dataQualifier.str(""); //clear
1848 dataQualifier << size-1 << "A";
1849 size = size-1;
1850 break;
1851
1852 default:
1853 Fatal("THIS SHOULD NEVER BE REACHED. dataLogger.cc ln 1198.");
1854 };
1855 //we skip the variable length strings for now (in fits only)
1856 if (dataQualifier.str() != "S")
1857 dataFormatsLocal.push_back(dataQualifier.str());
1858 }
1859 sub.nightlyFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1860 sub.runFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1861}
1862// --------------------------------------------------------------------------
1863//
1864//! write a dimInfo data to its corresponding FITS files
1865//
1866void DataLogger::WriteToFITS(SubscriptionType& sub)
1867{
1868 //nightly File status (open or not) already checked
1869 if (sub.nightlyFile.IsOpen())
1870 {
1871 sub.nightlyFile.Write(sub.fConv);
1872 if (fDebugIsOn)
1873 {
1874 Debug("Writing to nightly FITS " + sub.nightlyFile.fFileName);
1875 }
1876 }
1877 if (sub.runFile.IsOpen())
1878 {
1879 sub.runFile.Write(sub.fConv);
1880 if (fDebugIsOn)
1881 {
1882 Debug("Writing to Run FITS " + sub.runFile.fFileName);
1883 }
1884 }
1885}
1886#endif //if has_fits
1887// --------------------------------------------------------------------------
1888//
1889//! Implements the StartRun transition.
1890//! Concatenates the given path for the run file and the filename itself (based on the run number),
1891//! and tries to open it.
1892//! @returns
1893//! kSM_Logging if success, kSM_BadRunConfig if failure.
1894int DataLogger::StartRunPlease()
1895{
1896 if (fDebugIsOn)
1897 {
1898 Debug("Starting Run Logging...");
1899 }
1900 //attempt to open run file with current parameters
1901// if (fRunNumber == -1)
1902// return kSM_BadRunConfig;
1903 std::stringstream sRun;
1904 sRun << fRunNumber;
1905 fFullRunLogFileName = fRunFileName + '/' + sRun.str() + ".log";
1906 fRunLogFile.open(fFullRunLogFileName.c_str(), std::ios_base::out | std::ios_base::app); //maybe should be app instead of ate
1907 if (errno != 0)
1908 {
1909 std::stringstream str;
1910 str << "Unable to open run Log " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1911 Error(str);
1912 }
1913 fFullRunReportFileName = fRunFileName + '/' + sRun.str() + ".rep";
1914 fRunReportFile.open(fFullRunReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1915 if (errno != 0)
1916 {
1917 std::stringstream str;
1918 str << "Unable to open run report " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1919 Error(str);
1920 }
1921
1922 if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1923 {
1924 //TODO send an error message
1925 return kSM_BadRunConfig;
1926 }
1927 //get the size of the newly opened file.
1928 struct stat st;
1929 fBaseSizeRun = 0;
1930 if (fFileSizesMap.find(fFullRunLogFileName) == fFileSizesMap.end())
1931 {
1932 stat(fFullRunLogFileName.c_str(), &st);
1933 if (errno != 0)
1934 {
1935 std::stringstream str;
1936 str << "Unable to stat " << fFullRunLogFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1937 Error(str);
1938 }
1939 else
1940 fBaseSizeRun += st.st_size;
1941 fFileSizesMap[fFullRunLogFileName] = 0;
1942 }
1943 if (fFileSizesMap.find(fFullRunReportFileName) == fFileSizesMap.end())
1944 {
1945 stat(fFullRunReportFileName.c_str(), &st);
1946 if (errno != 0)
1947 {
1948 std::stringstream str;
1949 str << "Unable to stat " << fFullRunReportFileName << ". Reason: " << strerror(errno) << " [" << errno << "]";
1950 Error(str);
1951 }
1952 else
1953 fBaseSizeRun += st.st_size;
1954 fFileSizesMap[fFullRunReportFileName] = 0;
1955 }
1956 std::string actualTargetDir;
1957 if (fRunFileName == ".")
1958 {
1959 char currentPath[FILENAME_MAX];
1960 if (!getcwd(currentPath, sizeof(currentPath)))
1961 {
1962 if (errno != 0)
1963 {
1964 std::stringstream str;
1965 str << "Unable to retrieve the current path" << ". Reason: " << strerror(errno) << " [" << errno << "]";
1966 Error(str);
1967 }
1968 }
1969 actualTargetDir = currentPath;
1970 }
1971 else
1972 {
1973 actualTargetDir = fRunFileName;
1974 }
1975 NotifyOpenedFile(actualTargetDir + '/' + sRun.str(), 3, fOpenedRunFiles);
1976
1977 return kSM_Logging;
1978}
1979// --------------------------------------------------------------------------
1980//
1981//! Implements the StopRun transition.
1982//! Attempts to close the run file.
1983//! @returns
1984//! kSM_WaitingRun if success, kSM_FatalError otherwise
1985int DataLogger::StopRunPlease()
1986{
1987 if (fDebugIsOn)
1988 {
1989 Debug("Stopping Run Logging...");
1990 }
1991 if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1992 return kSM_FatalError;
1993 if (fRunLogFile.is_open())
1994 fRunLogFile.close();
1995 if (fRunReportFile.is_open())
1996 fRunReportFile.close();
1997#ifdef HAS_FITS
1998 for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
1999 for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
2000 {
2001 if (j->second.runFile.IsOpen())
2002 j->second.runFile.Close();
2003 }
2004#ifdef ONE_RUN_FITS_ONLY
2005 if (fRunFitsFile != NULL)
2006 {
2007 delete fRunFitsFile;
2008 fRunFitsFile = NULL;
2009 (fNumSubAndFitsData.numOpenFits)--;
2010 }
2011#endif
2012#endif
2013 NotifyOpenedFile("", 0, fOpenedRunFiles);
2014 if (fNumSubAndFitsIsOn)
2015 fNumSubAndFits->updateService();
2016 return kSM_WaitingRun;
2017
2018}
2019// --------------------------------------------------------------------------
2020//
2021//! Implements the Stop and Reset transitions.
2022//! Attempts to close any openned file.
2023//! @returns
2024//! kSM_Ready
2025int DataLogger::GoToReadyPlease()
2026{
2027 if (fDebugIsOn)
2028 {
2029 Debug("Going to the Ready state...");
2030 }
2031 if (fNightlyLogFile.is_open())
2032 fNightlyLogFile.close();
2033 if (fNightlyReportFile.is_open())
2034 fNightlyReportFile.close();
2035
2036 if (fRunLogFile.is_open())
2037 fRunLogFile.close();
2038 if (fRunReportFile.is_open())
2039 fRunReportFile.close();
2040
2041#ifdef HAS_FITS
2042 for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
2043 for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
2044 {
2045 if (j->second.nightlyFile.IsOpen())
2046 j->second.nightlyFile.Close();
2047 if (j->second.runFile.IsOpen())
2048 j->second.runFile.Close();
2049 }
2050#ifdef ONE_RUN_FITS_ONLY
2051 if (fRunFitsFile != NULL)
2052 {
2053 delete fRunFitsFile;
2054 fRunFitsFile = NULL;
2055 (fNumSubAndFitsData.numOpenFits)--;
2056 }
2057#endif
2058#endif
2059 if (GetCurrentState() == kSM_Logging)
2060 NotifyOpenedFile("", 0, fOpenedRunFiles);
2061 if (GetCurrentState() == kSM_Logging ||
2062 GetCurrentState() == kSM_WaitingRun ||
2063 GetCurrentState() == kSM_NightlyOpen)
2064 {
2065 NotifyOpenedFile("", 0, fOpenedNightlyFiles);
2066 if (fNumSubAndFitsIsOn)
2067 fNumSubAndFits->updateService();
2068 }
2069 return kSM_Ready;
2070}
2071// --------------------------------------------------------------------------
2072//
2073//! Implements the transition towards kSM_WaitingRun
2074//! Does nothing really.
2075//! @returns
2076//! kSM_WaitingRun
2077int DataLogger::NightlyToWaitRunPlease()
2078{
2079 if (fDebugIsOn)
2080 {
2081 Debug("Going to Wait Run Number state...");
2082 }
2083 return kSM_WaitingRun;
2084}
2085
2086void DataLogger::Setup(Configuration& conf)
2087{
2088 //Set the block or allow list
2089 fGreyList.clear();
2090 if (conf.Has("block"))
2091 {
2092 vector<string> vec = conf.Get<vector<string>>("block");
2093 if (vec.size() != 0)
2094 {
2095 fIsBlackList = true;
2096 if (fDebugIsOn)
2097 Debug("Setting BLOCK list:");
2098 }
2099 else if (conf.Has("allow"))
2100 {
2101 vec = conf.Get<vector<string>>("allow");
2102 if (vec.size() != 0)
2103 {
2104 fIsBlackList = false;
2105 if (fDebugIsOn)
2106 Debug("Setting ALLOW list:");
2107 }
2108 }
2109 for (vector<string>::iterator it=vec.begin(); it != vec.end(); it++)
2110 {
2111 fGreyList.insert(*it);
2112 if (fDebugIsOn)
2113 Debug(" " + *it);
2114 }
2115 }
2116}
2117/*
2118void DataLogger::setBlackWhiteList(const std::string& black, bool isBlack)
2119{
2120 if (fDebugIsOn)
2121 {
2122 if (isBlack)
2123 Debug("Setting BLACK list: " + black);
2124 else
2125 Debug("Setting WHITE list: " + black);
2126 }
2127 fGreyList.clear();
2128 stringstream stream(black);
2129
2130 string buffer;
2131 while (getline(stream, buffer, '|')) {
2132 fGreyList.insert(buffer);
2133 }
2134 fIsBlackList = isBlack;
2135}
2136*/
2137// --------------------------------------------------------------------------
2138
2139int RunDim(Configuration &conf)
2140{
2141 WindowLog wout;
2142
2143 //log.SetWindow(stdscr);
2144 if (conf.Has("log"))
2145 if (!wout.OpenLogFile(conf.Get<std::string>("log")))
2146 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
2147
2148 // Start io_service.Run to use the StateMachineImp::Run() loop
2149 // Start io_service.run to only use the commandHandler command detaching
2150 DataLogger logger(wout);
2151 logger.Run(true);
2152
2153 return 0;
2154}
2155
2156void RunThread(DataLogger* logger)
2157{
2158 // This is necessary so that the StateMachine Thread can signal the
2159 // Readline thread to exit
2160 logger->Run(true);
2161 Readline::Stop();
2162}
2163
2164template<class T>
2165int RunShell(Configuration &conf)
2166{
2167 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
2168
2169 WindowLog &win = shell.GetStreamIn();
2170 WindowLog &wout = shell.GetStreamOut();
2171
2172 if (conf.Has("log"))
2173 if (!wout.OpenLogFile(conf.Get<std::string>("log")))
2174 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
2175
2176 DataLogger logger(wout);
2177
2178 logger.Setup(conf);
2179
2180 shell.SetReceiver(logger);
2181
2182 boost::thread t(boost::bind(RunThread, &logger));
2183
2184 shell.Run(); // Run the shell
2185
2186 logger.Stop();
2187
2188 //Wait until the StateMachine has finished its thread
2189 //before returning and destroyinng the dim objects which might
2190 //still be in use.
2191 t.join();
2192
2193 return 0;
2194}
2195
2196/*
2197 Extract usage clause(s) [if any] for SYNOPSIS.
2198 Translators: "Usage" and "or" here are patterns (regular expressions) which
2199 are used to match the usage synopsis in program output. An example from cp
2200 (GNU coreutils) which contains both strings:
2201 Usage: cp [OPTION]... [-T] SOURCE DEST
2202 or: cp [OPTION]... SOURCE... DIRECTORY
2203 or: cp [OPTION]... -t DIRECTORY SOURCE...
2204 */
2205void PrintUsage()
2206{
2207 cout << "\n"
2208 "The data logger connects to all available Dim services and "
2209 "writes them to ascii and fits files.\n"
2210 "\n"
2211 "The default is that the program is started without user interaction. "
2212 "All actions are supposed to arrive as DimCommands. Using the -c "
2213 "option, a local shell can be initialized. With h or help a short "
2214 "help message about the usage can be brought to the screen.\n"
2215 "\n"
2216 "Usage: dataLogger [-c type] [OPTIONS]\n"
2217 " or: dataLogger [OPTIONS]\n";
2218 cout << endl;
2219
2220}
2221
2222void PrintHelp()
2223{
2224 /* Additional help text which is printed after the configuration
2225 options goes here */
2226 cout <<
2227 "\n"
2228 "The block option has priority over the allow, "
2229 "i.e. if both are present, only the block list is kept. "
2230 "If only a server name or service without its server prefix is given "
2231 "then all the services of that server, or all the services that "
2232 "correspond to the given suffix are ignored or considered.\n"
2233 "\n"
2234 "For example, block=DIS_DNS will skip all the services offered by "
2235 "the DIS_DNS server, while block=SERVICE_LIST will skip all the "
2236 "SERVICE_LIST services offered by any server.\n"
2237 "\n"
2238 "The commands offered by the dataLoger are the following: \n";
2239 cout << setw(20) << DataLogger::fConfigDay << " : specify the path where to put the nightly files\n";
2240 cout << setw(20) << DataLogger::fConfigRun << " : specify the path where to put the run files\n";
2241 cout << setw(20) << DataLogger::fConfigRunNumber << " : specify the run number\n";
2242 cout << setw(20) << DataLogger::fConfigLog << " : log a particular message\n";
2243 cout << setw(20) << DataLogger::fTransStart << " : start the nightly logging\n";
2244 cout << setw(20) << DataLogger::fTransStop << " : stop the nightly logging\n";
2245 cout << setw(20) << DataLogger::fTransStartRun << " : start the run logging\n";
2246 cout << setw(20) << DataLogger::fTransStopRun << " : stop the run logging\n";
2247 cout << setw(20) << DataLogger::fTransReset << " : stop any logging and/or recover from an error state\n";
2248 cout << setw(20) << DataLogger::fTransWait << " : go to the wait for run number state\n";
2249 cout << setw(20) << DataLogger::fPrintCommand << " : print the current state of the logger to the shell\n";
2250 cout << setw(20) << DataLogger::fDebugOnOff << " : turn on or off the debug mode\n";
2251 cout << setw(20) << DataLogger::fStatsPeriod << " : set the periodicity of the statistics. 0 disable them\n";
2252 cout << endl;
2253}
2254
2255void SetupConfiguration(Configuration &conf)
2256{
2257 const string n = conf.GetName()+".log";
2258
2259 po::options_description config("Program options");
2260 config.add_options()
2261 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
2262 ("log,l", var<string>(n), "Write log-file")
2263 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
2264 ("block,b", vars<string>(), "Black-list of services")
2265 ("allow,a", vars<string>(), "White-list of services")
2266 ;
2267
2268 conf.AddEnv("dns", "DIM_DNS_NODE");
2269
2270 conf.AddOptions(config);
2271}
2272
2273int main(int argc, const char* argv[])
2274{
2275 Configuration conf(argv[0]);
2276 conf.SetPrintUsage(PrintUsage);
2277 SetupConfiguration(conf);
2278
2279 po::variables_map vm;
2280 try
2281 {
2282 vm = conf.Parse(argc, argv);
2283 }
2284 catch (std::exception &e)
2285 {
2286#if BOOST_VERSION > 104000
2287 po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
2288 if (MO)
2289 cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
2290 else
2291#endif
2292 cout << "Error: " << e.what() << endl;
2293 cout << endl;
2294
2295 return -1;
2296 }
2297
2298 if (conf.HasPrint())
2299 return -1;
2300
2301 if (conf.HasVersion())
2302 {
2303 FACT::PrintVersion(argv[0]);
2304 return -1;
2305 }
2306
2307 if (conf.HasHelp())
2308 {
2309 PrintHelp();
2310 return -1;
2311 }
2312
2313 Dim::Setup(conf.Get<string>("dns"));
2314
2315 try
2316 {
2317 // No console access at all
2318 if (!conf.Has("console"))
2319 return RunDim(conf);
2320
2321 // Console access w/ and w/o Dim
2322 if (conf.Get<int>("console")==0)
2323 return RunShell<LocalShell>(conf);
2324 else
2325 return RunShell<LocalConsole>(conf);
2326 }
2327 catch (std::exception& e)
2328 {
2329 cerr << "Exception: " << e.what() << endl;
2330 return -1;
2331 }
2332
2333 return 0;
2334}
Note: See TracBrowser for help on using the repository browser.