From 3d3adaad914441a6e7b916eb8dfd5ae638aab068 Mon Sep 17 00:00:00 2001 From: Josh Steadmon Date: Fri, 20 Mar 2020 14:06:15 -0700 Subject: trace2: teach Git to log environment variables Via trace2, Git can already log interesting config parameters (see the trace2_cmd_list_config() function). However, this can grant an incomplete picture because many config parameters also allow overrides via environment variables. To allow for more complete logs, we add a new trace2_cmd_list_env_vars() function and supporting implementation, modeled after the pre-existing config param logging implementation. Signed-off-by: Josh Steadmon Acked-by: Jeff Hostetler Signed-off-by: Junio C Hamano diff --git a/Documentation/config/trace2.txt b/Documentation/config/trace2.txt index 4ce0b9a..01d3afd 100644 --- a/Documentation/config/trace2.txt +++ b/Documentation/config/trace2.txt @@ -48,6 +48,15 @@ trace2.configParams:: May be overridden by the `GIT_TRACE2_CONFIG_PARAMS` environment variable. Unset by default. +trace2.envVars:: + A comma-separated list of "important" environment variables that should + be recorded in the trace2 output. For example, + `GIT_HTTP_USER_AGENT,GIT_CONFIG` would cause the trace2 output to + contain events listing the overrides for HTTP user agent and the + location of the Git configuration file (assuming any are set). May be + overriden by the `GIT_TRACE2_ENV_VARS` environment variable. Unset by + default. + trace2.destinationDebug:: Boolean. When true Git will print error messages when a trace target destination cannot be opened for writing. diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt index 4f07cea..6b60855 100644 --- a/Documentation/technical/api-trace2.txt +++ b/Documentation/technical/api-trace2.txt @@ -656,7 +656,8 @@ The "exec_id" field is a command-unique id and is only useful if the ------------ `"def_param"`:: - This event is generated to log a global parameter. + This event is generated to log a global parameter, such as a config + setting, command-line flag, or environment variable. + ------------ { diff --git a/git.c b/git.c index 7be7ad3..b7dbe82 100644 --- a/git.c +++ b/git.c @@ -351,6 +351,7 @@ static int handle_alias(int *argcp, const char ***argv) trace2_cmd_alias(alias_command, child.args.argv); trace2_cmd_list_config(); + trace2_cmd_list_env_vars(); trace2_cmd_name("_run_shell_alias_"); ret = run_command(&child); @@ -388,6 +389,7 @@ static int handle_alias(int *argcp, const char ***argv) trace2_cmd_alias(alias_command, new_argv); trace2_cmd_list_config(); + trace2_cmd_list_env_vars(); *argv = new_argv; *argcp += count - 1; @@ -439,6 +441,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) trace_argv_printf(argv, "trace: built-in: git"); trace2_cmd_name(p->cmd); trace2_cmd_list_config(); + trace2_cmd_list_env_vars(); validate_cache_entries(the_repository->index); status = p->fn(argc, argv, prefix); diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index c9a232d..4cdab7e 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -111,6 +111,7 @@ int cmd_main(int argc, const char **argv) argc--; trace2_cmd_name(cmds[i].name); trace2_cmd_list_config(); + trace2_cmd_list_env_vars(); return cmds[i].fn(argc, argv); } } diff --git a/t/t0212-trace2-event.sh b/t/t0212-trace2-event.sh index 7065a1b..1529155 100755 --- a/t/t0212-trace2-event.sh +++ b/t/t0212-trace2-event.sh @@ -199,6 +199,43 @@ test_expect_success JSON_PP 'event stream, list config' ' test_cmp expect actual ' +# Test listing of all "interesting" environment variables. + +test_expect_success JSON_PP 'event stream, list env vars' ' + test_when_finished "rm trace.event actual expect" && + GIT_TRACE2_EVENT="$(pwd)/trace.event" \ + GIT_TRACE2_ENV_VARS="A_VAR,OTHER_VAR,MISSING" \ + A_VAR=1 OTHER_VAR="hello world" test-tool trace2 001return 0 && + perl "$TEST_DIRECTORY/t0212/parse_events.perl" actual && + sed -e "s/^|//" >expect <<-EOF && + |VAR1 = { + | "_SID0_":{ + | "argv":[ + | "_EXE_", + | "trace2", + | "001return", + | "0" + | ], + | "exit_code":0, + | "hierarchy":"trace2", + | "name":"trace2", + | "params":[ + | { + | "param":"A_VAR", + | "value":"1" + | }, + | { + | "param":"OTHER_VAR", + | "value":"hello world" + | } + | ], + | "version":"$V" + | } + |}; + EOF + test_cmp expect actual +' + test_expect_success JSON_PP 'basic trace2_data' ' test_when_finished "rm trace.event actual expect" && GIT_TRACE2_EVENT="$(pwd)/trace.event" test-tool trace2 006data test_category k1 v1 test_category k2 v2 && diff --git a/trace2.c b/trace2.c index c7b4f14..2c6b570 100644 --- a/trace2.c +++ b/trace2.c @@ -121,6 +121,7 @@ static void tr2main_atexit_handler(void) tr2_sid_release(); tr2_cmd_name_release(); tr2_cfg_free_patterns(); + tr2_cfg_free_env_vars(); tr2_sysenv_release(); trace2_enabled = 0; @@ -311,6 +312,14 @@ void trace2_cmd_list_config_fl(const char *file, int line) tr2_cfg_list_config_fl(file, line); } +void trace2_cmd_list_env_vars_fl(const char *file, int line) +{ + if (!trace2_enabled) + return; + + tr2_list_env_vars_fl(file, line); +} + void trace2_cmd_set_config_fl(const char *file, int line, const char *key, const char *value) { diff --git a/trace2.h b/trace2.h index e5e81c0..b18bc55 100644 --- a/trace2.h +++ b/trace2.h @@ -183,6 +183,19 @@ void trace2_cmd_list_config_fl(const char *file, int line); #define trace2_cmd_list_config() trace2_cmd_list_config_fl(__FILE__, __LINE__) /* + * Emit one or more 'def_param' events for "important" environment variables. + * + * Use the TR2_SYSENV_ENV_VARS setting to register a comma-separated list of + * environment variables considered important. For example: + * git config --system trace2.envVars 'GIT_HTTP_USER_AGENT,GIT_CONFIG' + * or: + * GIT_TRACE2_ENV_VARS="GIT_HTTP_USER_AGENT,GIT_CONFIG" + */ +void trace2_cmd_list_env_vars_fl(const char *file, int line); + +#define trace2_cmd_list_env_vars() trace2_cmd_list_env_vars_fl(__FILE__, __LINE__) + +/* * Emit a "def_param" event for the given config key/value pair IF * we consider the key to be "important". * diff --git a/trace2/tr2_cfg.c b/trace2/tr2_cfg.c index caa7f06..ec9ac1a 100644 --- a/trace2/tr2_cfg.c +++ b/trace2/tr2_cfg.c @@ -7,6 +7,10 @@ static struct strbuf **tr2_cfg_patterns; static int tr2_cfg_count_patterns; static int tr2_cfg_loaded; +static struct strbuf **tr2_cfg_env_vars; +static int tr2_cfg_env_vars_count; +static int tr2_cfg_env_vars_loaded; + /* * Parse a string containing a comma-delimited list of config keys * or wildcard patterns into a list of strbufs. @@ -46,6 +50,45 @@ void tr2_cfg_free_patterns(void) tr2_cfg_loaded = 0; } +/* + * Parse a string containing a comma-delimited list of environment variable + * names into a list of strbufs. + */ +static int tr2_load_env_vars(void) +{ + struct strbuf **s; + const char *varlist; + + if (tr2_cfg_env_vars_loaded) + return tr2_cfg_env_vars_count; + tr2_cfg_env_vars_loaded = 1; + + varlist = tr2_sysenv_get(TR2_SYSENV_ENV_VARS); + if (!varlist || !*varlist) + return tr2_cfg_env_vars_count; + + tr2_cfg_env_vars = strbuf_split_buf(varlist, strlen(varlist), ',', -1); + for (s = tr2_cfg_env_vars; *s; s++) { + struct strbuf *buf = *s; + + if (buf->len && buf->buf[buf->len - 1] == ',') + strbuf_setlen(buf, buf->len - 1); + strbuf_trim_trailing_newline(*s); + strbuf_trim(*s); + } + + tr2_cfg_env_vars_count = s - tr2_cfg_env_vars; + return tr2_cfg_env_vars_count; +} + +void tr2_cfg_free_env_vars(void) +{ + if (tr2_cfg_env_vars) + strbuf_list_free(tr2_cfg_env_vars); + tr2_cfg_env_vars_count = 0; + tr2_cfg_env_vars_loaded = 0; +} + struct tr2_cfg_data { const char *file; int line; @@ -79,6 +122,21 @@ void tr2_cfg_list_config_fl(const char *file, int line) read_early_config(tr2_cfg_cb, &data); } +void tr2_list_env_vars_fl(const char *file, int line) +{ + struct strbuf **s; + + if (tr2_load_env_vars() <= 0) + return; + + for (s = tr2_cfg_env_vars; *s; s++) { + struct strbuf *buf = *s; + const char *val = getenv(buf->buf); + if (val && *val) + trace2_def_param_fl(file, line, buf->buf, val); + } +} + void tr2_cfg_set_fl(const char *file, int line, const char *key, const char *value) { diff --git a/trace2/tr2_cfg.h b/trace2/tr2_cfg.h index d9c98f6..a11d71f 100644 --- a/trace2/tr2_cfg.h +++ b/trace2/tr2_cfg.h @@ -8,6 +8,12 @@ void tr2_cfg_list_config_fl(const char *file, int line); /* + * Iterate over all "interesting" environment variables and emit 'def_param' + * events for them to TRACE2. + */ +void tr2_list_env_vars_fl(const char *file, int line); + +/* * Emit a "def_param" event for the given key/value pair IF we consider * the key to be "interesting". */ @@ -16,4 +22,6 @@ void tr2_cfg_set_fl(const char *file, int line, const char *key, void tr2_cfg_free_patterns(void); +void tr2_cfg_free_env_vars(void); + #endif /* TR2_CFG_H */ diff --git a/trace2/tr2_sysenv.c b/trace2/tr2_sysenv.c index 3c3792e..a380dcf 100644 --- a/trace2/tr2_sysenv.c +++ b/trace2/tr2_sysenv.c @@ -29,6 +29,8 @@ struct tr2_sysenv_entry { static struct tr2_sysenv_entry tr2_sysenv_settings[] = { [TR2_SYSENV_CFG_PARAM] = { "GIT_TRACE2_CONFIG_PARAMS", "trace2.configparams" }, + [TR2_SYSENV_ENV_VARS] = { "GIT_TRACE2_ENV_VARS", + "trace2.envvars" }, [TR2_SYSENV_DST_DEBUG] = { "GIT_TRACE2_DST_DEBUG", "trace2.destinationdebug" }, diff --git a/trace2/tr2_sysenv.h b/trace2/tr2_sysenv.h index d4364a7..3292ee1 100644 --- a/trace2/tr2_sysenv.h +++ b/trace2/tr2_sysenv.h @@ -11,6 +11,7 @@ */ enum tr2_sysenv_variable { TR2_SYSENV_CFG_PARAM = 0, + TR2_SYSENV_ENV_VARS, TR2_SYSENV_DST_DEBUG, -- cgit v0.10.2-6-g49f6