Skip to content

Commit 6f64eea

Browse files
committed
Merge branch 'es/trace2-log-parent-process-name'
trace2 logs learned to show parent process name to see in what context Git was invoked. * es/trace2-log-parent-process-name: tr2: log parent process name tr2: make process info collection platform-generic
2 parents 276bc63 + 2f732bf commit 6f64eea

File tree

14 files changed

+184
-7
lines changed

14 files changed

+184
-7
lines changed

Documentation/technical/api-trace2.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,20 @@ about specific error arguments.
493493
}
494494
------------
495495

496+
`"cmd_ancestry"`::
497+
This event contains the text command name for the parent (and earlier
498+
generations of parents) of the current process, in an array ordered from
499+
nearest parent to furthest great-grandparent. It may not be implemented
500+
on all platforms.
501+
+
502+
------------
503+
{
504+
"event":"cmd_ancestry",
505+
...
506+
"ancestry":["bash","tmux: server","systemd"]
507+
}
508+
------------
509+
496510
`"cmd_name"`::
497511
This event contains the command name for this git process
498512
and the hierarchy of commands from parent git processes.

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,6 +1917,10 @@ ifneq ($(PROCFS_EXECUTABLE_PATH),)
19171917
BASIC_CFLAGS += '-DPROCFS_EXECUTABLE_PATH="$(procfs_executable_path_SQ)"'
19181918
endif
19191919

1920+
ifndef HAVE_PLATFORM_PROCINFO
1921+
COMPAT_OBJS += compat/stub/procinfo.o
1922+
endif
1923+
19201924
ifdef HAVE_NS_GET_EXECUTABLE_PATH
19211925
BASIC_CFLAGS += -DHAVE_NS_GET_EXECUTABLE_PATH
19221926
endif

compat/linux/procinfo.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include "cache.h"
2+
3+
#include "strbuf.h"
4+
#include "strvec.h"
5+
#include "trace2.h"
6+
7+
static void get_ancestry_names(struct strvec *names)
8+
{
9+
/*
10+
* NEEDSWORK: We could gather the entire pstree into an array to match
11+
* functionality with compat/win32/trace2_win32_process_info.c.
12+
* To do so, we may want to examine /proc/<pid>/stat. For now, just
13+
* gather the immediate parent name which is readily accessible from
14+
* /proc/$(getppid())/comm.
15+
*/
16+
struct strbuf procfs_path = STRBUF_INIT;
17+
struct strbuf name = STRBUF_INIT;
18+
19+
/* try to use procfs if it's present. */
20+
strbuf_addf(&procfs_path, "/proc/%d/comm", getppid());
21+
if (strbuf_read_file(&name, procfs_path.buf, 0)) {
22+
strbuf_release(&procfs_path);
23+
strbuf_trim_trailing_newline(&name);
24+
strvec_push(names, strbuf_detach(&name, NULL));
25+
}
26+
27+
return;
28+
/* NEEDSWORK: add non-procfs-linux implementations here */
29+
}
30+
31+
void trace2_collect_process_info(enum trace2_process_info_reason reason)
32+
{
33+
if (!trace2_is_enabled())
34+
return;
35+
36+
/* someday we may want to write something extra here, but not today */
37+
if (reason == TRACE2_PROCESS_INFO_EXIT)
38+
return;
39+
40+
if (reason == TRACE2_PROCESS_INFO_STARTUP) {
41+
/*
42+
* NEEDSWORK: we could do the entire ptree in an array instead,
43+
* see compat/win32/trace2_win32_process_info.c.
44+
*/
45+
struct strvec names = STRVEC_INIT;
46+
47+
get_ancestry_names(&names);
48+
49+
if (names.nr)
50+
trace2_cmd_ancestry(names.v);
51+
strvec_clear(&names);
52+
}
53+
54+
return;
55+
}

compat/stub/procinfo.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include "git-compat-util.h"
2+
3+
#include "trace2.h"
4+
5+
/*
6+
* Stub. See sample implementations in compat/linux/procinfo.c and
7+
* compat/win32/trace2_win32_process_info.c.
8+
*/
9+
void trace2_collect_process_info(enum trace2_process_info_reason reason)
10+
{
11+
}

config.mak.uname

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ ifeq ($(uname_S),Linux)
5858
FREAD_READS_DIRECTORIES = UnfortunatelyYes
5959
BASIC_CFLAGS += -DHAVE_SYSINFO
6060
PROCFS_EXECUTABLE_PATH = /proc/self/exe
61+
HAVE_PLATFORM_PROCINFO = YesPlease
62+
COMPAT_OBJS += compat/linux/procinfo.o
6163
endif
6264
ifeq ($(uname_S),GNU/kFreeBSD)
6365
HAVE_ALLOCA_H = YesPlease
@@ -617,6 +619,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
617619
ETAGS_TARGET = ETAGS
618620
NO_POSIX_GOODIES = UnfortunatelyYes
619621
DEFAULT_HELP_FORMAT = html
622+
HAVE_PLATFORM_PROCINFO = YesPlease
620623
BASIC_LDFLAGS += -municode
621624
COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
622625
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"

