vrecko
virtual reality framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Logger.h
Go to the documentation of this file.
1 #ifndef LOGGER_H
2 #define LOGGER_H
3 
4 #include <vrecko/Export>
5 #include <vrecko/Timer.h>
7 #include <fstream>
8 #include <map>
9 #include <helpers/DynamicArray.h>
10 #include <string>
11 #include <vrecko/MTLock.h>
12 
13 #include <windows.h>
14 
15 namespace vrecko {
16 
17 class logger_streambuf;
18 
19 
20 // Flags for Logger::dwAllowedOutput etc.
21 #define LOGGER_OUTPUTTYPE_ERROR 0x00000001
22  // Error message
23 #define LOGGER_OUTPUTTYPE_WARNING 0x00000002
24  // Warning
25 #define LOGGER_OUTPUTTYPE_NOTICE 0x00000004
26  // Simple notice
27 #define LOGGER_OUTPUTTYPE_DEBUG 0x00000008
28  // Debug message - won't be shown in normal user setup
29 #define LOGGER_OUTPUTTYPE_DEBUGFILE 0x00000010
30  // Debug message outputted only into the log file
31 #define LOGGER_OUTPUTTYPE_DEBUGFLUSH 0x00000020
32  // Debug message that is processed immediately, even in non-main thread.
33  // Otherwise the message is handed over to the main thread and processed there.
34 #define LOGGER_OUTPUTTYPE_TIMINGSFILE 0x00000040
35  // Special constant to output times into the timings file (which is xml-based)
36 
37 #define LOGGER_OUTPUTTYPEMASK_ALL 0xFFFFFFFF
38 #define LOGGER_OUTPUTTYPEMASK_NONE 0x00000000
39 #define LOGGER_OUTPUTTYPEMASK_DEBUG LOGGER_OUTPUTTYPEMASK_ALL
40 #define LOGGER_OUTPUTTYPEMASK_USER (LOGGER_OUTPUTTYPE_ERROR | LOGGER_OUTPUTTYPE_WARNING | LOGGER_OUTPUTTYPE_NOTICE)
41 #define LOGGER_OUTPUTTYPEMASK_NORMAL LOGGER_OUTPUTTYPEMASK_USER
42 
43 #define LOGGER_OT_INTERNALMASK_SPECIALTYPES (LOGGER_OUTPUTTYPE_TIMINGSFILE)
44 #define LOGGER_OT_INTERNALMASK_NORMALTYPES (0xFFFFFFFF ^ LOGGER_OT_INTERNALMASK_SPECIALTYPES)
45 
46 
47 // Constants for Logger:dwOutputDest etc.
48 #define LOGGER_OUTPUTDEST_STDOUT 0x00000001 // text console
49 #define LOGGER_OUTPUTDEST_FILE 0x00000002 // log file
50 #define LOGGER_OUTPUTDEST_DEBUGSTRING 0x00000004 // i.e. using OutputDebugString() to print it on VisutalStudio console.
51 
52 #define LOGGER_OUTPUTDESTMASK_ALL 0xFFFFFFFF // all output destinations
53 #define LOGGER_OUTPUTDESTMASK_NONE 0x00000000
54 #define LOGGER_OUTPUTDESTMASK_NO_STDOUT (LOGGER_OUTPUTDESTMASK_ALL ^ LOGGER_OUTPUTDEST_STDOUT)
55 #define LOGGER_OUTPUTDESTMASK_NO_FILE (LOGGER_OUTPUTDESTMASK_ALL ^ LOGGER_OUTPUTDEST_FILE)
56 #define LOGGER_OUTPUTDESTMASK_NO_DEBUGSTRING (LOGGER_OUTPUTDESTMASK_ALL ^ LOGGER_OUTPUTDEST_DEBUGSTRING)
57 
58 
59 
60 
61 class VRECKO_EXPORT Logger {
62  friend class World;
63 public:
64  Logger();
65  ~Logger();
66 
67  bool init();
68  // The initialization must be done from the main thread, because Logger will remember its ID
69  // and notices from other threads will be postponed and processed in the main thread.
70 
71  void done();
72 
73  void update();
74  // Should be called sometimes (ex. once/twice per frame) to process any possible outstanding texts.
75 
76  void noticeLog(const char *notice = "", ...);
77  void vnoticeLog(const char *notice, va_list args);
78 // void noticeLog(int level, const char *notice = "", ...);
79 // void vnoticeLog(int level, const char *notice, va_list args);
80  void warningLog(const char *warning = "", ...);
81  void vwarningLog(const char *warning, va_list args);
82 // void warningLog(int level, const char *warning = "", ...);
83 // void vwarningLog(int level, const char *warning, va_list args);
84  void errorLog(const char *error = "", ...);
85  void verrorLog(const char *error, va_list args);
86 // void errorLog(int level, const char *error = "", ...);
87 // void verrorLog(int level, const char *error, va_list args);
88  void debugLog(const char *debugText = "", ...);
89  void vdebugLog(const char *debugText, va_list args);
90  // The (v)debugFileLog() functions only write info to the file
91  void debugFileLog(const char *debugText = "", ...);
92  void vdebugFileLog(const char *debugText, va_list args);
93 
94  void debugFlush(const char *debugText = "", ...);
95  void vdebugFlush(const char *debugText, va_list args);
96  // Causes the text to be outputted immediately, even in a non-main thread
97 
98  inline unsigned long getAllowedOutput() { return dwAllowedOutput; }
99  inline void setAllowedOutput(unsigned long dwNewOutput) { dwAllowedOutput = dwNewOutput; }
100  // [dwNewOutput] is a combination of LOGGER_OUTPUTTYPE_*.
101  // It is possible to use one of LOGGER_OUTPUTTYPEMASK_* to initialize one of the default behaviours.
102 
103  inline unsigned long getOutputDest() { return dwOutputDest; }
104  inline void setOutputDest(unsigned long dwNewOutputDest) { dwOutputDest = dwNewOutputDest; }
105  // [dwNewOutputDest] is a combination of LOGGER_OUTPUTDEST_*
106 
107  void startTiming(std::string sectionName);
108  void stopTiming(std::string sectionName, DWORD dwOutputType = LOGGER_OUTPUTTYPE_DEBUG);
109  // LOGGER_OUTPUTTYPE_TIMINGSFILE can be used to output the value into the xml-based
110  // timings file.
111 
112  void writeBMCounter(const char *pName, float fValue);
113  // Writes out a counter value to the xml-based timings file.
114  //
115  // BEWARE! If this method is used in a NON-MAIN thread it's not a problem,
116  // but counters are cached and written into file in main thread.
117  // To prevent overflowing there is a LIMIT on number of waiting counter writes.
118 
119  inline osg::Timer_t tick() { return vrecko::Timer::instance()->tick(); };
120 
121  typedef void (*OutputNotificationFuncType)(unsigned long dwOutputType, const char *outputLine, void* userParam);
122 
123  bool registerOutputNotification(OutputNotificationFuncType aFunc, void* userParam);
124  bool unregisterOutputNotification(OutputNotificationFuncType aFunc);
125 
126 protected:
127  std::ofstream log_file;
128  osg::Timer_t starttime_stamp;
129 
131  // Used to determine whether the current call to one of the ...log() methods
132  // should output the message directly or pospone it to be processed
133  // in a different (main) thread.
134 
136 
138 
140  public:
141  unsigned long dwOutputType;
142  std::string str;
143  };
145 
147  public:
148  unsigned int time; // ms
149  std::string strName;
150  float fValue;
151  };
152  DynamicArray<OutstandingCounter> outstandingCounters[2];
153  // two arrays: One is processed in the main thread and written to the file
154  // and the other can be filled by other threads.
156  // Index of the array that is being WRITTEN to.
158 
159  void addOutstandingText(unsigned long dwOutputType, const char *buffer);
160  // This method expects that the caller has already locked the [generalLock]
161  void processOutstandingTexts();
162  // This method expects that the caller has already locked the [generalLock]
163 
164  void writeBMCounterLowLevel(unsigned int time, const char *pName, float fValue);
165  // This method expects that the caller has already locked the necessary lock(s)
166 
167  void processOutstandingCounters();
168  // Flushes outstanding counters into file.
169  // Can be called only from the main thread.
170 
171 
172  void processTextMain(unsigned long dwOutputType, const char *buffer);
173  // This method expects that the caller has already locked the [generalLock]
174 
175  bool openBenchmarkFile();
176  // This function does nothing if the file is already opened (and returns true).
177  // Otherwise returns false if an error occur.
178  // NOTE: The method assumes the benchmarkFile lock is already taken,
179 
180 
182  OutputNotificationFuncType outFunc;
183  void *userParam;
184  };
185 
186 
187  struct TimingInfo {
188  TimingInfo() { startTime = 0; totalTime = 0; numRuns = 0; }
189 
190  osg::Timer_t startTime;
191 
192  // for statistics across multiple timings
193  osg::Timer_t totalTime;
194  int numRuns;
195  };
196 
197  std::map<std::string, TimingInfo, std::less<std::string> > sectionsTiming;
199 
201  std::streambuf *old_cout_buf, *old_cerr_buf;
202  std::ostream *old_cout;
203 
204  unsigned long dwAllowedOutput;
205  // combination of LOGGER_OUTPUTTYPE_*
206 
207  unsigned long dwOutputDest;
208  // combination of LOGGER_OUTPUTDEST_*
209 
211  // Handle of the original stdout to allow us to change colors
213  // we will be changing the color of console output, so here is the original color to restore it
214 
215  void textLog(unsigned long dwOutputType, const char *text = "", ...);
216  void vtextLog(unsigned long dwOutputType, const char *text, va_list args);
217  // [dwOutputType] is one of LOGGER_OUTPUTTYPE_
218 };
219 
220 extern VRECKO_EXPORT Logger logger;
221 
222 
223 #ifdef _DEBUG
224  #define OUTPUTSTR(str) logger.debugLog(str);
225  #define OUTPUTSTR2(str, p1) logger.debugLog((str), (p1));
226  #define OUTPUTSTR3(str, p1, p2) logger.debugLog((str), (p1), (p2));
227  #define OUTPUTSTR4(str, p1, p2, p3) logger.debugLog((str), (p1), (p2), (p3));
228  #define OUTPUTSTR5(str, p1, p2, p3, p4) logger.debugLog((str), (p1), (p2), (p3), (p4));
229  #define OUTPUTSTR6(str, p1, p2, p3, p4, p5) logger.debugLog((str), (p1), (p2), (p3), (p4), (p5));
230  #define OUTPUTSTR7(str, p1, p2, p3, p4, p5, p6) logger.debugLog((str), (p1), (p2), (p3), (p4), (p5), (p6));
231 
232  #define STARTTIMING(sectionName) logger.startTiming(sectionName);
233  #define STOPTIMING(sectionName) logger.stopTiming(sectionName);
234 #else
235  #define OUTPUTSTR(str) {}
236  #define OUTPUTSTR2(str, p1) {}
237  #define OUTPUTSTR3(str, p1, p2) {}
238  #define OUTPUTSTR4(str, p1, p2, p3) {}
239  #define OUTPUTSTR5(str, p1, p2, p3, p4) {}
240  #define OUTPUTSTR6(str, p1, p2, p3, p4, p5) {}
241  #define OUTPUTSTR7(str, p1, p2, p3, p4, p5, p6) {}
242 
243  #define STARTTIMING(sectionName)
244  #define STOPTIMING(sectionName)
245 #endif
246 
247 
248 };
249 
250 #endif
251