globus_common  17.9
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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]; /* XXX better not use a fmt bigger than this */ \
50  sprintf( \
51  buf, "%lu::%s", (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  char buf[4096]; /* XXX better not use a fmt bigger than this */ \
64  globus_abstime_t current_time; \
65  \
66  if(!globus_i_##module_name##_debug_handle.file) \
67  return; \
68  \
69  GlobusTimeAbstimeGetCurrent(current_time); \
70  va_start(ap, fmt); \
71  if(globus_i_##module_name##_debug_handle.thread_ids) \
72  { \
73  globus_thread_t __self = GlobusDebugThreadId(); \
74  sprintf(buf, "%lu:%lu.%.9lu::%s", \
75  (unsigned long) __self.dummy, \
76  (unsigned long) current_time.tv_sec, \
77  (unsigned long) current_time.tv_nsec, \
78  fmt); \
79  vfprintf(globus_i_##module_name##_debug_handle.file, buf, ap); \
80  } \
81  else \
82  { \
83  sprintf(buf, "%lu.%.9lu::%s", \
84  (unsigned long) current_time.tv_sec, \
85  (unsigned long) current_time.tv_nsec, \
86  fmt); \
87  vfprintf(globus_i_##module_name##_debug_handle.file, buf, ap); \
88  } \
89  va_end(ap); \
90  } \
91  void globus_i_##module_name##_debug_fwrite( \
92  const void *ptr, size_t size, size_t nmemb) \
93  { \
94  if(globus_i_##module_name##_debug_handle.file) \
95  fwrite(ptr, size, nmemb, \
96  globus_i_##module_name##_debug_handle.file); \
97  } \
98  globus_debug_handle_t globus_i_##module_name##_debug_handle
99 
100 /* call this in a header file (if needed externally) */
101 #define GlobusDebugDeclare(module_name) \
102  extern void globus_i_##module_name##_debug_printf(const char *, ...); \
103  extern void globus_i_##module_name##_debug_time_printf(const char *, ...);\
104  extern void globus_i_##module_name##_debug_fwrite( \
105  const void *ptr, size_t size, size_t nmemb); \
106  extern globus_debug_handle_t globus_i_##module_name##_debug_handle
107 
108 /* call this in module activate func
109  *
110  * 'levels' is a space separated list of level names that can be used in env
111  * they will map to a 2^i value (so, list them in same order as value)
112  *
113  * will look in env for {module_name}_DEBUG whose value is:
114  * <levels> [, [ [ # ] <file name>] [, <flags> [, <timestamp_levels>] ] ]
115  * where <levels> can be a single numeric or '|' separated level names
116  * <file name> is a debug output file... can be empty. stderr by default
117  * if a '#' precedes the filename, the file will be overwritten on each run
118  * otherwise, the default is to append to the existing (if one exists)
119  * <flags> 0 default (or any of the following to enable:
120  * 1 show thread ids
121  * 2 append pid to debug filename
122  * <timestamp_levels> similar to <levels>. specifies which levels to print
123  * timestamps with. default is none.
124  * Also, users can use the ALL level in their env setting to turn on
125  * all levels or precede the list of levels with '^' to enable all levels
126  * except those.
127  */
128 #define GlobusDebugInit(module_name, levels) \
129  globus_debug_init( \
130  #module_name "_DEBUG", \
131  #levels, \
132  &globus_i_##module_name##_debug_handle)
133 
134 /* call this in module deactivate func */
135 #define GlobusDebugDestroy(module_name) \
136  do \
137  { \
138  if(globus_i_##module_name##_debug_handle.using_file) \
139  { \
140  fclose(globus_i_##module_name##_debug_handle.file); \
141  } \
142  globus_i_##module_name##_debug_handle.file = GLOBUS_NULL; \
143  } while(0)
144 
145 /* use this to print a message unconditionally (message must be enclosed in
146  * parenthesis and contains a format and possibly var args
147  */
148 #define GlobusDebugMyPrintf(module_name, message) \
149  globus_i_##module_name##_debug_printf message
150 #define GlobusDebugMyTimePrintf(module_name, message) \
151  globus_i_##module_name##_debug_time_printf message
152 
153 #define GlobusDebugMyFwrite(module_name, buffer, size, count) \
154  globus_i_##module_name##_debug_fwrite((buffer), (size), (count))
155 
156 #define GlobusDebugMyFile(module_name) \
157  (globus_i_##module_name##_debug_handle.file)
158 
159 /* use this in an if() to debug enable blocks of code
160  * for example
161  *
162  * if(GlobusDebugTrue(MY_MODULE, VERIFICATION))
163  * {
164  * compute stats
165  * GlobusDebugMyPrintf(MY_MODULE, "Stats = %d\n", stats);
166  * }
167  */
168 #define GlobusDebugTrue(module_name, level) \
169  (globus_i_##module_name##_debug_handle.levels & (level))
170 
171 #define GlobusDebugTimeTrue(module_name, level) \
172  (globus_i_##module_name##_debug_handle.timestamp_levels & (level))
173 
174 /* most likely wrap this with your own macro,
175  * so you don't need to pass module_name all the time
176  * 'message' needs to be wrapped with parens and contains a format and
177  * possibly var args
178  */
179 #define GlobusDebugPrintf(module_name, level, message) \
180  do \
181  { \
182  if(GlobusDebugTrue(module_name, level)) \
183  { \
184  if(!GlobusDebugTimeTrue(module_name, level)) \
185  { \
186  GlobusDebugMyPrintf(module_name, message); \
187  } \
188  else \
189  { \
190  GlobusDebugMyTimePrintf(module_name, message); \
191  } \
192  } \
193  } while(0)
194 
195 #define GlobusDebugFwrite(module_name, level, buffer, size, count) \
196  do \
197  { \
198  if(GlobusDebugTrue(module_name, level)) \
199  { \
200  GlobusDebugMyFwrite(module_name, buffer, size, count); \
201  } \
202  } while(0)
203 
204 #else
205 
206 #define GlobusDebugThreadId() 0
207 #define GlobusDebugDeclare(module_name)
208 #define GlobusDebugDefine(module_name)
209 #define GlobusDebugInit(module_name, levels) do {} while(0)
210 #define GlobusDebugDestroy(module_name) do {} while(0)
211 #define GlobusDebugPrintf(module_name, level, message) do {} while(0)
212 #define GlobusDebugFwrite(module_name, level, buffer, size, count) \
213  do {} while(0)
214 #define GlobusDebugMyPrintf(module_name, message) do {} while(0)
215 #define GlobusDebugMyTimePrintf(module_name, message) do {} while(0)
216 #define GlobusDebugMyFwrite(module_name, buffer, size, count) do {} while(0)
217 #define GlobusDebugMyFile(module_name) (stderr)
218 #define GlobusDebugTrue(module_name, level) 0
219 #define GlobusDebugTimeTrue(module_name, level) 0
220 
221 #endif
222 
223 #ifdef __cplusplus
224 }
225 #endif
226 
227 #endif /* GLOBUS_DEBUG_H */
int globus_bool_t
Boolean type.
Definition: globus_types.h:78
Time Types and Macros.
Include System Headers.