Git fork
at reftables-rust 279 lines 8.3 kB view raw
1#ifndef TRACE_H 2#define TRACE_H 3 4#include "strbuf.h" 5 6/** 7 * The trace API can be used to print debug messages to stderr or a file. Trace 8 * code is inactive unless explicitly enabled by setting `GIT_TRACE*` environment 9 * variables. 10 * 11 * The trace implementation automatically adds `timestamp file:line ... \n` to 12 * all trace messages. E.g.: 13 * 14 * ------------ 15 * 23:59:59.123456 git.c:312 trace: built-in: git 'foo' 16 * 00:00:00.000001 builtin/foo.c:99 foo: some message 17 * ------------ 18 * 19 * Bugs & Caveats 20 * -------------- 21 * 22 * GIT_TRACE_* environment variables can be used to tell Git to show 23 * trace output to its standard error stream. Git can often spawn a pager 24 * internally to run its subcommand and send its standard output and 25 * standard error to it. 26 * 27 * Because GIT_TRACE_PERFORMANCE trace is generated only at the very end 28 * of the program with atexit(), which happens after the pager exits, it 29 * would not work well if you send its log to the standard error output 30 * and let Git spawn the pager at the same time. 31 * 32 * As a work around, you can for example use '--no-pager', or set 33 * GIT_TRACE_PERFORMANCE to another file descriptor which is redirected 34 * to stderr, or set GIT_TRACE_PERFORMANCE to a file specified by its 35 * absolute path. 36 * 37 * For example instead of the following command which by default may not 38 * print any performance information: 39 * 40 * ------------ 41 * GIT_TRACE_PERFORMANCE=2 git log -1 42 * ------------ 43 * 44 * you may want to use: 45 * 46 * ------------ 47 * GIT_TRACE_PERFORMANCE=2 git --no-pager log -1 48 * ------------ 49 * 50 * or: 51 * 52 * ------------ 53 * GIT_TRACE_PERFORMANCE=3 3>&2 git log -1 54 * ------------ 55 * 56 * or: 57 * 58 * ------------ 59 * GIT_TRACE_PERFORMANCE=/path/to/log/file git log -1 60 * ------------ 61 * 62 */ 63 64/** 65 * Defines a trace key (or category). The default (for API functions that 66 * don't take a key) is `GIT_TRACE`. 67 * 68 * E.g. to define a trace key controlled by environment variable `GIT_TRACE_FOO`: 69 * 70 * ------------ 71 * static struct trace_key trace_foo = TRACE_KEY_INIT(FOO); 72 * 73 * static void trace_print_foo(const char *message) 74 * { 75 * trace_printf_key(&trace_foo, "%s", message); 76 * } 77 * ------------ 78 * 79 * Note: don't use `const` as the trace implementation stores internal state in 80 * the `trace_key` structure. 81 */ 82struct trace_key { 83 const char * const key; 84 int fd; 85 unsigned int initialized : 1; 86 unsigned int need_close : 1; 87}; 88 89extern struct trace_key trace_default_key; 90 91#define TRACE_KEY_INIT(name) { .key = "GIT_TRACE_" #name } 92extern struct trace_key trace_perf_key; 93extern struct trace_key trace_setup_key; 94 95struct repository; 96 97void trace_repo_setup(struct repository *r); 98 99/** 100 * Checks whether the trace key is enabled. Used to prevent expensive 101 * string formatting before calling one of the printing APIs. 102 */ 103int trace_want(struct trace_key *key); 104 105/** 106 * Enables or disables tracing for the specified key, as if the environment 107 * variable was set to the given value. 108 */ 109void trace_override_envvar(struct trace_key *key, const char *value); 110 111/** 112 * Disables tracing for the specified key, even if the environment variable 113 * was set. 114 */ 115void trace_disable(struct trace_key *key); 116 117/** 118 * Returns nanoseconds since the epoch (01/01/1970), typically used 119 * for performance measurements. 120 * Currently there are high precision timer implementations for Linux (using 121 * `clock_gettime(CLOCK_MONOTONIC)`) and Windows (`QueryPerformanceCounter`). 122 * Other platforms use `gettimeofday` as time source. 123 */ 124uint64_t getnanotime(void); 125 126void trace_command_performance(const char **argv); 127void trace_verbatim(struct trace_key *key, const void *buf, unsigned len); 128uint64_t trace_performance_enter(void); 129 130/* 131 * TRACE_CONTEXT may be set to __FUNCTION__ if the compiler supports it. The 132 * default is __FILE__, as it is consistent with assert(), and static function 133 * names are not necessarily unique. 134 * 135 * __FILE__ ":" __FUNCTION__ doesn't work with GNUC, as __FILE__ is supplied 136 * by the preprocessor as a string literal, and __FUNCTION__ is filled in by 137 * the compiler as a string constant. 138 */ 139#ifndef TRACE_CONTEXT 140# define TRACE_CONTEXT __FILE__ 141#endif 142 143/** 144 * Macros to add the file:line of the calling code, instead of that of 145 * the trace function itself. 146 * 147 * Note: with C99 variadic macros, __VA_ARGS__ must include the last fixed 148 * parameter ('format' in this case). Otherwise, a call without variable 149 * arguments will have a surplus ','. E.g.: 150 * 151 * #define foo(format, ...) bar(format, __VA_ARGS__) 152 * foo("test"); 153 * 154 * will expand to 155 * 156 * bar("test",); 157 * 158 * which is invalid (note the ',)'). With GNUC, '##__VA_ARGS__' drops the 159 * comma, but this is non-standard. 160 */ 161 162/** 163 * trace_printf(), accepts "const char *format, ...". 164 * 165 * Prints a formatted message, similar to printf. 166 */ 167#define trace_printf(...) trace_printf_key(&trace_default_key, __VA_ARGS__) 168 169/** 170 * trace_printf_key(), accepts "struct trace_key *key, const char *format, ...". 171 */ 172#define trace_printf_key(key, ...) \ 173 do { \ 174 if (trace_pass_fl(key)) \ 175 trace_printf_key_fl(TRACE_CONTEXT, __LINE__, key, \ 176 __VA_ARGS__); \ 177 } while (0) 178 179/** 180 * trace_argv_printf(), accepts "struct trace_key *key, const char *format, ...)". 181 * 182 * Prints a formatted message, followed by a quoted list of arguments. 183 */ 184#define trace_argv_printf(argv, ...) \ 185 do { \ 186 if (trace_pass_fl(&trace_default_key)) \ 187 trace_argv_printf_fl(TRACE_CONTEXT, __LINE__, \ 188 argv, __VA_ARGS__); \ 189 } while (0) 190 191/** 192 * trace_strbuf(), accepts "struct trace_key *key, const struct strbuf *data". 193 * 194 * Prints the strbuf, without additional formatting (i.e. doesn't 195 * choke on `%` or even `\0`). 196 */ 197#define trace_strbuf(key, data) \ 198 do { \ 199 if (trace_pass_fl(key)) \ 200 trace_strbuf_fl(TRACE_CONTEXT, __LINE__, key, data);\ 201 } while (0) 202 203/** 204 * trace_performance(), accepts "uint64_t nanos, const char *format, ...". 205 * 206 * Prints elapsed time (in nanoseconds) if GIT_TRACE_PERFORMANCE is enabled. 207 * 208 * Example: 209 * ------------ 210 * uint64_t t = 0; 211 * for (;;) { 212 * // ignore 213 * t -= getnanotime(); 214 * // code section to measure 215 * t += getnanotime(); 216 * // ignore 217 * } 218 * trace_performance(t, "frotz"); 219 * ------------ 220 */ 221#define trace_performance(nanos, ...) \ 222 do { \ 223 if (trace_pass_fl(&trace_perf_key)) \ 224 trace_performance_fl(TRACE_CONTEXT, __LINE__, nanos,\ 225 __VA_ARGS__); \ 226 } while (0) 227 228/** 229 * trace_performance_since(), accepts "uint64_t start, const char *format, ...". 230 * 231 * Prints elapsed time since 'start' if GIT_TRACE_PERFORMANCE is enabled. 232 * 233 * Example: 234 * ------------ 235 * uint64_t start = getnanotime(); 236 * // code section to measure 237 * trace_performance_since(start, "foobar"); 238 * ------------ 239 */ 240#define trace_performance_since(start, ...) \ 241 do { \ 242 if (trace_pass_fl(&trace_perf_key)) \ 243 trace_performance_fl(TRACE_CONTEXT, __LINE__, \ 244 getnanotime() - (start), \ 245 __VA_ARGS__); \ 246 } while (0) 247 248/** 249 * trace_performance_leave(), accepts "const char *format, ...". 250 */ 251#define trace_performance_leave(...) \ 252 do { \ 253 if (trace_pass_fl(&trace_perf_key)) \ 254 trace_performance_leave_fl(TRACE_CONTEXT, __LINE__, \ 255 getnanotime(), \ 256 __VA_ARGS__); \ 257 } while (0) 258 259/* backend functions, use non-*fl macros instead */ 260__attribute__((format (printf, 4, 5))) 261void trace_printf_key_fl(const char *file, int line, struct trace_key *key, 262 const char *format, ...); 263__attribute__((format (printf, 4, 5))) 264void trace_argv_printf_fl(const char *file, int line, const char **argv, 265 const char *format, ...); 266void trace_strbuf_fl(const char *file, int line, struct trace_key *key, 267 const struct strbuf *data); 268__attribute__((format (printf, 4, 5))) 269void trace_performance_fl(const char *file, int line, 270 uint64_t nanos, const char *fmt, ...); 271__attribute__((format (printf, 4, 5))) 272void trace_performance_leave_fl(const char *file, int line, 273 uint64_t nanos, const char *fmt, ...); 274static inline int trace_pass_fl(struct trace_key *key) 275{ 276 return key->fd || !key->initialized; 277} 278 279#endif /* TRACE_H */