Skip to content

Commit

Permalink
trace2: use system config for default trace2 settings
Browse files Browse the repository at this point in the history
Teach git to read the system config (usually "/etc/gitconfig") for
default Trace2 settings.  This allows system-wide Trace2 settings to
be installed and inherited to make it easier to manage a collection of
systems.

The original GIT_TR2* environment variables are loaded afterwards and
can be used to override the system settings.

Only the system config file is used.  Trace2 config values are ignored
in local, global, and other config files.  Likewise, the "-c" command
line arguments are ignored for Trace2 values.  These limits are for
performance reasons.

(1) For users not using Trace2, there should be minimal overhead to
detect that Trace2 is not enabled.  In particular, Trace2 should not
allocate lots of otherwise unused data strucutres.

(2) For accurate performance measurements, Trace2 should be initialized
as early in the git process as possible, and before most of the normal
git process initialization (which involves discovering the .git directory
and reading a hierarchy of config files).

Added the GIT_TEST_TR2_SYSTEM_CONFIG environment variable for testing
purposes to specify the pathname of a fake "system" config or disable
use of the system config.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
  • Loading branch information
jeffhostetler committed Mar 28, 2019
1 parent d4023ac commit 7e0d4e2
Show file tree
Hide file tree
Showing 15 changed files with 356 additions and 55 deletions.
31 changes: 31 additions & 0 deletions Documentation/technical/api-trace2.txt
Expand Up @@ -117,6 +117,37 @@ values are recognized.
Socket type can be either `stream` or `dgram`. If the socket type is
omitted, Git will try both.

== Trace2 Settings in System Config

Trace2 also reads configuration information from the system config.
This is intended to help adminstrators to gather system-wide Git
performance data.

Trace2 only reads the system configuration, it does not read global,
local, worktree, or `-c` config settings.

Trace2 will try to load the following system configuration settings
and then read the corresponding environment variables at startup.

....
---------------------------------------------------
trace2.normalTarget GIT_TR2
trace2.normalBrief GIT_TR2_BRIEF

trace2.perfTarget GIT_TR2_PERF
trace2.perfBrief GIT_TR2_PERF_BRIEF

trace2.eventTarget GIT_TR2_EVENT
trace2.eventBrief GIT_TR2_EVENT_BRIEF
trace2.eventNesting GIT_TR2_EVENT_NESTING

trace2.configParams GIT_TR2_CONFIG_PARAMS

trace2.destinationDebug GIT_TR2_DST_DEBUG
---------------------------------------------------
....


== Trace2 API

All public Trace2 functions and macros are defined in `trace2.h` and
Expand Down
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -1005,6 +1005,7 @@ LIB_OBJS += trace2/tr2_cfg.o
LIB_OBJS += trace2/tr2_cmd_name.o
LIB_OBJS += trace2/tr2_dst.o
LIB_OBJS += trace2/tr2_sid.o
LIB_OBJS += trace2/tr2_sysenv.o
LIB_OBJS += trace2/tr2_tbuf.o
LIB_OBJS += trace2/tr2_tgt_event.o
LIB_OBJS += trace2/tr2_tgt_normal.o
Expand Down
41 changes: 36 additions & 5 deletions t/t0210-trace2-normal.sh
@@ -1,5 +1,14 @@
#!/bin/sh

# Disable loading of Trace2 settings from the system config
# (usually "/etc/gitconfig") to eliminate system dependencies.
GIT_TEST_TR2_SYSTEM_CONFIG=0 && export GIT_TEST_TR2_SYSTEM_CONFIG

# Turn off any inherited trace2 settings for this test.
unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT
unset GIT_TR2_BRIEF
unset GIT_TR2_CONFIG_PARAMS

test_description='test trace2 facility (normal target)'
. ./test-lib.sh

Expand All @@ -15,11 +24,6 @@ PATH="$TTDIR:$PATH" && export PATH
# Warning: So you may see extra lines in artifact files when
# Warning: interactively debugging.

# Turn off any inherited trace2 settings for this test.
unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT
unset GIT_TR2_BRIEF
unset GIT_TR2_CONFIG_PARAMS

V=$(git version | sed -e 's/^git version //') && export V

