]>
Commit | Line | Data |
---|---|---|
6b5c0886 | 1 | #include "clar_libgit2_trace.h" |
22a2d3d5 | 2 | #include "clar_libgit2.h" |
9a859ef5 | 3 | #include "clar_libgit2_timer.h" |
6b5c0886 JH |
4 | #include "trace.h" |
5 | ||
6b5c0886 JH |
6 | struct method { |
7 | const char *name; | |
8 | void (*git_trace_cb)(git_trace_level_t level, const char *msg); | |
9 | void (*close)(void); | |
10 | }; | |
11 | ||
22a2d3d5 UG |
12 | static const char *message_prefix(git_trace_level_t level) |
13 | { | |
14 | switch (level) { | |
15 | case GIT_TRACE_NONE: | |
16 | return "[NONE]: "; | |
17 | case GIT_TRACE_FATAL: | |
18 | return "[FATAL]: "; | |
19 | case GIT_TRACE_ERROR: | |
20 | return "[ERROR]: "; | |
21 | case GIT_TRACE_WARN: | |
22 | return "[WARN]: "; | |
23 | case GIT_TRACE_INFO: | |
24 | return "[INFO]: "; | |
25 | case GIT_TRACE_DEBUG: | |
26 | return "[DEBUG]: "; | |
27 | case GIT_TRACE_TRACE: | |
28 | return "[TRACE]: "; | |
29 | default: | |
30 | return "[?????]: "; | |
31 | } | |
32 | } | |
6b5c0886 | 33 | |
6b5c0886 JH |
34 | static void _git_trace_cb__printf(git_trace_level_t level, const char *msg) |
35 | { | |
22a2d3d5 | 36 | printf("%s%s\n", message_prefix(level), msg); |
6b5c0886 JH |
37 | } |
38 | ||
39 | #if defined(GIT_WIN32) | |
40 | static void _git_trace_cb__debug(git_trace_level_t level, const char *msg) | |
41 | { | |
22a2d3d5 | 42 | OutputDebugString(message_prefix(level)); |
6b5c0886 JH |
43 | OutputDebugString(msg); |
44 | OutputDebugString("\n"); | |
45 | ||
22a2d3d5 | 46 | printf("%s%s\n", message_prefix(level), msg); |
6b5c0886 JH |
47 | } |
48 | #else | |
49 | #define _git_trace_cb__debug _git_trace_cb__printf | |
50 | #endif | |
51 | ||
52 | ||
53 | static void _trace_printf_close(void) | |
54 | { | |
55 | fflush(stdout); | |
56 | } | |
57 | ||
58 | #define _trace_debug_close _trace_printf_close | |
59 | ||
60 | ||
61 | static struct method s_methods[] = { | |
62 | { "printf", _git_trace_cb__printf, _trace_printf_close }, | |
63 | { "debug", _git_trace_cb__debug, _trace_debug_close }, | |
64 | /* TODO add file method */ | |
65 | {0}, | |
66 | }; | |
67 | ||
68 | ||
69 | static int s_trace_loaded = 0; | |
70 | static int s_trace_level = GIT_TRACE_NONE; | |
71 | static struct method *s_trace_method = NULL; | |
22a2d3d5 | 72 | static int s_trace_tests = 0; |
6b5c0886 JH |
73 | |
74 | static int set_method(const char *name) | |
75 | { | |
76 | int k; | |
77 | ||
78 | if (!name || !*name) | |
79 | name = "printf"; | |
80 | ||
81 | for (k=0; (s_methods[k].name); k++) { | |
82 | if (strcmp(name, s_methods[k].name) == 0) { | |
83 | s_trace_method = &s_methods[k]; | |
84 | return 0; | |
85 | } | |
86 | } | |
87 | fprintf(stderr, "Unknown CLAR_TRACE_METHOD: '%s'\n", name); | |
88 | return -1; | |
89 | } | |
90 | ||
91 | ||
92 | /** | |
93 | * Lookup CLAR_TRACE_LEVEL and CLAR_TRACE_METHOD from | |
94 | * the environment and set the above s_trace_* fields. | |
95 | * | |
96 | * If CLAR_TRACE_LEVEL is not set, we disable tracing. | |
97 | * | |
98 | * TODO If set, we assume GIT_TRACE_TRACE level, which | |
99 | * logs everything. Later, we may want to parse the | |
100 | * value of the environment variable and set a specific | |
101 | * level. | |
102 | * | |
103 | * We assume the "printf" method. This can be changed | |
104 | * with the CLAR_TRACE_METHOD environment variable. | |
105 | * Currently, this is only needed on Windows for a "debug" | |
106 | * version which also writes to the debug output window | |
107 | * in Visual Studio. | |
108 | * | |
109 | * TODO add a "file" method that would open and write | |
110 | * to a well-known file. This would help keep trace | |
111 | * output and clar output separate. | |
112 | * | |
113 | */ | |
114 | static void _load_trace_params(void) | |
115 | { | |
116 | char *sz_level; | |
117 | char *sz_method; | |
22a2d3d5 | 118 | char *sz_tests; |
6b5c0886 JH |
119 | |
120 | s_trace_loaded = 1; | |
121 | ||
122 | sz_level = cl_getenv("CLAR_TRACE_LEVEL"); | |
123 | if (!sz_level || !*sz_level) { | |
124 | s_trace_level = GIT_TRACE_NONE; | |
125 | s_trace_method = NULL; | |
126 | return; | |
127 | } | |
128 | ||
129 | /* TODO Parse sz_level and set s_trace_level. */ | |
130 | s_trace_level = GIT_TRACE_TRACE; | |
131 | ||
132 | sz_method = cl_getenv("CLAR_TRACE_METHOD"); | |
133 | if (set_method(sz_method) < 0) | |
134 | set_method(NULL); | |
22a2d3d5 UG |
135 | |
136 | sz_tests = cl_getenv("CLAR_TRACE_TESTS"); | |
137 | if (sz_tests != NULL) | |
138 | s_trace_tests = 1; | |
6b5c0886 JH |
139 | } |
140 | ||
141 | #define HR "================================================================" | |
142 | ||
9a859ef5 JH |
143 | /** |
144 | * Timer to report the take spend in a test's run() method. | |
145 | */ | |
146 | static cl_perf_timer s_timer_run = CL_PERF_TIMER_INIT; | |
147 | ||
148 | /** | |
149 | * Timer to report total time in a test (init, run, cleanup). | |
150 | */ | |
151 | static cl_perf_timer s_timer_test = CL_PERF_TIMER_INIT; | |
152 | ||
e579e0f7 | 153 | static void _cl_trace_cb__event_handler( |
6b5c0886 JH |
154 | cl_trace_event ev, |
155 | const char *suite_name, | |
156 | const char *test_name, | |
157 | void *payload) | |
158 | { | |
159 | GIT_UNUSED(payload); | |
160 | ||
22a2d3d5 UG |
161 | if (!s_trace_tests) |
162 | return; | |
163 | ||
6b5c0886 JH |
164 | switch (ev) { |
165 | case CL_TRACE__SUITE_BEGIN: | |
f096fbf4 | 166 | git_trace(GIT_TRACE_TRACE, "\n\n%s\n%s: Begin Suite", HR, suite_name); |
c25aa7cd | 167 | #if 0 && defined(GIT_WIN32_LEAKCHECK) |
93b42728 JH |
168 | git_win32__crtdbg_stacktrace__dump( |
169 | GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK, | |
170 | suite_name); | |
171 | #endif | |
6b5c0886 JH |
172 | break; |
173 | ||
174 | case CL_TRACE__SUITE_END: | |
c25aa7cd | 175 | #if 0 && defined(GIT_WIN32_LEAKCHECK) |
93b42728 JH |
176 | /* As an example of checkpointing, dump leaks within this suite. |
177 | * This may generate false positives for things like the global | |
178 | * TLS error state and maybe the odb cache since they aren't | |
179 | * freed until the global shutdown and outside the scope of this | |
180 | * set of tests. | |
181 | * | |
182 | * This may under-report if the test itself uses a checkpoint. | |
183 | * See tests/trace/windows/stacktrace.c | |
184 | */ | |
185 | git_win32__crtdbg_stacktrace__dump( | |
186 | GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK, | |
187 | suite_name); | |
188 | #endif | |
f096fbf4 | 189 | git_trace(GIT_TRACE_TRACE, "\n\n%s: End Suite\n%s", suite_name, HR); |
6b5c0886 JH |
190 | break; |
191 | ||
192 | case CL_TRACE__TEST__BEGIN: | |
f096fbf4 | 193 | git_trace(GIT_TRACE_TRACE, "\n%s::%s: Begin Test", suite_name, test_name); |
9a859ef5 JH |
194 | cl_perf_timer__init(&s_timer_test); |
195 | cl_perf_timer__start(&s_timer_test); | |
6b5c0886 JH |
196 | break; |
197 | ||
198 | case CL_TRACE__TEST__END: | |
9a859ef5 JH |
199 | cl_perf_timer__stop(&s_timer_test); |
200 | git_trace(GIT_TRACE_TRACE, "%s::%s: End Test (%.3f %.3f)", suite_name, test_name, | |
201 | cl_perf_timer__last(&s_timer_run), | |
202 | cl_perf_timer__last(&s_timer_test)); | |
6b5c0886 JH |
203 | break; |
204 | ||
205 | case CL_TRACE__TEST__RUN_BEGIN: | |
f096fbf4 | 206 | git_trace(GIT_TRACE_TRACE, "%s::%s: Begin Run", suite_name, test_name); |
9a859ef5 JH |
207 | cl_perf_timer__init(&s_timer_run); |
208 | cl_perf_timer__start(&s_timer_run); | |
6b5c0886 JH |
209 | break; |
210 | ||
211 | case CL_TRACE__TEST__RUN_END: | |
9a859ef5 | 212 | cl_perf_timer__stop(&s_timer_run); |
f096fbf4 | 213 | git_trace(GIT_TRACE_TRACE, "%s::%s: End Run", suite_name, test_name); |
6b5c0886 JH |
214 | break; |
215 | ||
216 | case CL_TRACE__TEST__LONGJMP: | |
9a859ef5 | 217 | cl_perf_timer__stop(&s_timer_run); |
f096fbf4 | 218 | git_trace(GIT_TRACE_TRACE, "%s::%s: Aborted", suite_name, test_name); |
6b5c0886 JH |
219 | break; |
220 | ||
221 | default: | |
222 | break; | |
223 | } | |
224 | } | |
225 | ||
6b5c0886 JH |
226 | /** |
227 | * Setup/Enable git_trace() based upon settings user's environment. | |
6b5c0886 JH |
228 | */ |
229 | void cl_global_trace_register(void) | |
230 | { | |
6b5c0886 JH |
231 | if (!s_trace_loaded) |
232 | _load_trace_params(); | |
233 | ||
234 | if (s_trace_level == GIT_TRACE_NONE) | |
235 | return; | |
236 | if (s_trace_method == NULL) | |
237 | return; | |
238 | if (s_trace_method->git_trace_cb == NULL) | |
239 | return; | |
240 | ||
241 | git_trace_set(s_trace_level, s_trace_method->git_trace_cb); | |
242 | cl_trace_register(_cl_trace_cb__event_handler, NULL); | |
6b5c0886 JH |
243 | } |
244 | ||
245 | /** | |
246 | * If we turned on git_trace() earlier, turn it off. | |
247 | * | |
248 | * This is intended to let us close/flush any buffered | |
249 | * IO if necessary. | |
250 | * | |
251 | */ | |
252 | void cl_global_trace_disable(void) | |
253 | { | |
6b5c0886 JH |
254 | cl_trace_register(NULL, NULL); |
255 | git_trace_set(GIT_TRACE_NONE, NULL); | |
256 | if (s_trace_method && s_trace_method->close) | |
257 | s_trace_method->close(); | |
258 | ||
259 | /* Leave s_trace_ vars set so they can restart tracing | |
260 | * since we only want to hit the environment variables | |
261 | * once. | |
262 | */ | |
6b5c0886 | 263 | } |