t/t0210/scrub_normal.perl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@
4242
# so just omit it for testing purposes.
4343
# print "cmd_path _EXE_\n";
4444
}
45+
elsif ($line =~ m/^cmd_ancestry/) {
46+
# 'cmd_ancestry' is not implemented everywhere, so for portability's
47+
# sake, skip it when parsing normal.
48+
#
49+
# print "$line";
50+
}
4551
else {
4652
print "$line";
4753
}

t/t0211/scrub_perf.perl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@
4444
# $tokens[$col_rest] = "_EXE_";
4545
goto SKIP_LINE;
4646
}
47+
elsif ($tokens[$col_event] =~ m/cmd_ancestry/) {
48+
# 'cmd_ancestry' is platform-specific and not implemented everywhere,
49+
# so skip it.
50+
goto SKIP_LINE;
51+
}
4752
elsif ($tokens[$col_event] =~ m/child_exit/) {
4853
$tokens[$col_rest] =~ s/ pid:\d* / pid:_PID_ /;
4954
}

t/t0212/parse_events.perl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@
132132
# just omit it for testing purposes.
133133
# $processes->{$sid}->{'path'} = "_EXE_";
134134
}
135-
135+
elsif ($event eq 'cmd_ancestry') {
136+
# 'cmd_ancestry' is platform-specific and not implemented everywhere, so
137+
# just skip it for testing purposes.
138+
}
136139
elsif ($event eq 'cmd_name') {
137140
$processes->{$sid}->{'name'} = $line->{'name'};
138141
$processes->{$sid}->{'hierarchy'} = $line->{'hierarchy'};

trace2.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,19 @@ void trace2_cmd_path_fl(const char *file, int line, const char *pathname)
260260
tgt_j->pfn_command_path_fl(file, line, pathname);
261261
}
262262