# There are multiple trace2 targets: normal, perf, and event.
Expand Down Expand Up @@ -132,4 +136,31 @@ test_expect_success 'normal stream, error event' '
test_cmp expect actual
'

# Now test using system config by using a mocked up config file
# rather than inheriting "/etc/gitconfig". Here we do not use
# GIT_TR2* environment variables.

unset GIT_TR2_BRIEF

MOCK=./mock_system_config

test_expect_success 'setup mocked /etc/gitconfig' '
git config --file $MOCK trace2.normalTarget "$(pwd)/trace.normal" &&
git config --file $MOCK trace2.normalBrief 1
'

test_expect_success 'using mock, normal stream, return code 0' '
test_when_finished "rm trace.normal actual expect" &&
GIT_TEST_TR2_SYSTEM_CONFIG="$MOCK" test-tool trace2 001return 0 &&
perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
cat >expect <<-EOF &&
version $V
start _EXE_ trace2 001return 0
cmd_name trace2 (trace2)
exit elapsed:_TIME_ code:0
atexit elapsed:_TIME_ code:0
EOF
test_cmp expect actual
'

test_done
41 changes: 36 additions & 5 deletions t/t0211-trace2-perf.sh
@@ -1,5 +1,14 @@
#!/bin/sh

# Disable loading of Trace2 settings from the system config
# (usually "/etc/gitconfig") to eliminate system dependencies.
GIT_TEST_TR2_SYSTEM_CONFIG=0 && export GIT_TEST_TR2_SYSTEM_CONFIG

# Turn off any inherited trace2 settings for this test.
unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT
unset GIT_TR2_PERF_BRIEF
unset GIT_TR2_CONFIG_PARAMS

test_description='test trace2 facility (perf target)'
. ./test-lib.sh

Expand All @@ -15,11 +24,6 @@ PATH="$TTDIR:$PATH" && export PATH
# Warning: So you may see extra lines in artifact files when
# Warning: interactively debugging.

# Turn off any inherited trace2 settings for this test.
unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT
unset GIT_TR2_PERF_BRIEF
unset GIT_TR2_CONFIG_PARAMS

V=$(git version | sed -e 's/^git version //') && export V

# There are multiple trace2 targets: normal, perf, and event.
Expand Down Expand Up @@ -150,4 +154,31 @@ test_expect_success 'perf stream, child processes' '
test_cmp expect actual
'

# Now test using system config by using a mocked up config file
# rather than inheriting "/etc/gitconfig". Here we do not use
# GIT_TR2* environment variables.

unset GIT_TR2_PERF_BRIEF

MOCK=./mock_system_config

test_expect_success 'setup mocked /etc/gitconfig' '
git config --file $MOCK trace2.perfTarget "$(pwd)/trace.perf" &&
git config --file $MOCK trace2.perfBrief 1
'

test_expect_success 'using mock, perf stream, return code 0' '
test_when_finished "rm trace.perf actual expect" &&
GIT_TEST_TR2_SYSTEM_CONFIG="$MOCK" test-tool trace2 001return 0 &&
perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual &&
cat >expect <<-EOF &&
d0|main|version|||||$V
d0|main|start||_T_ABS_|||_EXE_ trace2 001return 0
d0|main|cmd_name|||||trace2 (trace2)
d0|main|exit||_T_ABS_|||code:0
d0|main|atexit||_T_ABS_|||code:0
EOF
test_cmp expect actual
'

test_done
52 changes: 47 additions & 5 deletions t/t0212-trace2-event.sh
@@ -1,5 +1,14 @@
#!/bin/sh

# Disable loading of Trace2 settings from the system config
# (usually "/etc/gitconfig") to eliminate system dependencies.
GIT_TEST_TR2_SYSTEM_CONFIG=0 && export GIT_TEST_TR2_SYSTEM_CONFIG

# Turn off any inherited trace2 settings for this test.
unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT
unset GIT_TR2_BARE
unset GIT_TR2_CONFIG_PARAMS

test_description='test trace2 facility'
. ./test-lib.sh

Expand All @@ -17,11 +26,6 @@ PATH="$TTDIR:$PATH" && export PATH
# Warning: So you may see extra lines in artifact files when
# Warning: interactively debugging.

# Turn off any inherited trace2 settings for this test.
unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT
unset GIT_TR2_BARE
unset GIT_TR2_CONFIG_PARAMS

