1 #include "clar_libgit2.h"
2 #include "clar_libgit2_trace.h"
3 #include "clar_libgit2_timer.h"
9 void (*git_trace_cb
)(git_trace_level_t level
, const char *msg
);
14 #if defined(GIT_TRACE)
15 static void _git_trace_cb__printf(git_trace_level_t level
, const char *msg
)
17 /* TODO Use level to print a per-message prefix. */
23 #if defined(GIT_WIN32)
24 static void _git_trace_cb__debug(git_trace_level_t level
, const char *msg
)
26 /* TODO Use level to print a per-message prefix. */
29 OutputDebugString(msg
);
30 OutputDebugString("\n");
35 #define _git_trace_cb__debug _git_trace_cb__printf
39 static void _trace_printf_close(void)
44 #define _trace_debug_close _trace_printf_close
47 static struct method s_methods
[] = {
48 { "printf", _git_trace_cb__printf
, _trace_printf_close
},
49 { "debug", _git_trace_cb__debug
, _trace_debug_close
},
50 /* TODO add file method */
55 static int s_trace_loaded
= 0;
56 static int s_trace_level
= GIT_TRACE_NONE
;
57 static struct method
*s_trace_method
= NULL
;
60 static int set_method(const char *name
)
67 for (k
=0; (s_methods
[k
].name
); k
++) {
68 if (strcmp(name
, s_methods
[k
].name
) == 0) {
69 s_trace_method
= &s_methods
[k
];
73 fprintf(stderr
, "Unknown CLAR_TRACE_METHOD: '%s'\n", name
);
79 * Lookup CLAR_TRACE_LEVEL and CLAR_TRACE_METHOD from
80 * the environment and set the above s_trace_* fields.
82 * If CLAR_TRACE_LEVEL is not set, we disable tracing.
84 * TODO If set, we assume GIT_TRACE_TRACE level, which
85 * logs everything. Later, we may want to parse the
86 * value of the environment variable and set a specific
89 * We assume the "printf" method. This can be changed
90 * with the CLAR_TRACE_METHOD environment variable.
91 * Currently, this is only needed on Windows for a "debug"
92 * version which also writes to the debug output window
95 * TODO add a "file" method that would open and write
96 * to a well-known file. This would help keep trace
97 * output and clar output separate.
100 static void _load_trace_params(void)
107 sz_level
= cl_getenv("CLAR_TRACE_LEVEL");
108 if (!sz_level
|| !*sz_level
) {
109 s_trace_level
= GIT_TRACE_NONE
;
110 s_trace_method
= NULL
;
114 /* TODO Parse sz_level and set s_trace_level. */
115 s_trace_level
= GIT_TRACE_TRACE
;
117 sz_method
= cl_getenv("CLAR_TRACE_METHOD");
118 if (set_method(sz_method
) < 0)
122 #define HR "================================================================"
125 * Timer to report the take spend in a test's run() method.
127 static cl_perf_timer s_timer_run
= CL_PERF_TIMER_INIT
;
130 * Timer to report total time in a test (init, run, cleanup).
132 static cl_perf_timer s_timer_test
= CL_PERF_TIMER_INIT
;
134 void _cl_trace_cb__event_handler(
136 const char *suite_name
,
137 const char *test_name
,
143 case CL_TRACE__SUITE_BEGIN
:
144 git_trace(GIT_TRACE_TRACE
, "\n\n%s\n%s: Begin Suite", HR
, suite_name
);
145 #if 0 && defined(GIT_MSVC_CRTDBG)
146 git_win32__crtdbg_stacktrace__dump(
147 GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK
,
152 case CL_TRACE__SUITE_END
:
153 #if 0 && defined(GIT_MSVC_CRTDBG)
154 /* As an example of checkpointing, dump leaks within this suite.
155 * This may generate false positives for things like the global
156 * TLS error state and maybe the odb cache since they aren't
157 * freed until the global shutdown and outside the scope of this
160 * This may under-report if the test itself uses a checkpoint.
161 * See tests/trace/windows/stacktrace.c
163 git_win32__crtdbg_stacktrace__dump(
164 GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK
,
167 git_trace(GIT_TRACE_TRACE
, "\n\n%s: End Suite\n%s", suite_name
, HR
);
170 case CL_TRACE__TEST__BEGIN
:
171 git_trace(GIT_TRACE_TRACE
, "\n%s::%s: Begin Test", suite_name
, test_name
);
172 cl_perf_timer__init(&s_timer_test
);
173 cl_perf_timer__start(&s_timer_test
);
176 case CL_TRACE__TEST__END
:
177 cl_perf_timer__stop(&s_timer_test
);
178 git_trace(GIT_TRACE_TRACE
, "%s::%s: End Test (%.3f %.3f)", suite_name
, test_name
,
179 cl_perf_timer__last(&s_timer_run
),
180 cl_perf_timer__last(&s_timer_test
));
183 case CL_TRACE__TEST__RUN_BEGIN
:
184 git_trace(GIT_TRACE_TRACE
, "%s::%s: Begin Run", suite_name
, test_name
);
185 cl_perf_timer__init(&s_timer_run
);
186 cl_perf_timer__start(&s_timer_run
);
189 case CL_TRACE__TEST__RUN_END
:
190 cl_perf_timer__stop(&s_timer_run
);
191 git_trace(GIT_TRACE_TRACE
, "%s::%s: End Run", suite_name
, test_name
);
194 case CL_TRACE__TEST__LONGJMP
:
195 cl_perf_timer__stop(&s_timer_run
);
196 git_trace(GIT_TRACE_TRACE
, "%s::%s: Aborted", suite_name
, test_name
);
207 * Setup/Enable git_trace() based upon settings user's environment.
210 void cl_global_trace_register(void)
212 #if defined(GIT_TRACE)
214 _load_trace_params();
216 if (s_trace_level
== GIT_TRACE_NONE
)
218 if (s_trace_method
== NULL
)
220 if (s_trace_method
->git_trace_cb
== NULL
)
223 git_trace_set(s_trace_level
, s_trace_method
->git_trace_cb
);
224 cl_trace_register(_cl_trace_cb__event_handler
, NULL
);
229 * If we turned on git_trace() earlier, turn it off.
231 * This is intended to let us close/flush any buffered
235 void cl_global_trace_disable(void)
237 #if defined(GIT_TRACE)
238 cl_trace_register(NULL
, NULL
);
239 git_trace_set(GIT_TRACE_NONE
, NULL
);
240 if (s_trace_method
&& s_trace_method
->close
)
241 s_trace_method
->close();
243 /* Leave s_trace_ vars set so they can restart tracing
244 * since we only want to hit the environment variables