1 /*
2  *  Open BEAGLE
3  *  Copyright (C) 2001-2007 by Christian Gagne and Marc Parizeau
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Contact:
20  *  Laboratoire de Vision et Systemes Numeriques
21  *  Departement de genie electrique et de genie informatique
22  *  Universite Laval, Quebec, Canada, G1K 7P4
23  *  http://vision.gel.ulaval.ca
24  *
25  */
26 
27 /*!
28  *  \file   beagle/src/LoggerXML.cpp
29  *  \brief  Implementation of class LoggerXML.
30  *  \author Christian Gagne
31  *  \author Marc Parizeau
32  *  $Revision: 1.16.2.2 $
33  *  $Date: 2007/09/10 18:24:12 $
34  */
35 
36 #include "beagle/Beagle.hpp"
37 
38 #include <cstdio>
39 #include <iomanip>
40 #include <fstream>
41 
42 using namespace Beagle;
43 
44 /*!
45  *  \brief Construct a new LoggerXML.
46  */
LoggerXML()47 LoggerXML::LoggerXML() :
48   mActualFileName(""),
49   mStreamerFile(NULL),
50   mLogOutStream(NULL),
51   mStreamerConsole(NULL),
52   mTerminated(false)
53 { }
54 
55 
56 /*!
57  *  \brief Copy construct a LoggerXML is undefined.
58  */
LoggerXML(const LoggerXML & inLoggerXML)59 LoggerXML::LoggerXML(const LoggerXML& inLoggerXML) :
60   Logger()
61 {
62   Beagle_StackTraceBeginM();
63   throw Beagle_UndefinedMethodInternalExceptionM("LoggerXML(const LoggerXML&)", "LoggerXML", getName());
64   Beagle_StackTraceEndM("LoggerXML::LoggerXML(const LoggerXML& inLoggerXML)");
65 }
66 
67 
68 /*!
69  *  \brief Destruct a LoggerXML.
70  */
~LoggerXML()71 LoggerXML::~LoggerXML()
72 {
73   Beagle_StackTraceBeginM();
74   terminate();
75   Beagle_StackTraceEndM("LoggerXML::~LoggerXML()");
76 }
77 
78 
79 /*!
80  *  \brief Copy a LoggerXML is undefined.
81  */
operator =(const LoggerXML & inLoggerXML)82 LoggerXML& LoggerXML::operator=(const LoggerXML& inLoggerXML)
83 {
84   Beagle_StackTraceBeginM();
85   throw Beagle_UndefinedMethodInternalExceptionM("operator=","LoggerXML",getName());
86   Beagle_StackTraceEndM("LoggerXML& LoggerXML::operator=(const LoggerXML& inLoggerXML)");
87 }
88 
89 
90 /*!
91  *  \brief Initialize logger by registering its parameters.
92  *  \param ioSystem Reference to the system to use for initialization.
93  */
initialize(System & ioSystem)94 void LoggerXML::initialize(System& ioSystem)
95 {
96   Beagle_StackTraceBeginM();
97   Logger::initialize(ioSystem);
98 
99   if(ioSystem.getRegister().isRegistered("lg.console.level")) {
100     mLogConsoleLevel = castHandleT<UInt>(ioSystem.getRegister().getEntry("lg.console.level"));
101   } else {
102     mLogConsoleLevel = new UInt(eStats);
103     string lLongDescrip("Log level used for console output generation. ");
104     lLongDescrip += "Log levels available are: (0) no log, (1) basic logs, (2) stats, ";
105     lLongDescrip += "(3) general informations, (4) details on operations, ";
106     lLongDescrip += "(5) trace of the algorithms, (6) verbose, ";
107     lLongDescrip += "(7) debug (enabled only in full debug mode).";
108     Register::Description lDescription(
109       "Console log level",
110       "UInt",
111       "2",
112       lLongDescrip
113     );
114     ioSystem.getRegister().addEntry("lg.console.level", mLogConsoleLevel, lDescription);
115   }
116 
117   if(ioSystem.getRegister().isRegistered("lg.file.level")) {
118     mLogFileLevel = castHandleT<UInt>(ioSystem.getRegister().getEntry("lg.file.level"));
119   } else {
120     mLogFileLevel = new UInt(eInfo);
121     string lLongDescrip("Log level used for file output generation. ");
122     lLongDescrip += "Log levels available are: (0) no log, (1) basic logs, (2) stats, ";
123     lLongDescrip += "(3) general informations, (4) details on operations, ";
124     lLongDescrip += "(5) trace of the algorithms, (6) verbose, ";
125     lLongDescrip += "(7) debug (enabled only in full debug mode).";
126     Register::Description lDescription(
127       "File log level",
128       "UInt",
129       "3",
130       lLongDescrip
131     );
132     ioSystem.getRegister().addEntry("lg.file.level", mLogFileLevel, lDescription);
133   }
134 
135   if(ioSystem.getRegister().isRegistered("lg.file.name")) {
136     mLogFileName = castHandleT<String>(ioSystem.getRegister().getEntry("lg.file.name"));
137   } else {
138     mLogFileName = new String("beagle.log");
139     string lLongDescrip("Filename in which messages are outputed. ");
140     lLongDescrip += "An empty string file name means no output is done to a file.";
141     Register::Description lDescription(
142       "Log filename",
143       "String",
144       "\"beagle.log\"",
145       lLongDescrip
146     );
147     ioSystem.getRegister().addEntry("lg.file.name", mLogFileName, lDescription);
148   }
149 
150   if(ioSystem.getRegister().isRegistered("lg.show.level")) {
151     mShowLevel = castHandleT<Bool>(ioSystem.getRegister().getEntry("lg.show.level"));
152   } else {
153     mShowLevel = new Bool(false);
154     string lLongDescrip("Flag whether logging level in outputed in the logs.");
155     Register::Description lDescription(
156       "Show level in logs",
157       "Bool",
158       "0",
159       lLongDescrip
160     );
161     ioSystem.getRegister().addEntry("lg.show.level", mShowLevel, lDescription);
162   }
163 
164   if(ioSystem.getRegister().isRegistered("lg.show.type")) {
165     mShowType = castHandleT<Bool>(ioSystem.getRegister().getEntry("lg.show.type"));
166   } else {
167     mShowType = new Bool(false);
168     string lLongDescrip("Flag whether message type is outputed in the logs.");
169     Register::Description lDescription(
170       "Show message type in logs",
171       "Bool",
172       "0",
173       lLongDescrip
174     );
175     ioSystem.getRegister().addEntry("lg.show.type", mShowType, lDescription);
176   }
177 
178   if(ioSystem.getRegister().isRegistered("lg.show.class")) {
179     mShowClass = castHandleT<Bool>(ioSystem.getRegister().getEntry("lg.show.class"));
180   } else {
181     mShowClass = new Bool(false);
182     string lLongDescrip("Flag whether class name is outputed in the logs.");
183     Register::Description lDescription(
184       "Show class name in logs",
185       "Bool",
186       "0",
187       lLongDescrip
188     );
189     ioSystem.getRegister().addEntry("lg.show.class", mShowClass, lDescription);
190   }
191   Beagle_StackTraceEndM("void LoggerXML::initialize(System& ioSystem)");
192 }
193 
194 
195 /*!
196  *  \brief Write message to the output device.
197  *  \param inLevel Log level of the message
198  *  \param inType Type of the message to log.
199  *  \param inClass Class associated to the message.
200  *  \param inMessage Message to log in the output device.
201  */
outputMessage(unsigned int inLevel,Beagle::string inType,Beagle::string inClass,Beagle::string inMessage)202 void LoggerXML::outputMessage(unsigned int inLevel,
203                               Beagle::string inType,
204                               Beagle::string inClass,
205                               Beagle::string inMessage)
206 {
207   Beagle_StackTraceBeginM();
208   if(mTerminated)
209     throw Beagle_RunTimeExceptionM("Can't log in a terminated XML logger!");
210 
211   // Log file output
212   if(mLogFileLevel->getWrappedValue()>=inLevel) {
213     if(mActualFileName != mLogFileName->getWrappedValue()) {
214       mActualFileName = mLogFileName->getWrappedValue();
215       if(mStreamerFile != NULL) {
216         mStreamerFile->closeTag();
217         mStreamerFile->closeTag();
218         *mLogOutStream << std::endl;
219         delete mStreamerFile;
220         mStreamerFile = NULL;
221       }
222       if(mLogOutStream) {
223         mLogOutStream->close();
224         delete mLogOutStream;
225         mLogOutStream = NULL;
226       }
227       if(mLogFileName->getWrappedValue().empty() == false) {
228         string lFilenameBak = mLogFileName->getWrappedValue() + "~";
229         std::remove(lFilenameBak.c_str());
230         std::rename(mLogFileName->getWrappedValue().c_str(), lFilenameBak.c_str());
231         mLogOutStream = new std::ofstream(mLogFileName->getWrappedValue().c_str());
232         mStreamerFile = new PACC::XML::Streamer(*mLogOutStream);
233         mStreamerFile->insertHeader();
234         mStreamerFile->openTag("Beagle");
235         mStreamerFile->insertAttribute("version", BEAGLE_VERSION);
236         mStreamerFile->openTag("Logger");
237       }
238     }
239     if(mStreamerFile != NULL) {
240       mStreamerFile->openTag("Log", false);
241       if(mShowLevel->getWrappedValue()) mStreamerFile->insertAttribute("level", uint2str(inLevel));
242       if(mShowType->getWrappedValue())  mStreamerFile->insertAttribute("type",  inType);
243       if(mShowClass->getWrappedValue()) mStreamerFile->insertAttribute("class", inClass);
244       mStreamerFile->insertStringContent(inMessage.c_str());
245       mStreamerFile->closeTag();
246     }
247   }
248 
249   // Log console output
250   if(mLogConsoleLevel->getWrappedValue()>=inLevel) {
251     if(mStreamerConsole == NULL) {
252       mStreamerConsole = new PACC::XML::Streamer(std::cout);
253       mStreamerConsole->insertHeader();
254       mStreamerConsole->openTag("Beagle");
255       mStreamerConsole->insertAttribute("version", BEAGLE_VERSION);
256       mStreamerConsole->openTag("Logger");
257     }
258     mStreamerConsole->openTag("Log", false);
259     if(mShowLevel->getWrappedValue()) mStreamerConsole->insertAttribute("level", uint2str(inLevel));
260     if(mShowType->getWrappedValue())  mStreamerConsole->insertAttribute("type",  inType);
261     if(mShowClass->getWrappedValue()) mStreamerConsole->insertAttribute("class", inClass);
262     mStreamerConsole->insertStringContent(inMessage.c_str());
263     mStreamerConsole->closeTag();
264   }
265   Beagle_StackTraceEndM("void LoggerXML::outputMessage(unsigned int inLevel, string inType, string inClass, string inMessage)");
266 }
267 
268 
269 /*!
270  *  \brief Write Beagle object to the output device.
271  *  \param inLevel Log level of the message
272  *  \param inType Type of the message to log.
273  *  \param inClass Class associated to the message.
274  *  \param inObject Beagle object to log in the output device.
275  */
outputObject(unsigned int inLevel,Beagle::string inType,Beagle::string inClass,const Object & inObject)276 void LoggerXML::outputObject(unsigned int inLevel,
277                              Beagle::string inType,
278                              Beagle::string inClass,
279                              const Object& inObject)
280 {
281   Beagle_StackTraceBeginM();
282   if(mTerminated)
283     throw Beagle_RunTimeExceptionM("Can't log in a terminated XML logger!");
284 
285   // Log file output
286   if(mLogFileLevel->getWrappedValue()>=inLevel) {
287     if(mActualFileName != mLogFileName->getWrappedValue()) {
288       mActualFileName = mLogFileName->getWrappedValue();
289       if(mStreamerFile != NULL) {
290         mStreamerFile->closeTag();
291         mStreamerFile->closeTag();
292         *mLogOutStream << std::endl;
293         delete mStreamerFile;
294         mStreamerFile = NULL;
295       }
296       if(mLogOutStream) {
297         mLogOutStream->close();
298         delete mLogOutStream;
299         mLogOutStream = NULL;
300       }
301       if(mLogFileName->getWrappedValue().empty() == false) {
302         string lFilenameBak = mLogFileName->getWrappedValue() + "~";
303         std::remove(lFilenameBak.c_str());
304         std::rename(mLogFileName->getWrappedValue().c_str(), lFilenameBak.c_str());
305         mLogOutStream = new std::ofstream(mLogFileName->getWrappedValue().c_str());
306         mStreamerFile = new PACC::XML::Streamer(*mLogOutStream);
307         mStreamerFile->insertHeader();
308         mStreamerFile->openTag("Beagle");
309         mStreamerFile->insertAttribute("version", BEAGLE_VERSION);
310         mStreamerFile->openTag("Logger");
311       }
312     }
313     if(mStreamerFile != NULL) {
314       mStreamerFile->openTag("Log");
315       if(mShowLevel->getWrappedValue()) mStreamerFile->insertAttribute("level", uint2str(inLevel));
316       if(mShowType->getWrappedValue())  mStreamerFile->insertAttribute("type",  inType);
317       if(mShowClass->getWrappedValue()) mStreamerFile->insertAttribute("class", inClass);
318       inObject.write(*mStreamerFile);
319       mStreamerFile->closeTag();
320     }
321   }
322 
323   // Log console output
324   if(mLogConsoleLevel->getWrappedValue()>=inLevel) {
325     if(mStreamerConsole == NULL) {
326       mStreamerConsole = new PACC::XML::Streamer(std::cout);
327       mStreamerConsole->insertHeader();
328       mStreamerConsole->openTag("Beagle");
329       mStreamerConsole->insertAttribute("version", BEAGLE_VERSION);
330       mStreamerConsole->openTag("Logger");
331     }
332     mStreamerConsole->openTag("Log");
333     if(mShowLevel->getWrappedValue()) mStreamerConsole->insertAttribute("level", uint2str(inLevel));
334     if(mShowType->getWrappedValue())  mStreamerConsole->insertAttribute("type",  inType);
335     if(mShowClass->getWrappedValue()) mStreamerConsole->insertAttribute("class", inClass);
336     inObject.write(*mStreamerConsole);
337     mStreamerConsole->closeTag();
338   }
339   Beagle_StackTraceEndM("void LoggerXML::outputObject(unsigned int inLevel, string inType, string inClass, const Object& inObject)");
340 }
341 
342 
343 /*!
344  *  \brief Post-initialize logger.
345  */
postInit(System & ioSystem)346 void LoggerXML::postInit(System& ioSystem)
347 {
348   Beagle_StackTraceBeginM();
349   Logger::postInit(ioSystem);
350 
351   mInitialized = true;
352 
353   Beagle_LogBasicM(
354     (*this),
355     "logger", "Beagle::LoggerXML",
356     string("Open BEAGLE, version ")+BEAGLE_VERSION
357   );
358 
359   switch(mLogConsoleLevel->getWrappedValue()) {
360     case eNothing:
361     {
362       Beagle_LogBasicM(
363         (*this),
364         "logger", "Beagle::LoggerXML",
365         "Console logger initialized, using log level 0 (no message)"
366       );
367       break;
368     }
369     case eBasic:
370     {
371       Beagle_LogBasicM(
372         (*this),
373         "logger", "Beagle::LoggerXML",
374         "Console logger initialized, using log level 1 (essential informations)"
375       );
376       break;
377     }
378     case eStats:
379     {
380       Beagle_LogBasicM(
381         (*this),
382         "logger", "Beagle::LoggerXML",
383         "Console logger initialized, using log level 2 (evolution statistics)"
384       );
385       break;
386     }
387     case eInfo:
388     {
389       Beagle_LogBasicM(
390         (*this),
391         "logger", "Beagle::LoggerXML",
392         "Console logger initialized, using log level 3 (general informations)"
393       );
394       break;
395     }
396     case eDetailed:
397     {
398       Beagle_LogBasicM(
399         (*this),
400         "logger", "Beagle::LoggerXML",
401         "Console logger initialized, using log level 4 (details on operations)"
402       );
403       break;
404     }
405     case eTrace:
406     {
407       Beagle_LogBasicM(
408         (*this),
409         "logger", "Beagle::LoggerXML",
410         "Console logger initialized, using log level 5 (trace of the algorithms)"
411       );
412       break;
413     }
414     case eVerbose:
415     {
416       Beagle_LogBasicM(
417         (*this),
418         "logger", "Beagle::LoggerXML",
419         "Console logger initialized, using log level 6 (details on everything)"
420       );
421 #ifdef BEAGLE_NDEBUG
422       Beagle_LogBasicM(
423         (*this),
424         "logger", "Beagle::LoggerXML",
425         "Console log level 6 (verbose) is unused as optimization mode is enabled"
426       );
427 #endif // BEAGLE_NDEBUG
428       break;
429     }
430     case eDebug:
431     {
432       Beagle_LogBasicM(
433         (*this),
434         "logger", "Beagle::LoggerXML",
435         "Console logger initialized, using log level 7 (debug)"
436       );
437 #ifdef BEAGLE_NDEBUG
438       Beagle_LogBasicM(
439         (*this),
440         "logger", "Beagle::LoggerXML",
441         "Console log level 7 (debug) is unused as optimization mode is enabled"
442       );
443 #endif // BEAGLE_NDEBUG
444 #ifndef BEAGLE_FULL_DEBUG
445       Beagle_LogBasicM(
446         (*this),
447         "logger", "Beagle::LoggerXML",
448         "Console log level 7 (debug) is unused as full debug mode is disabled"
449       );
450 #endif // BEAGLE_FULL_DEBUG
451       break;
452     }
453     default:
454     {
455       Beagle_LogBasicM(
456         (*this),
457         "logger", "Beagle::LoggerXML",
458         string("Console logger initialized, using log level ")+
459         uint2str(mLogConsoleLevel->getWrappedValue())+
460         " (unused)"
461       );
462       break;
463     }
464   }
465 
466   if(mLogFileName->getWrappedValue().empty()) {
467     Beagle_LogBasicM(
468       (*this),
469       "logger", "Beagle::LoggerXML",
470       "File logging disabled"
471     );
472   }
473   else {
474     switch(mLogFileLevel->getWrappedValue()) {
475       case eNothing:
476       {
477         Beagle_LogBasicM(
478           (*this),
479           "logger", "Beagle::LoggerXML",
480           "File logger initialized, using log level 0 (no message)"
481         );
482         break;
483       }
484       case eBasic:
485       {
486         Beagle_LogBasicM(
487           (*this),
488           "logger", "Beagle::LoggerXML",
489           "File logger initialized, using log level 1 (essential informations)"
490         );
491         break;
492       }
493       case eStats:
494       {
495         Beagle_LogBasicM(
496           (*this),
497           "logger", "Beagle::LoggerXML",
498           "File logger initialized, using log level 2 (evolution statistics)"
499         );
500         break;
501       }
502       case eInfo:
503       {
504         Beagle_LogBasicM(
505           (*this),
506           "logger", "Beagle::LoggerXML",
507           "File logger initialized, using log level 3 (general informations)"
508         );
509         break;
510       }
511       case eDetailed:
512       {
513         Beagle_LogBasicM(
514           (*this),
515           "logger", "Beagle::LoggerXML",
516           "File logger initialized, using log level 4 (details on operations)"
517         );
518         break;
519       }
520       case eTrace:
521       {
522         Beagle_LogBasicM(
523           (*this),
524           "logger", "Beagle::LoggerXML",
525           "File logger initialized, using log level 5 (trace of the algorithms)"
526         );
527         break;
528       }
529       case eVerbose:
530       {
531         Beagle_LogBasicM(
532           (*this),
533           "logger", "Beagle::LoggerXML",
534           "File logger initialized, using log level 6 (details on everything)"
535         );
536   #ifdef BEAGLE_NDEBUG
537         Beagle_LogBasicM(
538           (*this),
539           "logger", "Beagle::LoggerXML",
540           "File log level 6 (verbose) is unused as optimization mode is enabled"
541         );
542   #endif // BEAGLE_NDEBUG
543         break;
544       }
545       case eDebug:
546       {
547         Beagle_LogBasicM(
548           (*this),
549           "logger", "Beagle::LoggerXML",
550           "File logger initialized, using log level 7 (debug)"
551         );
552   #ifdef BEAGLE_NDEBUG
553         Beagle_LogBasicM(
554           (*this),
555           "logger", "Beagle::LoggerXML",
556           "File log level 7 (debug) is unused as optimization mode is enabled"
557         );
558   #endif // BEAGLE_NDEBUG
559   #ifndef BEAGLE_FULL_DEBUG
560         Beagle_LogBasicM(
561           (*this),
562           "logger", "Beagle::LoggerXML",
563           "File log level 7 (debug) is unused as full debug mode is disabled"
564         );
565   #endif // BEAGLE_FULL_DEBUG
566         break;
567       }
568       default:
569       {
570         Beagle_LogBasicM(
571           (*this),
572           "logger", "Beagle::LoggerXML",
573           string("File logger initialized, using log level ")+
574           uint2str(mLogFileLevel->getWrappedValue())+
575           " (unused)"
576         );
577         break;
578       }
579     }
580 
581     Beagle_LogBasicM(
582       (*this),
583       "logger", "Beagle::LoggerXML",
584       string("Logging to file named \"")+mLogFileName->getWrappedValue()+string("\"")
585     );
586   }
587 
588   for(std::list< Message,BEAGLE_STLALLOCATOR<Message> >::const_iterator lIter = mBuffer.begin();
589       lIter != mBuffer.end(); ++lIter) {
590     outputMessage(lIter->mLogLevel, lIter->mType, lIter->mClass, lIter->mMessage);
591   }
592   mBuffer.clear();
593   Beagle_StackTraceEndM("void LoggerXML::postInit(System& ioSystem)");
594 }
595 
596 
597 
598 /*!
599  *  \brief Terminate XML logger operations.
600  */
terminate()601 void LoggerXML::terminate()
602 {
603   Beagle_StackTraceBeginM();
604   if(mTerminated == false) {
605     mTerminated = true;
606     if(mStreamerFile != NULL) {
607       mStreamerFile->closeTag();
608       mStreamerFile->closeTag();
609       *mLogOutStream << std::endl;
610       delete mStreamerFile;
611       mStreamerFile = NULL;
612     }
613     if(mStreamerConsole != NULL) {
614       mStreamerConsole->closeTag();
615       mStreamerConsole->closeTag();
616       std::cout << std::endl;
617       delete mStreamerConsole;
618       mStreamerConsole = NULL;
619     }
620     if(mLogOutStream) {
621       mLogOutStream->close();
622       delete mLogOutStream;
623       mLogOutStream = NULL;
624     }
625   }
626   Beagle_StackTraceEndM("void LoggerXML::terminate()");
627 }
628 
629