V=$(git version | sed -e 's/^git version //') && export V

# There are multiple trace2 targets: normal, perf, and event.
Expand Down Expand Up @@ -233,4 +237,42 @@ test_expect_success JSON_PP 'basic trace2_data' '
test_cmp expect actual
'

# Now test using system config by using a mocked up config file
# rather than inheriting "/etc/gitconfig". Here we do not use
# GIT_TR2* environment variables.

MOCK=./mock_system_config

test_expect_success 'setup mocked /etc/gitconfig' '
git config --file $MOCK trace2.eventTarget "$(pwd)/trace.event"
'

test_expect_success JSON_PP 'using mock, event stream, error event' '
test_when_finished "rm trace.event actual expect" &&
GIT_TEST_TR2_SYSTEM_CONFIG="$MOCK" test-tool trace2 003error "hello world" "this is a test" &&
perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual &&
sed -e "s/^|//" >expect <<-EOF &&
|VAR1 = {
| "_SID0_":{
| "argv":[
| "_EXE_",
| "trace2",
| "003error",
| "hello world",
| "this is a test"
| ],
| "errors":[
| "%s",
| "%s"
| ],
| "exit_code":0,
| "hierarchy":"trace2",
| "name":"trace2",
| "version":"$V"
| }
|};
EOF
test_cmp expect actual
'

test_done
4 changes: 4 additions & 0 deletions trace2.c
Expand Up @@ -10,6 +10,7 @@
#include "trace2/tr2_cmd_name.h"
#include "trace2/tr2_dst.h"
#include "trace2/tr2_sid.h"
#include "trace2/tr2_sysenv.h"
#include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h"

Expand Down Expand Up @@ -120,6 +121,7 @@ static void tr2main_atexit_handler(void)
tr2_sid_release();
tr2_cmd_name_release();
tr2_cfg_free_patterns();
tr2_sysenv_release();

trace2_enabled = 0;
}
Expand Down Expand Up @@ -155,6 +157,8 @@ void trace2_initialize_fl(const char *file, int line)
if (trace2_enabled)
return;

tr2_sysenv_load();

if (!tr2_tgt_want_builtins())
return;
trace2_enabled = 1;
Expand Down
7 changes: 4 additions & 3 deletions trace2.h
Expand Up @@ -38,7 +38,8 @@ void trace2_initialize_clock(void);

/*
* Initialize TRACE2 tracing facility if any of the builtin TRACE2
* targets are enabled in the environment. Emits a 'version' event.
* targets are enabled in the system config or the environment.
* Emits a 'version' event.
*
* Cleanup/Termination is handled automatically by a registered
* atexit() routine.
Expand Down Expand Up @@ -125,8 +126,8 @@ void trace2_cmd_alias_fl(const char *file, int line, const char *alias,
* Emit one or more 'def_param' events for "interesting" configuration
* settings.
*
* The environment variable "GIT_TR2_CONFIG_PARAMS" can be set to a
* list of patterns considered important. For example:
* Use the TR2_SYSENV_CFG_PARAM setting to register a list of patterns
* configured important. For example:
*
* GIT_TR2_CONFIG_PARAMS="core.*,remote.*.url"
*
Expand Down
7 changes: 3 additions & 4 deletions trace2/tr2_cfg.c
@@ -1,8 +1,7 @@
#include "cache.h"
#include "config.h"
#include "tr2_cfg.h"

#define TR2_ENVVAR_CFG_PARAM "GIT_TR2_CONFIG_PARAMS"
#include "trace2/tr2_cfg.h"
#include "trace2/tr2_sysenv.h"

static struct strbuf **tr2_cfg_patterns;
static int tr2_cfg_count_patterns;
Expand All @@ -21,7 +20,7 @@ static int tr2_cfg_load_patterns(void)
return tr2_cfg_count_patterns;
tr2_cfg_loaded = 1;

envvar = getenv(TR2_ENVVAR_CFG_PARAM);
envvar = tr2_sysenv_get(TR2_SYSENV_CFG_PARAM);
if (!envvar || !*envvar)
return tr2_cfg_count_patterns;

Expand Down
24 changes: 12 additions & 12 deletions trace2/tr2_dst.c
@@ -1,23 +1,20 @@
#include "cache.h"
#include "trace2/tr2_dst.h"
#include "trace2/tr2_sysenv.h"

/*
* If a Trace2 target cannot be opened for writing, we should issue a
* warning to stderr, but this is very annoying if the target is a pipe
* or socket and beyond the user's control -- especially since every
* git command (and sub-command) will print the message. So we silently
* eat these warnings and just discard the trace data.
*
* Enable the following environment variable to see these warnings.
*/
#define TR2_ENVVAR_DST_DEBUG "GIT_TR2_DST_DEBUG"

