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>
Josh Steadmon committed
Mar 20, 2020 at 14:06 UTC
3d3adaad914441a6e7b916eb8dfd5ae638aab068
11 files changed
+143
-1
Documentation/config/trace2.txt
+9
@@ -48,6 +48,15 @@ trace2.configParams::
48
May be overridden by the `GIT_TRACE2_CONFIG_PARAMS` environment
49
variable. Unset by default.
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
+
60
trace2.destinationDebug::
61
Boolean. When true Git will print error messages when a
62
trace target destination cannot be opened for writing.
Documentation/technical/api-trace2.txt
+2
-1
@@ -656,7 +656,8 @@ The "exec_id" field is a command-unique id and is only useful if the
656
------------
657
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.
661
+
662
------------
663
{
git.c
+3
@@ -351,6 +351,7 @@ static int handle_alias(int *argcp, const char ***argv)
351
352
trace2_cmd_alias(alias_command, child.args.argv);
353
trace2_cmd_list_config();
354
+ trace2_cmd_list_env_vars();
355
trace2_cmd_name("_run_shell_alias_");
356
357
ret = run_command(&child);
@@ -388,6 +389,7 @@ static int handle_alias(int *argcp, const char ***argv)
389
390
trace2_cmd_alias(alias_command, new_argv);
391
trace2_cmd_list_config();
392
+ trace2_cmd_list_env_vars();
393
394
*argv = new_argv;
395
*argcp += count - 1;
@@ -439,6 +441,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
441
trace_argv_printf(argv, "trace: built-in: git");
442
trace2_cmd_name(p->cmd);
443
trace2_cmd_list_config();
444
+ trace2_cmd_list_env_vars();
445
446
validate_cache_entries(the_repository->index);
447
status = p->fn(argc, argv, prefix);
t/helper/test-tool.c
+1
@@ -111,6 +111,7 @@ int cmd_main(int argc, const char **argv)
111
argc--;
112
trace2_cmd_name(cmds[i].name);
113
trace2_cmd_list_config();
114
+ trace2_cmd_list_env_vars();
115
return cmds[i].fn(argc, argv);
116
}
117
}
t/t0212-trace2-event.sh
+37
@@ -199,6 +199,43 @@ test_expect_success JSON_PP 'event stream, list config' '
199
test_cmp expect actual
200
'
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
+
239
test_expect_success JSON_PP 'basic trace2_data' '
240
test_when_finished "rm trace.event actual expect" &&
241
GIT_TRACE2_EVENT="$(pwd)/trace.event" test-tool trace2 006data test_category k1 v1 test_category k2 v2 &&
trace2.c
+9
@@ -121,6 +121,7 @@ static void tr2main_atexit_handler(void)
121
tr2_sid_release();
122
tr2_cmd_name_release();
123
tr2_cfg_free_patterns();
124
+ tr2_cfg_free_env_vars();
125
tr2_sysenv_release();
126
127
trace2_enabled = 0;
@@ -311,6 +312,14 @@ void trace2_cmd_list_config_fl(const char *file, int line)
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);
321
+}
322
+
323
void trace2_cmd_set_config_fl(const char *file, int line, const char *key,
324
const char *value)
325
{
trace2.h
+13
@@ -182,6 +182,19 @@ void trace2_cmd_list_config_fl(const char *file, int line);
182
183
#define trace2_cmd_list_config() trace2_cmd_list_config_fl(__FILE__, __LINE__)
184
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
/*
199
* Emit a "def_param" event for the given config key/value pair IF
200
* we consider the key to be "important".
trace2/tr2_cfg.c
+58
@@ -7,6 +7,10 @@ static struct strbuf **tr2_cfg_patterns;
7
static int tr2_cfg_count_patterns;
8
static int tr2_cfg_loaded;
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
+
14
/*
15
* Parse a string containing a comma-delimited list of config keys
16
* or wildcard patterns into a list of strbufs.
@@ -46,6 +50,45 @@ void tr2_cfg_free_patterns(void)
50
tr2_cfg_loaded = 0;
51
}
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
+
92
struct tr2_cfg_data {
93
const char *file;
94
int line;
@@ -79,6 +122,21 @@ void tr2_cfg_list_config_fl(const char *file, int line)
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
+ }
138
+}
139
+
140
void tr2_cfg_set_fl(const char *file, int line, const char *key,
141
const char *value)
142
{
trace2/tr2_cfg.h
+8
@@ -7,6 +7,12 @@
7
*/
8
void tr2_cfg_list_config_fl(const char *file, int line);
9
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
/*
17
* Emit a "def_param" event for the given key/value pair IF we consider
18
* the key to be "interesting".
@@ -16,4 +22,6 @@ void tr2_cfg_set_fl(const char *file, int line, const char *key,
22
23
void tr2_cfg_free_patterns(void);
24
25
+void tr2_cfg_free_env_vars(void);
26
+
27
#endif /* TR2_CFG_H */
trace2/tr2_sysenv.c
+2
@@ -29,6 +29,8 @@ struct tr2_sysenv_entry {
29
static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
30
[TR2_SYSENV_CFG_PARAM] = { "GIT_TRACE2_CONFIG_PARAMS",
31
"trace2.configparams" },
32
+ [TR2_SYSENV_ENV_VARS] = { "GIT_TRACE2_ENV_VARS",
33
+ "trace2.envvars" },
34
35
[TR2_SYSENV_DST_DEBUG] = { "GIT_TRACE2_DST_DEBUG",
36
"trace2.destinationdebug" },
trace2/tr2_sysenv.h
+1
@@ -11,6 +11,7 @@
11
*/
12
enum tr2_sysenv_variable {
13
TR2_SYSENV_CFG_PARAM = 0,
14
+ TR2_SYSENV_ENV_VARS,
15
16
TR2_SYSENV_DST_DEBUG,
17