Skip to content

Commit 6f83a78

Browse files
author
Vicent Martí
committed
Merge pull request nodegit#1403 from ethomson/tracing
Optional tracing back to consumers
2 parents 33abaad + b5ec543 commit 6f83a78

5 files changed

Lines changed: 255 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ OPTION( BUILD_CLAR "Build Tests using the Clar suite" ON )
2222
OPTION( BUILD_EXAMPLES "Build library usage example apps" OFF )
2323
OPTION( TAGS "Generate tags" OFF )
2424
OPTION( PROFILE "Generate profiling information" OFF )
25+
OPTION( ENABLE_TRACE "Enables tracing support" OFF )
2526
IF(MSVC)
2627
# This option is only availalbe when building with MSVC. By default,
2728
# libgit2 is build using the stdcall calling convention, as that's what
@@ -105,6 +106,11 @@ ELSE()
105106
FILE(GLOB SRC_SHA1 src/hash/hash_generic.c)
106107
ENDIF()
107108

109+
# Enable tracing
110+
IF (ENABLE_TRACE STREQUAL "ON")
111+
ADD_DEFINITIONS(-DGIT_TRACE)
112+
ENDIF()
113+
108114
# Include POSIX regex when it is required
109115
IF(WIN32 OR AMIGA)
110116
INCLUDE_DIRECTORIES(deps/regex)

include/git2/trace.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
#ifndef INCLUDE_git_trace_h__
8+
#define INCLUDE_git_trace_h__
9+
10+
#include "common.h"
11+
#include "types.h"
12+
13+
/**
14+
* @file git2/trace.h
15+
* @brief Git tracing configuration routines
16+
* @defgroup git_trace Git tracing configuration routines
17+
* @ingroup Git
18+
* @{
19+
*/
20+
GIT_BEGIN_DECL
21+
22+
/**
23+
* Available tracing levels. When tracing is set to a particular level,
24+
* callers will be provided tracing at the given level and all lower levels.
25+
*/
26+
typedef enum {
27+
/** No tracing will be performed. */
28+
GIT_TRACE_NONE = 0,
29+
30+
/** Severe errors that may impact the program's execution */
31+
GIT_TRACE_FATAL = 1,
32+
33+
/** Errors that do not impact the program's execution */
34+
GIT_TRACE_ERROR = 2,
35+
36+
/** Warnings that suggest abnormal data */
37+
GIT_TRACE_WARN = 3,
38+
39+
/** Informational messages about program execution */
40+
GIT_TRACE_INFO = 4,
41+
42+
/** Detailed data that allows for debugging */
43+
GIT_TRACE_DEBUG = 5,
44+
45+
/** Exceptionally detailed debugging data */
46+
GIT_TRACE_TRACE = 6
47+
} git_trace_level_t;
48+
49+
/**
50+
* An instance for a tracing function
51+
*/
52+
typedef void (*git_trace_callback)(git_trace_level_t level, const char *msg);
53+
54+
/**
55+
* Sets the system tracing configuration to the specified level with the
56+
* specified callback. When system events occur at a level equal to, or
57+
* lower than, the given level they will be reported to the given callback.
58+
*
59+
* @param level Level to set tracing to
60+
* @param cb Function to call with trace data
61+
* @return 0 or an error code
62+
*/
63+
GIT_EXTERN(int) git_trace_set(git_trace_level_t level, git_trace_callback cb);
64+
65+
/** @} */
66+
GIT_END_DECL
67+
#endif
68+

src/trace.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include "buffer.h"
9+
#include "common.h"
10+
#include "global.h"
11+
#include "trace.h"
12+
#include "git2/trace.h"
13+
14+
#ifdef GIT_TRACE
15+
16+
struct git_trace_data git_trace__data = {0};
17+
18+
#endif
19+
20+
int git_trace_set(git_trace_level_t level, git_trace_callback callback)
21+
{
22+
#ifdef GIT_TRACE
23+
assert(level == 0 || callback != NULL);
24+
25+
git_trace__data.level = level;
26+
git_trace__data.callback = callback;
27+
GIT_MEMORY_BARRIER;
28+
29+
return 0;
30+
#else
31+
GIT_UNUSED(level);
32+
GIT_UNUSED(callback);
33+
34+
giterr_set(GITERR_INVALID,
35+
"This version of libgit2 was not built with tracing.");
36+
return -1;
37+
#endif
38+
}
39+

