It can be useful to tell who invoked Git - was it invoked manually by a user via CLI or script? By an IDE? Knowing where the Git invocation came from can help with debugging to isolate where the problem came from. Unfortunately, there's no cross-platform reliable way to gather the name of the parent process. If procfs is present, we can use that; otherwise we will need to discover the name another way. However, the process ID should be sufficient regardless of platform. Signed-off-by: Emily Shaffer <emilyshaffer@xxxxxxxxxx> --- We briefly discussed hiding this behind a config, internally. However, I wanted to include the parent name alongside the cmd_start event, which happens very early (maybe before config gathering?). Maybe it's better to log the parent_name as its own event, since it shouldn't change over the lifetime of the process? procfs is very non-portable, though - I think this won't even work on MacOS. So I'm curious if anybody has better suggestions for how to do this. - Emily Makefile | 1 + compat/procinfo.c | 19 +++++++++++++++++++ git-compat-util.h | 6 ++++++ t/t0212-trace2-event.sh | 8 ++++++++ t/t0212/parse_events.perl | 1 + trace2/tr2_tgt_event.c | 3 +++ 6 files changed, 38 insertions(+) create mode 100644 compat/procinfo.c diff --git a/Makefile b/Makefile index 93664d6714..19f5189c6f 100644 --- a/Makefile +++ b/Makefile @@ -855,6 +855,7 @@ LIB_OBJS += commit-graph.o LIB_OBJS += commit-reach.o LIB_OBJS += commit.o LIB_OBJS += compat/obstack.o +LIB_OBJS += compat/procinfo.o LIB_OBJS += compat/terminal.o LIB_OBJS += config.o LIB_OBJS += connect.o diff --git a/compat/procinfo.c b/compat/procinfo.c new file mode 100644 index 0000000000..7f4c8dd284 --- /dev/null +++ b/compat/procinfo.c @@ -0,0 +1,19 @@ +#include "git-compat-util.h" + +#include "strbuf.h" + +char *get_process_name(int pid) +{ + struct strbuf procfs_path = STRBUF_INIT; + struct strbuf out = STRBUF_INIT; + /* try to use procfs if it's present. */ + strbuf_addf(&procfs_path, "/proc/%d/cmdline", pid); + if (strbuf_read_file(&out, procfs_path.buf, 0) > 0) + { + strbuf_release(&procfs_path); + return strbuf_detach(&out, NULL); + } + + /* NEEDSWORK: add non-procfs implementations here. */ + return NULL; +} diff --git a/git-compat-util.h b/git-compat-util.h index a508dbe5a3..cc7d5d8a2a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -1382,4 +1382,10 @@ static inline void *container_of_or_null_offset(void *ptr, size_t offset) void sleep_millisec(int millisec); +/* + * Convert PID to process name (as would show in top/task manager). Returns + * NULL if unimplemented - be sure to check for NULL at callsite. + */ +char *get_process_name(int pid); + #endif diff --git a/t/t0212-trace2-event.sh b/t/t0212-trace2-event.sh index 1529155cf0..3a2a8a5b5f 100755 --- a/t/t0212-trace2-event.sh +++ b/t/t0212-trace2-event.sh @@ -61,6 +61,7 @@ test_expect_success JSON_PP 'event stream, error event' ' | "exit_code":0, | "hierarchy":"trace2", | "name":"trace2", + | "parent_name":"/bin/sh", | "version":"$V" | } |}; @@ -115,6 +116,7 @@ test_expect_success JSON_PP 'event stream, return code 0' ' | "exit_code":0, | "hierarchy":"trace2", | "name":"trace2", + | "parent_name":"/bin/sh", | "version":"$V" | }, | "_SID0_/_SID1_":{ @@ -143,6 +145,7 @@ test_expect_success JSON_PP 'event stream, return code 0' ' | "exit_code":0, | "hierarchy":"trace2/trace2", | "name":"trace2", + | "parent_name":"test-tool", | "version":"$V" | }, | "_SID0_/_SID1_/_SID2_":{ @@ -155,6 +158,7 @@ test_expect_success JSON_PP 'event stream, return code 0' ' | "exit_code":0, | "hierarchy":"trace2/trace2/trace2", | "name":"trace2", + | "parent_name":"$TEST_DIRECTORY/../t/helper//test-tool", | "version":"$V" | } |}; @@ -192,6 +196,7 @@ test_expect_success JSON_PP 'event stream, list config' ' | "value":"hello world" | } | ], + | "parent_name":"/bin/sh", | "version":"$V" | } |}; @@ -229,6 +234,7 @@ test_expect_success JSON_PP 'event stream, list env vars' ' | "value":"hello world" | } | ], + | "parent_name":"/bin/sh", | "version":"$V" | } |}; @@ -263,6 +269,7 @@ test_expect_success JSON_PP 'basic trace2_data' ' | "exit_code":0, | "hierarchy":"trace2", | "name":"trace2", + | "parent_name":"/bin/sh", | "version":"$V" | } |}; @@ -295,6 +302,7 @@ test_expect_success JSON_PP 'using global config, event stream, error event' ' | "exit_code":0, | "hierarchy":"trace2", | "name":"trace2", + | "parent_name":"/bin/sh", | "version":"$V" | } |}; diff --git a/t/t0212/parse_events.perl b/t/t0212/parse_events.perl index 6584bb5634..dd8b1be844 100644 --- a/t/t0212/parse_events.perl +++ b/t/t0212/parse_events.perl @@ -99,6 +99,7 @@ } elsif ($event eq 'start') { + $processes->{$sid}->{'parent_name'} = $line->{'parent_name'}; $processes->{$sid}->{'argv'} = $line->{'argv'}; $processes->{$sid}->{'argv'}[0] = "_EXE_"; } diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c index 6353e8ad91..d258d5807c 100644 --- a/trace2/tr2_tgt_event.c +++ b/trace2/tr2_tgt_event.c @@ -145,10 +145,12 @@ static void fn_start_fl(const char *file, int line, const char *event_name = "start"; struct json_writer jw = JSON_WRITER_INIT; double t_abs = (double)us_elapsed_absolute / 1000000.0; + char *parent_name = get_process_name(getppid()); jw_object_begin(&jw, 0); event_fmt_prepare(event_name, file, line, NULL, &jw); jw_object_double(&jw, "t_abs", 6, t_abs); + jw_object_string(&jw, "parent_name", parent_name ? parent_name : NULL ); jw_object_inline_begin_array(&jw, "argv"); jw_array_argv(&jw, argv); jw_end(&jw); @@ -156,6 +158,7 @@ static void fn_start_fl(const char *file, int line, tr2_dst_write_line(&tr2dst_event, &jw.json); jw_release(&jw); + free(parent_name); } static void fn_exit_fl(const char *file, int line, uint64_t us_elapsed_absolute, -- 2.31.1.607.g51e8a6a459-goog