3cc234e75383c1576f59c573ac9ec0228fcd2bb9
[platform/upstream/syncevolution.git] / src / synthesis / src / sysync / debuglogger.h
1 /*
2  *  File:         debuglogger.h
3  *
4  *  Author:       Lukas Zeller (luz@plan44.ch)
5  *
6  *  Global debug mechanisms
7  *
8  *  Copyright (c) 2005-2011 by Synthesis AG + plan44.ch
9  *
10  *  2005-08-04 : luz : created
11  *
12  */
13
14 #ifndef DEBUGLOGGER_H
15 #define DEBUGLOGGER_H
16
17 #ifdef SYDEBUG
18
19 #include "generic_types.h"
20 #include "platform_mutex.h"
21 #include "platform_thread.h"
22 #include "sysync.h"
23 #include "sysync_noncopyable.h"
24
25 namespace sysync {
26
27
28 /// @brief Debug output formats
29 typedef enum {
30   dbgfmt_text,        ///< plain text format (but can be indented)
31   dbgfmt_xml,         ///< XML format
32   dbgfmt_html,        ///< HTML format
33 #ifdef USE_DLT
34   dbgfmt_dlt,         ///< GENIVI Diagnostic Log and Trace
35 #endif
36   numDbgOutFormats
37 } TDbgOutFormats;
38
39 /// @brief HTML dynamic folding
40 typedef enum {
41   dbgfold_none,       ///< do not include dynamic folding into HTML logs
42   dbgfold_collapsed,  ///< include folding - all collapsed by default
43   dbgfold_expanded,   ///< include folding - all expanded by default
44   dbgfold_auto,       ///< include folding - collapse/expand state predefined on a block-by-block basis
45   numDbgFoldingModes
46 } TDbgFoldingModes;
47
48 /// @brief Debug flush modes
49 typedef enum {
50   dbgflush_none,      ///< no flush, keep open as long as possible
51   dbgflush_flush,     ///< flush every debug message
52   dbgflush_openclose, ///< open and close debug channel separately for every message (as in 2.x engine)
53   numDbgFlushModes
54 } TDbgFlushModes;
55
56 /// @brief Debug subthread logging modes
57 typedef enum {
58   dbgsubthread_none,          ///< do not handle output from subthread specially
59   dbgsubthread_suppress,      ///< suppress output from subthreads
60   dbgsubthread_separate,      ///< create separate output stream (=file) for each subthread
61   dbgsubthread_linemix,       ///< mix output on a line by line basis (forcing output to slow openclose mode)
62   dbgsubthread_bufferandmix,  ///< buffer thread's output and mix it into main stream when appropriate
63   numDbgSubthreadModes
64 } TDbgSubthreadModes;
65
66
67 /// @brief HTML linking into source code
68 typedef enum {
69   dbgsource_none,     ///< do not include links into source code in HTML logs
70   dbgsource_hint,     ///< no links, but info about what file/line number the message comes from
71   dbgsource_doxygen,  ///< include link into doxygen prepared HTML version of source code
72   dbgsource_txmt,     ///< include txmt:// link (understood by TextMate and BBEdit) into source code
73   numDbgSourceModes
74 } TDbgSourceModes;
75
76
77 #ifndef HARDCODED_CONFIG
78 extern cAppCharP const DbgOutFormatNames[numDbgOutFormats];
79 extern cAppCharP const DbgFoldingModeNames[numDbgFoldingModes];
80 extern cAppCharP const DbgFlushModeNames[numDbgFlushModes];
81 extern cAppCharP const DbgSubthreadModeNames[numDbgSubthreadModes];
82 extern cAppCharP const DbgSourceModeNames[numDbgSourceModes];
83 #endif
84 extern cAppCharP const DbgOutFormatExtensions[numDbgOutFormats];
85
86 /// @brief Debug options container
87 class TDbgOptions {
88 public:
89   // constructor
90   TDbgOptions();
91   // methods
92   void clear(void);
93   // properties
94   TDbgOutFormats fOutputFormat; ///< format
95   string fIndentString; ///< indent string
96   string fCustomPrefix; ///< custom prefix (different xml header or html with different styles for example)
97   string fCustomSuffix; ///< custom suffix (should match prefix)
98   string fBasename; ///< the initial part of the log file name, can override the hard-coded TARGETID (empty if unset)
99   bool fSeparateMsgs; ///< separate message lines (needed especially in XML to avoid unformatted PCDATA block)
100   bool fTimestampStructure; ///< include timestamp for structure elements (blocks)
101   bool fTimestampForAll; ///< include timestamp information for every message
102   bool fThreadIDForAll; ///< include thread ID information for every message
103   TDbgFlushModes fFlushMode; ///< how and when to flush
104   TDbgFoldingModes fFoldingMode; ///< if and how to fold HTML output
105   TDbgSourceModes fSourceLinkMode; ///< if and how to link with source code
106   string fSourceRootPath; ///< defines root path for source links
107   bool fAppend; ///< if set, existing debug files will not be overwritten, but appended to
108   TDbgSubthreadModes fSubThreadMode; ///< how to handle debug messages from subthreads
109   uInt32 fSubThreadBufferMax; ///< how much to buffer for subthread maximally
110 }; // TDbgOptions
111
112
113 /// @brief Debug output channel
114 class TDbgOut : noncopyable {
115   // construction/destruction
116 private:
117   bool fDestructed; // flag which will be set once destruct() has been called - by the outermost derivate's destructor
118 public:
119   TDbgOut();
120   virtual ~TDbgOut();
121   virtual void doDestruct(void); // will be called by destruct, derived must call inherited if they implement it
122   void destruct(void); // to be called by ALL destructors of derivates.
123   // methods
124   /// @brief duplicate output channel
125   virtual TDbgOut *clone(void) { return new TDbgOut; };
126   /// @brief open debug output channel
127   /// Notes:
128   /// - Autocloses current channel if already open
129   /// - May not actually open the channel, but should test if channel is writable
130   /// @return                         false if debug channel cannot be opened and written to
131   /// @param aDbgOutputName[in]       name (usually file name) of debug output channel
132   /// @param aSuggestedExtension[in]  file extension suggested (may not be used depending on channel type)
133   /// @param aFlushMode[in]           flush mode to be used on the channel
134   /// @param aOverWrite[in]           if true, debug output channel (=file) will be overwritten (otherwise: appended to)
135   /// @param aRawMode[in]             if true, debug output channel (=file) is opened in binary raw mode (for message dumps etc.)
136   virtual bool openDbg(cAppCharP aDbgOutputName, cAppCharP aSuggestedExtension, TDbgFlushModes aFlushMode, bool aOverWrite, bool aRawMode=false) { return true; };
137   /// @brief get current size of output file
138   /// @return number of bytes, 0 if file is empty or for non-files (like console)
139   virtual uInt32 dbgFileSize(void) { return 0; };
140   /// @brief close and flush all log output
141   virtual void closeDbg(void) { /* nop */ };
142   /// @brief write single line to debug output channel
143   /// @param aLine[in]                text for line to be written out (must not contain line ends)
144   /// @param aForceFlush[in]          if true, debug output will be flushed to permanent storage regardless of current flush mode
145   virtual void putLine(cAppCharP aLine, bool aForceFlush) { /* nop */};
146   /// @brief write raw data to debug output channel (usually makes sense only when channel is opened in raw mode)
147   /// @param aData[in]                pointer to data to be written
148   /// @param aSize[in]                size in bytes of data block at aData to be written
149   virtual void putRawData(cAppPointer aData, memSize aSize) { /* nop */};
150 protected:
151   bool fIsOpen;
152 }; // TDbgOut
153
154
155
156 #ifndef NO_C_FILES
157
158 /// @brief Standard file debug output channel
159 class TStdFileDbgOut : public TDbgOut {
160   typedef TDbgOut inherited;
161 public:
162   // constructor/destructor
163   TStdFileDbgOut();
164   virtual ~TStdFileDbgOut();
165   // methods
166   virtual TDbgOut *clone(void) { return new TStdFileDbgOut; };
167   virtual bool openDbg(cAppCharP aDbgOutputName, cAppCharP aSuggestedExtension, TDbgFlushModes aFlushMode, bool aOverWrite, bool aRawMode=false);
168   virtual uInt32 dbgFileSize(void);
169   virtual void closeDbg(void);
170   virtual void putLine(cAppCharP aLine, bool aForceFlush);
171   virtual void putRawData(cAppPointer aData, memSize aSize);
172 private:
173   TDbgFlushModes fFlushMode;
174   string fFileName;
175   FILE * fFile;
176   MutexPtr_t mutex;
177 }; // TStdFileDbgOut
178
179 #endif
180
181
182 /// @brief Output to console
183 class TConsoleDbgOut : public TDbgOut {
184   typedef TDbgOut inherited;
185 public:
186   // constructor/destructor
187   TConsoleDbgOut();
188   // methods
189   virtual TDbgOut *clone(void) { return new TConsoleDbgOut; };
190   virtual bool openDbg(cAppCharP aDbgOutputName, cAppCharP aSuggestedExtension, TDbgFlushModes aFlushMode, bool aOverWrite, bool aRawMode=false);
191   virtual void closeDbg(void);
192   virtual void putLine(cAppCharP aLine, bool aForceFlush);
193   virtual void putRawData(cAppPointer aData, memSize aSize) { /* not supported on console, just NOP */ };
194 }; // TConsoleDbgOut
195
196
197 // Debug logger class
198 // ------------------
199
200 /// @brief hierachical block history
201 typedef struct BlockLevel {
202   string fBlockName;
203   uInt32 fBlockNo;
204   struct BlockLevel *fNext;
205 } TBlockLevel;
206
207 class TDebugLogger;
208 class GZones;
209
210 /// @brief Debug logger base class (without subthread handling)
211 class TDebugLoggerBase : noncopyable {
212 public:
213   // constructor/destructor
214   TDebugLoggerBase(GZones *aGZonesP);
215   virtual ~TDebugLoggerBase();
216   // methods
217   /// @brief install output channel handler object (and pass it's ownership!)
218   /// @param aDbgOutP[in] output channel to be used for this logger (will be owned and finally destroyed by the logger)
219   void installOutput(TDbgOut *aDbgOutP);
220   /// @brief link this logger to another logger and redirect output to that logger
221   /// @param aDebugLoggerP[in] another logger, that must be alive as long as this logger is alive
222   void outputVia(TDebugLoggerBase *aDebugLoggerP);
223   /// @brief check if an output channel is already established other than with default values
224   bool outputEstablished(void) { return fOutStarted; };
225   /// @brief set debug options
226   virtual void setOptions(const TDbgOptions *aDbgOptionsP) { fDbgOptionsP = aDbgOptionsP; };
227   /// @brief get debug options pointer
228   const TDbgOptions *getOptions(void) { return fDbgOptionsP; };
229   // @brief convenience version for getting time
230   lineartime_t getSystemNowAs(timecontext_t aContext);
231   /// @brief get current debug mask for this logger.
232   /// Note that setEnabled(false) will cause this to return 0 even if the mask itself is non-zero
233   uInt32 getMask(void) { return fDebugEnabled ? fDebugMask : 0; };
234   uInt32 getRealMask(void) { return fDebugMask; };
235   /// @brief set new debug mask for this logger
236   void setMask(uInt32 aDbgMask)
237     { fDebugMask=aDbgMask; };
238   /// @brief enable or disable this logger (but leave dbgMask intact)
239   void setEnabled(bool aEnabled)
240     { fDebugEnabled=aEnabled; };
241   /// @brief set debug output path + filename (no extension, please)
242   void setDebugPath(cAppCharP aPath) { fDbgPath = aPath; };
243   /// @brief append to debug output path + filename (no extension, please)
244   void appendToDebugPath(cAppCharP aPathElement) { fDbgPath += aPathElement; };
245   /// @brief get debug output file path (w/o extension)
246   cAppCharP getDebugPath(void) { return fOutputLoggerP ? fOutputLoggerP->getDebugPath() : fDbgPath.c_str(); };
247   /// @brief get debug output file name (w/o path or extension)
248   cAppCharP getDebugFilename(void) { if (fOutputLoggerP) return fOutputLoggerP->getDebugFilename(); size_t n=fDbgPath.find_last_of("\\/:"); return fDbgPath.c_str()+(n!=string::npos ? n+1 : 0); };
249   /// @brief get debug output file extension
250   cAppCharP getDebugExt(void) { return fOutputLoggerP ? fOutputLoggerP->getDebugExt() : fDbgOptionsP ? DbgOutFormatExtensions[fDbgOptionsP->fOutputFormat] : ""; };
251   // - normal output
252   /// @brief Write text to debug output channel.
253   /// Notes:
254   /// - Line will be terminated by linefeed automatically (no need to include a linefeed for single line message)
255   /// - \n chars can be used to separate multi-line output. Formatter will take care that
256   ///   all lines are equally indented/formatted/prefixed
257   /// @param aDbgMask debug mask, bits set here must be set in the debuglogger's own mask in order to display the debug text
258   /// @param aText[in] text to be written out
259   /// @param aTextSize[in] if>0, this is the maximum number of chars to output from aText
260   virtual void DebugPuts(TDBG_LOCATION_PROTO uInt32 aDbgMask, cAppCharP aText, stringSize aTextSize=0, bool aPreFormatted=false);
261   /// @brief Write formatted text to debug output channel.
262   /// @param aDbgMask debug mask, bits set here must be set in the debuglogger's own mask in order to display the debug text
263   /// @param aFormat[in] format text in vprintf style to be written out
264   /// @param aArgs[in] varargs in vprintf style
265   virtual void DebugVPrintf(TDBG_LOCATION_PROTO uInt32 aDbgMask, cAppCharP aFormat, va_list aArgs);
266   /// @brief Write formatted text to debug output channel.
267   /// @param aDbgMask debug mask, bits set here must be set in the debuglogger's own mask in order to display the debug text
268   /// @param aFormat[in] format text in printf style to be written out
269   void DebugPrintf(TDBG_LOCATION_PROTO uInt32 aDbgMask, cAppCharP aFormat, ...)
270     #ifdef __GNUC__
271     __attribute__((format(printf, TDBG_LOCATION_ARG_NUM + 3, TDBG_LOCATION_ARG_NUM + 4)))
272     #endif
273     ;
274   /// @brief set debug mask to be used for next DebugPrintfLastMask() call
275   /// @param aDbgMask debug mask, bits set here must be set in the debuglogger's own mask in order to display the debug text
276   virtual TDebugLoggerBase &setNextMask(uInt32 aDbgMask);
277   /// @brief like DebugPrintf(), but using mask previously set by setNextMask()
278   /// @param aFormat[in] format text in printf style to be written out
279   void DebugPrintfLastMask(TDBG_LOCATION_PROTO cAppCharP aFormat, ...)
280     #ifdef __GNUC__
281     __attribute__((format(printf, TDBG_LOCATION_ARG_NUM + 2, TDBG_LOCATION_ARG_NUM + 3)))
282     #endif
283     ;
284   // - Blocks
285   /// @brief Open structure Block. Depending on the output format, this will generate indent, XML tags, HTML headers etc.
286   /// @param aBlockName[in]  Name of Block. Will be used e.g. for tag name in XML. Intention is to group similar entities with the same BlockName
287   /// @param aBlockTitle[in] Title (descriptive text) of Block.
288   /// @param aCollapsed[in]  If set, and folding mode is auto, block will be initially collapsed when log is opened in browser.
289   /// @param aBlockFmt[in]   Format string for additional Block info. Should contain one or multiple tag=value pairs, separated by the pipe char |.
290   ///                          This will be used to generate XML attributes or other identifiers.
291   /// @param aArgs[in]         varargs in vprintf style for aBlockFmt
292   virtual void DebugVOpenBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, bool aCollapsed, cAppCharP aBlockFmt, va_list aArgs);
293   /// @brief Open structure Block, printf style variant
294   void DebugOpenBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, bool aCollapsed, cAppCharP aBlockFmt, ...)
295     #ifdef __GNUC__
296     __attribute__((format(printf, TDBG_LOCATION_ARG_NUM + 5, TDBG_LOCATION_ARG_NUM + 6)))
297     #endif
298       ;
299   void DebugOpenBlockExpanded(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, cAppCharP aBlockFmt, ...)
300     #ifdef __GNUC__
301     __attribute__((format(printf, TDBG_LOCATION_ARG_NUM + 4, TDBG_LOCATION_ARG_NUM + 5)))
302     #endif
303     ;
304   void DebugOpenBlockCollapsed(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, cAppCharP aBlockFmt, ...)
305     #ifdef __GNUC__
306     __attribute__((format(printf, TDBG_LOCATION_ARG_NUM + 4, TDBG_LOCATION_ARG_NUM + 5)))
307     #endif
308     ;
309   /// @brief Open structure Block, without any attributes
310   virtual void DebugOpenBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle=NULL, bool aCollapsed=false);
311   /// @brief Close structure Block. Name is used to close possibly unclosed contained Blocks automatically.
312   virtual void DebugCloseBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName);
313 protected:
314   // helper methods
315   /// @brief start debugging output if needed and sets fOutStarted
316   bool DebugStartOutput(void);
317   /// @brief Output single line to debug channel (includes indenting, but no other formatting)
318   void DebugPutLine(TDBG_LOCATION_PROTO cAppCharP aText, stringSize aTextSize=0, bool aPre=false);
319   /// @brief finalize debugging output
320   void DebugFinalizeOutput(void);
321   /// @brief get block number
322   uInt32 getBlockNo(void) { return fOutputLoggerP ? fOutputLoggerP->getBlockNo() : fBlockNo; };
323   /// @brief increment block number
324   void nextBlock(void) { if (fOutputLoggerP) fOutputLoggerP->nextBlock(); else fBlockNo++; };
325   /// @brief internal helper for closing debug Blocks
326   /// @param aBlockName[in]   Name of Block to close. All Blocks including the first with given name will be closed. If NULL, all Blocks will be closed.
327   /// @param aCloseComment[in]  Comment about closing Block. If NULL, no comment will be shown (unless implicit closes occur, which auto-creates a comment)
328   void internalCloseBlocks(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aCloseComment);
329   #ifdef SYDEBUG_LOCATION
330   /// @brief turn text into link to source code
331   string dbg2Link(const TDbgLocation &aTDbgLoc, const string &aTxt);
332   #endif // SYDEBUG_LOCATION
333   // Variables
334   TDbgOut *fDbgOutP; // the debug output
335   string fDbgPath; // the output path+filename (w/o extension)
336   const TDbgOptions *fDbgOptionsP; // the debug options
337   uInt32 fDebugMask; // the debug mask
338   bool fDebugEnabled; // on-off-switch for debugging output
339   uInt32 fNextDebugMask; // debug mask to be used for next DebugPrintfLastMask()
340   uInt16 fIndent; // the current indent
341   TBlockLevel *fBlockHistory; // the linked list of Block history entries
342   bool fOutStarted; // set if output has started
343   uInt32 fBlockNo; // block count for folding
344   GZones *fGZonesP; // zones list for time conversions
345   TDebugLoggerBase *fOutputLoggerP; // another logger to be used for output
346 }; // TDebugLoggerBase
347
348
349 #ifdef MULTI_THREAD_SUPPORT
350 /// @brief Subthread log handling
351 typedef struct SubThreadLog {
352   uInt32 fThreadID;
353   struct SubThreadLog *fNext;
354   TDebugLoggerBase *fSubThreadLogger;
355 } TSubThreadLog;
356 #endif
357
358
359
360 /// @brief Debug logger class
361 class TDebugLogger : public TDebugLoggerBase {
362   typedef TDebugLoggerBase inherited;
363 public:
364   // constructor/destructor
365   TDebugLogger(GZones *aGZonesP);
366   virtual ~TDebugLogger();
367   // methods
368   #ifdef MULTI_THREAD_SUPPORT
369   /// @brief set debug options in this logger and all sub thread loggers
370   virtual void setOptions(const TDbgOptions *aDbgOptionsP);
371   virtual void DebugPuts(TDBG_LOCATION_PROTO uInt32 aDbgMask, cAppCharP aText, stringSize aTextSize=0, bool aPreFormatted=false);
372   virtual void DebugVPrintf(TDBG_LOCATION_PROTO uInt32 aDbgMask, cAppCharP aFormat, va_list aArgs);
373   virtual void DebugVOpenBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, bool aCollapsed, cAppCharP aBlockFmt, va_list aArgs);
374   virtual void DebugCloseBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName);
375   virtual TDebugLoggerBase &setNextMask(uInt32 aDbgMask);
376   #endif
377   // - thread debug output serializing
378   /// @brief output all buffered subthread's output in a special subthread Block in the main output
379   void DebugShowSubThreadOutput(void);
380   /// @brief signals the calling thread that it is done with doing output for now.
381   /// @param aRemoveIt[in] if set, do remove thread from the subthread logger list
382   /// Notes:
383   /// - If the main thread is doing this and we have bufferandmix mode, the next subthread will be allowed
384   ///   to write into the output channel until a new main thread gains control via DebugDefineMainThread();
385   void DebugThreadOutputDone(bool aRemoveIt=false);
386   /// @brief Define the current calling thread as the main debug thread
387   /// Note: This is used for example when starting to process the next request of a session which possibly
388   //        occurs from another thread).
389   void DebugDefineMainThread(void);
390 private:
391   #ifdef MULTI_THREAD_SUPPORT
392   // helpers
393   /// @brief find (and possibly delete) subthread record
394   /// @param aAndRemove[in] if set, the subthread record will be removed in a thread safe way
395   ///        IF AND ONLY IF aThreadID is the calling thread (i.e. only own thread may be removed from the list)!
396   ///        Note that the caller must take care of deleting the subthread record
397   TSubThreadLog *findSubThread(uInt32 aThreadID, bool aAndRemove=false);
398   /// @brief find or create logger for subthread
399   TDebugLoggerBase *getThreadLogger(bool aCreateNew=true);
400   // Variables
401   uIntArch fMainThreadID;
402   TSubThreadLog *fSubThreadLogs; // the linked list of active subthreads
403   TDebugLoggerBase *fSilentLoggerP; // a silent (inactive) logger required for suppressed subthreads
404   #endif
405 }; // TDebugLogger
406
407
408
409
410 } // namespace sysync
411
412 #endif // SYDEBUG
413
414 #endif // DEBUGLOGGER_H
415
416
417 // eof
418