globus_common  17.13
globus_debug.h
Go to the documentation of this file.
1 
7 #ifndef GLOBUS_DEBUG_H
8 #define GLOBUS_DEBUG_H
9 
10 #include "globus_common_include.h"
11 #include "globus_time.h"
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 #ifdef BUILD_DEBUG
18 
19 typedef struct
20 {
21  unsigned levels;
22  unsigned timestamp_levels;
23  FILE * file;
24  globus_bool_t thread_ids;
25  globus_bool_t using_file;
26 } globus_debug_handle_t;
27 
28 void
29 globus_debug_init(
30  const char * env_name,
31  const char * level_names,
32  globus_debug_handle_t * handle);
33 
34 #define GlobusDebugThreadId() globus_thread_self()
35 
36 /* call in same file as module_activate func (before (de)activate funcs) */
37 #define GlobusDebugDefine(module_name) \
38  extern globus_debug_handle_t globus_i_##module_name##_debug_handle; \
39  void globus_i_##module_name##_debug_printf(const char * fmt, ...) \
40  { \
41  va_list ap; \
42  \
43  if(!globus_i_##module_name##_debug_handle.file) \
44  return; \
45  \
46  va_start(ap, fmt); \
47  if(globus_i_##module_name##_debug_handle.thread_ids) \
48  { \
49  char buf[4096] = {0}; /* will truncate larger messages */ \
50  snprintf(buf, sizeof(buf), "%lu::%s", \
51  (unsigned long) globus_thread_self().dummy, fmt); \
52  vfprintf(globus_i_##module_name##_debug_handle.file, buf, ap); \
53  } \
54  else \
55  { \
56  vfprintf(globus_i_##module_name##_debug_handle.file, fmt, ap); \
57  } \
58  va_end(ap); \
59  } \
60  void globus_i_##module_name##_debug_time_printf(const char * fmt, ...) \
61  { \
62  va_list ap; \
63  globus_abstime_t current_time; \
64  if(globus_i_##module_name##_debug_handle.file) \
65  { \
66  char buf[4096] = {0}; /* will truncate larger messages */ \
67  GlobusTimeAbstimeGetCurrent(current_time); \
68  va_start(ap, fmt); \
69  if(globus_i_##module_name##_debug_handle.thread_ids) \
70  { \
71  globus_thread_t __self = GlobusDebugThreadId(); \
72  snprintf(buf, sizeof(buf), "%lu:%lu.%.9lu::%s", \
73  (unsigned long) __self.dummy, \
74  (unsigned long) current_time.tv_sec, \
75  (unsigned long) current_time.tv_nsec, \
76  fmt); \
77  } \
78  else \
79  { \
80  snprintf(buf, sizeof(buf), "%lu.%.9lu::%s", \
81  (unsigned long) current_time.tv_sec, \
82  (unsigned long) current_time.tv_nsec, \
83  fmt); \
84  } \
85  vfprintf(globus_i_##module_name##_debug_handle.file, buf, ap); \
86  va_end(ap); \
87  } \
88  } \
89  void globus_i_##module_name##_debug_fwrite( \
90  const void *ptr, size_t size, size_t nmemb) \
91  { \
92  if(globus_i_##module_name##_debug_handle.file) \
93  fwrite(ptr, size, nmemb, \
94  globus_i_##module_name##_debug_handle.file); \
95  } \
96  globus_debug_handle_t globus_i_##module_name##_debug_handle
97 
98 /* call this in a header file (if needed externally) */
99 #define GlobusDebugDeclare(module_name) \
100  extern void globus_i_##module_name##_debug_printf(const char *, ...); \
101  extern void globus_i_##module_name##_debug_time_printf(const char *, ...);\
102  extern void globus_i_##module_name##_debug_fwrite( \
103  const void *ptr, size_t size, size_t nmemb); \
104  extern globus_debug_handle_t globus_i_##module_name##_debug_handle
105 
106 /* call this in module activate func
107  *
108  * 'levels' is a space separated list of level names that can be used in env
109  * they will map to a 2^i value (so, list them in same order as value)
110  *
111  * will look in env for {module_name}_DEBUG whose value is:
112  * <levels> [, [ [ # ] <file name>] [, <flags> [, <timestamp_levels>] ] ]
113  * where <levels> can be a single numeric or '|' separated level names
114  * <file name> is a debug output file... can be empty. stderr by default
115  * if a '#' precedes the filename, the file will be overwritten on each run
116  * otherwise, the default is to append to the existing (if one exists)
117  * <flags> 0 default (or any of the following to enable:
118  * 1 show thread ids
119  * 2 append pid to debug filename
120  * <timestamp_levels> similar to <levels>. specifies which levels to print
121  * timestamps with. default is none.
122  * Also, users can use the ALL level in their env setting to turn on
123  * all levels or precede the list of levels with '^' to enable all levels
124  * except those.
125  */
126 #define GlobusDebugInit(module_name, levels) \
127  globus_debug_init( \
128  #module_name "_DEBUG", \
129  #levels, \
130  &globus_i_##module_name##_debug_handle)
131 
132 /* call this in module deactivate func */
133 #define GlobusDebugDestroy(module_name) \
134  do \
135  { \
136  if(globus_i_##module_name##_debug_handle.using_file) \
137  { \
138  fclose(globus_i_##module_name##_debug_handle.file); \
139  } \
140  globus_i_##module_name##_debug_handle.file = GLOBUS_NULL; \
141  } while(0)
142 
143 /* use this to print a message unconditionally (message must be enclosed in
144  * parenthesis and contains a format and possibly var args
145  */
146 #define GlobusDebugMyPrintf(module_name, message) \
147  globus_i_##module_name##_debug_printf message
148 #define GlobusDebugMyTimePrintf(module_name, message) \
149  globus_i_##module_name##_debug_time_printf message
150 
151 #define GlobusDebugMyFwrite(module_name, buffer, size, count) \
152  globus_i_##module_name##_debug_fwrite((buffer), (size), (count))
153 
154 #define GlobusDebugMyFile(module_name) \
155  (globus_i_##module_name##_debug_handle.file)
156 
157 /* use this in an if() to debug enable blocks of code
158  * for example
159  *
160  * if(GlobusDebugTrue(MY_MODULE, VERIFICATION))
161  * {
162  * compute stats
163  * GlobusDebugMyPrintf(MY_MODULE, "Stats = %d\n", stats);
164  * }
165  */
166 #define GlobusDebugTrue(module_name, level) \
167  (globus_i_##module_name##_debug_handle.levels & (level))
168 
169 #define GlobusDebugTimeTrue(module_name, level) \
170  (globus_i_##module_name##_debug_handle.timestamp_levels & (level))
171 
172 /* most likely wrap this with your own macro,
173  * so you don't need to pass module_name all the time
174  * 'message' needs to be wrapped with parens and contains a format and
175  * possibly var args
176  */
177 #define GlobusDebugPrintf(module_name, level, message) \
178  do \
179  { \
180  if(GlobusDebugTrue(module_name, level)) \
181  { \
182  if(!GlobusDebugTimeTrue(module_name, level)) \
183  { \
184  GlobusDebugMyPrintf(module_name, message); \
185  } \
186  else \
187  { \
188  GlobusDebugMyTimePrintf(module_name, message); \
189  } \
190  } \
191  } while(0)
192 
193 #define GlobusDebugFwrite(module_name, level, buffer, size, count) \
194  do \
195  { \
196  if(GlobusDebugTrue(module_name, level)) \
197  { \
198  GlobusDebugMyFwrite(module_name, buffer, size, count); \
199  } \
200  } while(0)
201 
202 #else
203 
204 #define GlobusDebugThreadId() 0
205 #define GlobusDebugDeclare(module_name)
206 #define GlobusDebugDefine(module_name)
207 #define GlobusDebugInit(module_name, levels) do {} while(0)
208 #define GlobusDebugDestroy(module_name) do {} while(0)
209 #define GlobusDebugPrintf(module_name, level, message) do {} while(0)
210 #define GlobusDebugFwrite(module_name, level, buffer, size, count) \
211  do {} while(0)
212 #define GlobusDebugMyPrintf(module_name, message) do {} while(0)
213 #define GlobusDebugMyTimePrintf(module_name, message) do {} while(0)
214 #define GlobusDebugMyFwrite(module_name, buffer, size, count) do {} while(0)
215 #define GlobusDebugMyFile(module_name) (stderr)
216 #define GlobusDebugTrue(module_name, level) 0
217 #define GlobusDebugTimeTrue(module_name, level) 0
218 
219 #endif
220 
221 #ifdef __cplusplus
222 }
223 #endif
224 
225 #endif /* GLOBUS_DEBUG_H */
Include System Headers.
Time Types and Macros.
int globus_bool_t
Boolean type.
Definition: globus_types.h:78