Git fork

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 <steadmon@google.com>
Acked-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Josh Steadmon and committed by
Junio C Hamano
3d3adaad 98cedd02

+143 -1
+9
Documentation/config/trace2.txt
··· 48 48 May be overridden by the `GIT_TRACE2_CONFIG_PARAMS` environment 49 49 variable. Unset by default. 50 50 51 + trace2.envVars:: 52 + A comma-separated list of "important" environment variables that should 53 + be recorded in the trace2 output. For example, 54 + `GIT_HTTP_USER_AGENT,GIT_CONFIG` would cause the trace2 output to 55 + contain events listing the overrides for HTTP user agent and the 56 + location of the Git configuration file (assuming any are set). May be 57 + overriden by the `GIT_TRACE2_ENV_VARS` environment variable. Unset by 58 + default. 59 + 51 60 trace2.destinationDebug:: 52 61 Boolean. When true Git will print error messages when a 53 62 trace target destination cannot be opened for writing.
+2 -1
Documentation/technical/api-trace2.txt
··· 656 656 ------------ 657 657 658 658 `"def_param"`:: 659 - This event is generated to log a global parameter. 659 + This event is generated to log a global parameter, such as a config 660 + setting, command-line flag, or environment variable. 660 661 + 661 662 ------------ 662 663 {
+3
git.c
··· 351 351 352 352 trace2_cmd_alias(alias_command, child.args.argv); 353 353 trace2_cmd_list_config(); 354 + trace2_cmd_list_env_vars(); 354 355 trace2_cmd_name("_run_shell_alias_"); 355 356 356 357 ret = run_command(&child); ··· 388 389 389 390 trace2_cmd_alias(alias_command, new_argv); 390 391 trace2_cmd_list_config(); 392 + trace2_cmd_list_env_vars(); 391 393 392 394 *argv = new_argv; 393 395 *argcp += count - 1; ··· 439 441 trace_argv_printf(argv, "trace: built-in: git"); 440 442 trace2_cmd_name(p->cmd); 441 443 trace2_cmd_list_config(); 444 + trace2_cmd_list_env_vars(); 442 445 443 446 validate_cache_entries(the_repository->index); 444 447 status = p->fn(argc, argv, prefix);
+1
t/helper/test-tool.c
··· 111 111 argc--; 112 112 trace2_cmd_name(cmds[i].name); 113 113 trace2_cmd_list_config(); 114 + trace2_cmd_list_env_vars(); 114 115 return cmds[i].fn(argc, argv); 115 116 } 116 117 }
+37
t/t0212-trace2-event.sh
··· 199 199 test_cmp expect actual 200 200 ' 201 201 202 + # Test listing of all "interesting" environment variables. 203 + 204 + test_expect_success JSON_PP 'event stream, list env vars' ' 205 + test_when_finished "rm trace.event actual expect" && 206 + GIT_TRACE2_EVENT="$(pwd)/trace.event" \ 207 + GIT_TRACE2_ENV_VARS="A_VAR,OTHER_VAR,MISSING" \ 208 + A_VAR=1 OTHER_VAR="hello world" test-tool trace2 001return 0 && 209 + perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual && 210 + sed -e "s/^|//" >expect <<-EOF && 211 + |VAR1 = { 212 + | "_SID0_":{ 213 + | "argv":[ 214 + | "_EXE_", 215 + | "trace2", 216 + | "001return", 217 + | "0" 218 + | ], 219 + | "exit_code":0, 220 + | "hierarchy":"trace2", 221 + | "name":"trace2", 222 + | "params":[ 223 + | { 224 + | "param":"A_VAR", 225 + | "value":"1" 226 + | }, 227 + | { 228 + | "param":"OTHER_VAR", 229 + | "value":"hello world" 230 + | } 231 + | ], 232 + | "version":"$V" 233 + | } 234 + |}; 235 + EOF 236 + test_cmp expect actual 237 + ' 238 + 202 239 test_expect_success JSON_PP 'basic trace2_data' ' 203 240 test_when_finished "rm trace.event actual expect" && 204 241 GIT_TRACE2_EVENT="$(pwd)/trace.event" test-tool trace2 006data test_category k1 v1 test_category k2 v2 &&
+9
trace2.c
··· 121 121 tr2_sid_release(); 122 122 tr2_cmd_name_release(); 123 123 tr2_cfg_free_patterns(); 124 + tr2_cfg_free_env_vars(); 124 125 tr2_sysenv_release(); 125 126 126 127 trace2_enabled = 0; ··· 309 310 return; 310 311 311 312 tr2_cfg_list_config_fl(file, line); 313 + } 314 + 315 + void trace2_cmd_list_env_vars_fl(const char *file, int line) 316 + { 317 + if (!trace2_enabled) 318 + return; 319 + 320 + tr2_list_env_vars_fl(file, line); 312 321 } 313 322 314 323 void trace2_cmd_set_config_fl(const char *file, int line, const char *key,
+13
trace2.h
··· 183 183 #define trace2_cmd_list_config() trace2_cmd_list_config_fl(__FILE__, __LINE__) 184 184 185 185 /* 186 + * Emit one or more 'def_param' events for "important" environment variables. 187 + * 188 + * Use the TR2_SYSENV_ENV_VARS setting to register a comma-separated list of 189 + * environment variables considered important. For example: 190 + * git config --system trace2.envVars 'GIT_HTTP_USER_AGENT,GIT_CONFIG' 191 + * or: 192 + * GIT_TRACE2_ENV_VARS="GIT_HTTP_USER_AGENT,GIT_CONFIG" 193 + */ 194 + void trace2_cmd_list_env_vars_fl(const char *file, int line); 195 + 196 + #define trace2_cmd_list_env_vars() trace2_cmd_list_env_vars_fl(__FILE__, __LINE__) 197 + 198 + /* 186 199 * Emit a "def_param" event for the given config key/value pair IF 187 200 * we consider the key to be "important". 188 201 *
+58
trace2/tr2_cfg.c
··· 7 7 static int tr2_cfg_count_patterns; 8 8 static int tr2_cfg_loaded; 9 9 10 + static struct strbuf **tr2_cfg_env_vars; 11 + static int tr2_cfg_env_vars_count; 12 + static int tr2_cfg_env_vars_loaded; 13 + 10 14 /* 11 15 * Parse a string containing a comma-delimited list of config keys 12 16 * or wildcard patterns into a list of strbufs. ··· 46 50 tr2_cfg_loaded = 0; 47 51 } 48 52 53 + /* 54 + * Parse a string containing a comma-delimited list of environment variable 55 + * names into a list of strbufs. 56 + */ 57 + static int tr2_load_env_vars(void) 58 + { 59 + struct strbuf **s; 60 + const char *varlist; 61 + 62 + if (tr2_cfg_env_vars_loaded) 63 + return tr2_cfg_env_vars_count; 64 + tr2_cfg_env_vars_loaded = 1; 65 + 66 + varlist = tr2_sysenv_get(TR2_SYSENV_ENV_VARS); 67 + if (!varlist || !*varlist) 68 + return tr2_cfg_env_vars_count; 69 + 70 + tr2_cfg_env_vars = strbuf_split_buf(varlist, strlen(varlist), ',', -1); 71 + for (s = tr2_cfg_env_vars; *s; s++) { 72 + struct strbuf *buf = *s; 73 + 74 + if (buf->len && buf->buf[buf->len - 1] == ',') 75 + strbuf_setlen(buf, buf->len - 1); 76 + strbuf_trim_trailing_newline(*s); 77 + strbuf_trim(*s); 78 + } 79 + 80 + tr2_cfg_env_vars_count = s - tr2_cfg_env_vars; 81 + return tr2_cfg_env_vars_count; 82 + } 83 + 84 + void tr2_cfg_free_env_vars(void) 85 + { 86 + if (tr2_cfg_env_vars) 87 + strbuf_list_free(tr2_cfg_env_vars); 88 + tr2_cfg_env_vars_count = 0; 89 + tr2_cfg_env_vars_loaded = 0; 90 + } 91 + 49 92 struct tr2_cfg_data { 50 93 const char *file; 51 94 int line; ··· 77 120 78 121 if (tr2_cfg_load_patterns() > 0) 79 122 read_early_config(tr2_cfg_cb, &data); 123 + } 124 + 125 + void tr2_list_env_vars_fl(const char *file, int line) 126 + { 127 + struct strbuf **s; 128 + 129 + if (tr2_load_env_vars() <= 0) 130 + return; 131 + 132 + for (s = tr2_cfg_env_vars; *s; s++) { 133 + struct strbuf *buf = *s; 134 + const char *val = getenv(buf->buf); 135 + if (val && *val) 136 + trace2_def_param_fl(file, line, buf->buf, val); 137 + } 80 138 } 81 139 82 140 void tr2_cfg_set_fl(const char *file, int line, const char *key,
+8
trace2/tr2_cfg.h
··· 8 8 void tr2_cfg_list_config_fl(const char *file, int line); 9 9 10 10 /* 11 + * Iterate over all "interesting" environment variables and emit 'def_param' 12 + * events for them to TRACE2. 13 + */ 14 + void tr2_list_env_vars_fl(const char *file, int line); 15 + 16 + /* 11 17 * Emit a "def_param" event for the given key/value pair IF we consider 12 18 * the key to be "interesting". 13 19 */ ··· 15 21 const char *value); 16 22 17 23 void tr2_cfg_free_patterns(void); 24 + 25 + void tr2_cfg_free_env_vars(void); 18 26 19 27 #endif /* TR2_CFG_H */
+2
trace2/tr2_sysenv.c
··· 29 29 static struct tr2_sysenv_entry tr2_sysenv_settings[] = { 30 30 [TR2_SYSENV_CFG_PARAM] = { "GIT_TRACE2_CONFIG_PARAMS", 31 31 "trace2.configparams" }, 32 + [TR2_SYSENV_ENV_VARS] = { "GIT_TRACE2_ENV_VARS", 33 + "trace2.envvars" }, 32 34 33 35 [TR2_SYSENV_DST_DEBUG] = { "GIT_TRACE2_DST_DEBUG", 34 36 "trace2.destinationdebug" },
+1
trace2/tr2_sysenv.h
··· 11 11 */ 12 12 enum tr2_sysenv_variable { 13 13 TR2_SYSENV_CFG_PARAM = 0, 14 + TR2_SYSENV_ENV_VARS, 14 15 15 16 TR2_SYSENV_DST_DEBUG, 16 17