static int tr2_dst_want_warning(void)
{
static int tr2env_dst_debug = -1;

if (tr2env_dst_debug == -1) {
const char *env_value = getenv(TR2_ENVVAR_DST_DEBUG);
const char *env_value = tr2_sysenv_get(TR2_SYSENV_DST_DEBUG);
if (!env_value || !*env_value)
tr2env_dst_debug = 0;
else
Expand All @@ -42,7 +39,9 @@ static int tr2_dst_try_path(struct tr2_dst *dst, const char *tgt_value)
if (fd == -1) {
if (tr2_dst_want_warning())
warning("trace2: could not open '%s' for '%s' tracing: %s",
tgt_value, dst->env_var_name, strerror(errno));
tgt_value,
tr2_sysenv_display_name(dst->sysenv_var),
strerror(errno));

tr2_dst_trace_disable(dst);
return 0;
Expand Down Expand Up @@ -116,7 +115,7 @@ static int tr2_dst_try_unix_domain_socket(struct tr2_dst *dst,
if (!path || !*path) {
if (tr2_dst_want_warning())
warning("trace2: invalid AF_UNIX value '%s' for '%s' tracing",
tgt_value, dst->env_var_name);
tgt_value, tr2_sysenv_display_name(dst->sysenv_var));

tr2_dst_trace_disable(dst);
return 0;
Expand All @@ -126,7 +125,7 @@ static int tr2_dst_try_unix_domain_socket(struct tr2_dst *dst,
strlen(path) >= sizeof(((struct sockaddr_un *)0)->sun_path)) {
if (tr2_dst_want_warning())
warning("trace2: invalid AF_UNIX path '%s' for '%s' tracing",
path, dst->env_var_name);
path, tr2_sysenv_display_name(dst->sysenv_var));

tr2_dst_trace_disable(dst);
return 0;
Expand All @@ -148,7 +147,7 @@ static int tr2_dst_try_unix_domain_socket(struct tr2_dst *dst,
error:
if (tr2_dst_want_warning())
warning("trace2: could not connect to socket '%s' for '%s' tracing: %s",
path, dst->env_var_name, strerror(e));
path, tr2_sysenv_display_name(dst->sysenv_var), strerror(e));

tr2_dst_trace_disable(dst);
return 0;
Expand All @@ -168,7 +167,7 @@ static void tr2_dst_malformed_warning(struct tr2_dst *dst,
struct strbuf buf = STRBUF_INIT;

strbuf_addf(&buf, "trace2: unknown value for '%s': '%s'",
dst->env_var_name, tgt_value);
tr2_sysenv_display_name(dst->sysenv_var), tgt_value);
warning("%s", buf.buf);

strbuf_release(&buf);
Expand All @@ -184,7 +183,7 @@ int tr2_dst_get_trace_fd(struct tr2_dst *dst)

dst->initialized = 1;

tgt_value = getenv(dst->env_var_name);
tgt_value = tr2_sysenv_get(dst->sysenv_var);

if (!tgt_value || !strcmp(tgt_value, "") || !strcmp(tgt_value, "0") ||
!strcasecmp(tgt_value, "false")) {
Expand Down Expand Up @@ -246,7 +245,8 @@ void tr2_dst_write_line(struct tr2_dst *dst, struct strbuf *buf_line)
return;

if (tr2_dst_want_warning())
warning("unable to write trace to '%s': %s", dst->env_var_name,
warning("unable to write trace to '%s': %s",
tr2_sysenv_display_name(dst->sysenv_var),
strerror(errno));
tr2_dst_trace_disable(dst);
}

0 comments on commit 7e0d4e2

Please sign in to comment.