src/trace.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
#ifndef INCLUDE_trace_h__
8+
#define INCLUDE_trace_h__
9+
10+
#include <stdarg.h>
11+
12+
#include <git2/trace.h>
13+
#include "buffer.h"
14+
15+
#ifdef GIT_TRACE
16+
17+
struct git_trace_data {
18+
git_trace_level_t level;
19+
git_trace_callback callback;
20+
};
21+
22+
extern struct git_trace_data git_trace__data;
23+
24+
GIT_INLINE(void) git_trace__write_fmt(
25+
git_trace_level_t level,
26+
const char *fmt, ...)
27+
{
28+
git_trace_callback callback = git_trace__data.callback;
29+
git_buf message = GIT_BUF_INIT;
30+
va_list ap;
31+
32+
va_start(ap, fmt);
33+
git_buf_vprintf(&message, fmt, ap);
34+
va_end(ap);
35+
36+
callback(level, git_buf_cstr(&message));
37+
38+
git_buf_free(&message);
39+
}
40+
41+
#define git_trace_level() (git_trace__data.level)
42+
#define git_trace(l, ...) { \
43+
if (git_trace__data.level >= l && \
44+
git_trace__data.callback != NULL) { \
45+
git_trace__write_fmt(l, __VA_ARGS__); \
46+
} \
47+
}
48+
49+
#else
50+
51+
#define git_trace_level() ((void)0)
52+
#define git_trace(lvl, ...) ((void)0)
53+
54+
#endif
55+
56+
#endif

tests-clar/trace/trace.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include "clar_libgit2.h"
2+
#include "trace.h"
3+
4+
static int written = 0;
5+
6+
static void trace_callback(git_trace_level_t level, const char *message)
7+
{
8+
cl_assert(strcmp(message, "Hello world!") == 0);
9+
10+
written = 1;
11+
}
12+
13+
void test_trace_trace__initialize(void)
14+
{
15+
git_trace_set(GIT_TRACE_INFO, trace_callback);
16+
written = 0;
17+
}
18+
19+
void test_trace_trace__cleanup(void)
20+
{
21+
git_trace_set(GIT_TRACE_NONE, NULL);
22+
}
23+
24+
void test_trace_trace__sets(void)
25+
{
26+
#ifdef GIT_TRACE
27+
cl_assert(git_trace_level() == GIT_TRACE_INFO);
28+
#endif
29+
}
30+
31+
void test_trace_trace__can_reset(void)
32+
{
33+
#ifdef GIT_TRACE
34+
cl_assert(git_trace_level() == GIT_TRACE_INFO);
35+
cl_git_pass(git_trace_set(GIT_TRACE_ERROR, trace_callback));
36+
37+
cl_assert(written == 0);
38+
git_trace(GIT_TRACE_INFO, "Hello %s!", "world");
39+
cl_assert(written == 0);
40+
41+
git_trace(GIT_TRACE_ERROR, "Hello %s!", "world");
42+
cl_assert(written == 1);
43+
#endif
44+
}
45+
46+
void test_trace_trace__can_unset(void)
47+
{
48+
#ifdef GIT_TRACE
49+
cl_assert(git_trace_level() == GIT_TRACE_INFO);
50+
cl_git_pass(git_trace_set(GIT_TRACE_NONE, NULL));
51+
52+
cl_assert(git_trace_level() == GIT_TRACE_NONE);
53+
54+
cl_assert(written == 0);
55+
git_trace(GIT_TRACE_FATAL, "Hello %s!", "world");
56+
cl_assert(written == 0);
57+
#endif
58+
}
59+
60+
void test_trace_trace__skips_higher_level(void)
61+
{
62+
#ifdef GIT_TRACE
63+
cl_assert(written == 0);
64+
git_trace(GIT_TRACE_DEBUG, "Hello %s!", "world");
65+
cl_assert(written == 0);
66+
#endif
67+
}
68+
69+
void test_trace_trace__writes(void)
70+
{
71+
#ifdef GIT_TRACE
72+
cl_assert(written == 0);
73+
git_trace(GIT_TRACE_INFO, "Hello %s!", "world");
74+
cl_assert(written == 1);
75+
#endif
76+
}
77+
78+
void test_trace_trace__writes_lower_level(void)
79+
{
80+
#ifdef GIT_TRACE
81+
cl_assert(written == 0);
82+
git_trace(GIT_TRACE_ERROR, "Hello %s!", "world");
83+
cl_assert(written == 1);
84+
#endif
85+
}
86+

0 commit comments

Comments
 (0)