263+
void trace2_cmd_ancestry_fl(const char *file, int line, const char **parent_names)
264+
{
265+
struct tr2_tgt *tgt_j;
266+
int j;
267+
268+
if (!trace2_enabled)
269+
return;
270+
271+
for_each_wanted_builtin (j, tgt_j)
272+
if (tgt_j->pfn_command_ancestry_fl)
273+
tgt_j->pfn_command_ancestry_fl(file, line, parent_names);
274+
}
275+
263276
void trace2_cmd_name_fl(const char *file, int line, const char *name)
264277
{
265278
struct tr2_tgt *tgt_j;

trace2.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,16 @@ void trace2_cmd_path_fl(const char *file, int line, const char *pathname);
133133

134134
#define trace2_cmd_path(p) trace2_cmd_path_fl(__FILE__, __LINE__, (p))
135135

136+
/*
137+
* Emit an 'ancestry' event with the process name of the current process's
138+
* parent process.
139+
* This gives post-processors a way to determine what invoked the command and
140+
* learn more about usage patterns.
141+
*/
142+
void trace2_cmd_ancestry_fl(const char *file, int line, const char **parent_names);
143+
144+
#define trace2_cmd_ancestry(v) trace2_cmd_ancestry_fl(__FILE__, __LINE__, (v))
145+
136146
/*
137147
* Emit a 'cmd_name' event with the canonical name of the command.
138148
* This gives post-processors a simple field to identify the command
@@ -492,13 +502,7 @@ enum trace2_process_info_reason {
492502
TRACE2_PROCESS_INFO_EXIT,
493503
};
494504

495-
#if defined(GIT_WINDOWS_NATIVE)
496505
void trace2_collect_process_info(enum trace2_process_info_reason reason);
497-
#else
498-
#define trace2_collect_process_info(reason) \
499-
do { \
500-
} while (0)
501-
#endif
502506

503507
const char *trace2_session_id(void);
504508

trace2/tr2_tgt.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ typedef void(tr2_tgt_evt_error_va_fl_t)(const char *file, int line,
2727

2828
typedef void(tr2_tgt_evt_command_path_fl_t)(const char *file, int line,
2929
const char *command_path);
30+
typedef void(tr2_tgt_evt_command_ancestry_fl_t)(const char *file, int line,
31+
const char **parent_names);
3032
typedef void(tr2_tgt_evt_command_name_fl_t)(const char *file, int line,
3133
const char *name,
3234
const char *hierarchy);
@@ -108,6 +110,7 @@ struct tr2_tgt {
108110
tr2_tgt_evt_atexit_t *pfn_atexit;
109111
tr2_tgt_evt_error_va_fl_t *pfn_error_va_fl;
110112
tr2_tgt_evt_command_path_fl_t *pfn_command_path_fl;
113+
tr2_tgt_evt_command_ancestry_fl_t *pfn_command_ancestry_fl;
111114
tr2_tgt_evt_command_name_fl_t *pfn_command_name_fl;
112115
tr2_tgt_evt_command_mode_fl_t *pfn_command_mode_fl;
113116
tr2_tgt_evt_alias_fl_t *pfn_alias_fl;

trace2/tr2_tgt_event.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,26 @@ static void fn_command_path_fl(const char *file, int line, const char *pathname)
261261
jw_release(&jw);
262262
}
263263

264+
static void fn_command_ancestry_fl(const char *file, int line, const char **parent_names)
265+
{
266+
const char *event_name = "cmd_ancestry";
267+
const char *parent_name = NULL;
268+
struct json_writer jw = JSON_WRITER_INIT;
269+
270+
jw_object_begin(&jw, 0);
271+
event_fmt_prepare(event_name, file, line, NULL, &jw);
272+
jw_object_inline_begin_array(&jw, "ancestry");
273+
274+
while ((parent_name = *parent_names++))
275+
jw_array_string(&jw, parent_name);
276+
277+
jw_end(&jw); /* 'ancestry' array */
278+
jw_end(&jw); /* event object */
279+
280+
tr2_dst_write_line(&tr2dst_event, &jw.json);
281+
jw_release(&jw);
282+
}
283+
264284
static void fn_command_name_fl(const char *file, int line, const char *name,
265285
const char *hierarchy)
266286
{
@@ -584,6 +604,7 @@ struct tr2_tgt tr2_tgt_event = {
584604
fn_atexit,
585605
fn_error_va_fl,
586606
fn_command_path_fl,
607+
fn_command_ancestry_fl,
587608
fn_command_name_fl,
588609
fn_command_mode_fl,
589610
fn_alias_fl,

trace2/tr2_tgt_normal.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,24 @@ static void fn_command_path_fl(const char *file, int line, const char *pathname)
160160
strbuf_release(&buf_payload);
161161
}
162162

163+
static void fn_command_ancestry_fl(const char *file, int line, const char **parent_names)
164+
{
165+
const char *parent_name = NULL;
166+
struct strbuf buf_payload = STRBUF_INIT;
167+
168+
/* cmd_ancestry parent <- grandparent <- great-grandparent */
169+
strbuf_addstr(&buf_payload, "cmd_ancestry ");
170+
while ((parent_name = *parent_names++)) {
171+
strbuf_addstr(&buf_payload, parent_name);
172+
/* if we'll write another one after this, add a delimiter */
173+
if (parent_names && *parent_names)
174+
strbuf_addstr(&buf_payload, " <- ");
175+
}
176+
177+
normal_io_write_fl(file, line, &buf_payload);
178+
strbuf_release(&buf_payload);
179+
}
180+
163181
static void fn_command_name_fl(const char *file, int line, const char *name,
164182
const char *hierarchy)
165183
{
@@ -306,6 +324,7 @@ struct tr2_tgt tr2_tgt_normal = {
306324
fn_atexit,
307325
fn_error_va_fl,
308326
fn_command_path_fl,
327+
fn_command_ancestry_fl,
309328
fn_command_name_fl,
310329
fn_command_mode_fl,
311330
fn_alias_fl,

trace2/tr2_tgt_perf.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,21 @@ static void fn_command_path_fl(const char *file, int line, const char *pathname)
253253
strbuf_release(&buf_payload);
254254
}
255255

256+
static void fn_command_ancestry_fl(const char *file, int line, const char **parent_names)
257+
{
258+
const char *event_name = "cmd_ancestry";
259+
struct strbuf buf_payload = STRBUF_INIT;
260+
261+
strbuf_addstr(&buf_payload, "ancestry:[");
262+
/* It's not an argv but the rules are basically the same. */
263+
sq_append_quote_argv_pretty(&buf_payload, parent_names);
264+
strbuf_addch(&buf_payload, ']');
265+
266+
perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
267+
&buf_payload);
268+
strbuf_release(&buf_payload);
269+
}
270+
256271
static void fn_command_name_fl(const char *file, int line, const char *name,
257272
const char *hierarchy)
258273
{
@@ -532,6 +547,7 @@ struct tr2_tgt tr2_tgt_perf = {
532547
fn_atexit,
533548
fn_error_va_fl,
534549
fn_command_path_fl,
550+
fn_command_ancestry_fl,
535551
fn_command_name_fl,
536552
fn_command_mode_fl,
537553
fn_alias_fl,

0 commit comments

Comments
 (0)