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
This commit is contained in:
Junio C Hamano 2021-08-24 15:32:40 -07:00
Родитель 276bc6357e 2f732bf15e
Коммит 6f64eeab60
14 изменённых файлов: 184 добавлений и 7 удалений

Просмотреть файл

@ -493,6 +493,20 @@ about specific error arguments.
} }
------------ ------------
`"cmd_ancestry"`::
This event contains the text command name for the parent (and earlier
generations of parents) of the current process, in an array ordered from
nearest parent to furthest great-grandparent. It may not be implemented
on all platforms.
+
------------
{
"event":"cmd_ancestry",
...
"ancestry":["bash","tmux: server","systemd"]
}
------------
`"cmd_name"`:: `"cmd_name"`::
This event contains the command name for this git process This event contains the command name for this git process
and the hierarchy of commands from parent git processes. and the hierarchy of commands from parent git processes.

Просмотреть файл

@ -1917,6 +1917,10 @@ ifneq ($(PROCFS_EXECUTABLE_PATH),)
BASIC_CFLAGS += '-DPROCFS_EXECUTABLE_PATH="$(procfs_executable_path_SQ)"' BASIC_CFLAGS += '-DPROCFS_EXECUTABLE_PATH="$(procfs_executable_path_SQ)"'
endif endif
ifndef HAVE_PLATFORM_PROCINFO
COMPAT_OBJS += compat/stub/procinfo.o
endif
ifdef HAVE_NS_GET_EXECUTABLE_PATH ifdef HAVE_NS_GET_EXECUTABLE_PATH
BASIC_CFLAGS += -DHAVE_NS_GET_EXECUTABLE_PATH BASIC_CFLAGS += -DHAVE_NS_GET_EXECUTABLE_PATH
endif endif

55
compat/linux/procinfo.c Normal file
Просмотреть файл

@ -0,0 +1,55 @@
#include "cache.h"
#include "strbuf.h"
#include "strvec.h"
#include "trace2.h"
static void get_ancestry_names(struct strvec *names)
{
/*
* NEEDSWORK: We could gather the entire pstree into an array to match
* functionality with compat/win32/trace2_win32_process_info.c.
* To do so, we may want to examine /proc/<pid>/stat. For now, just
* gather the immediate parent name which is readily accessible from
* /proc/$(getppid())/comm.
*/
struct strbuf procfs_path = STRBUF_INIT;
struct strbuf name = STRBUF_INIT;
/* try to use procfs if it's present. */
strbuf_addf(&procfs_path, "/proc/%d/comm", getppid());
if (strbuf_read_file(&name, procfs_path.buf, 0)) {
strbuf_release(&procfs_path);
strbuf_trim_trailing_newline(&name);
strvec_push(names, strbuf_detach(&name, NULL));
}
return;
/* NEEDSWORK: add non-procfs-linux implementations here */
}
void trace2_collect_process_info(enum trace2_process_info_reason reason)
{
if (!trace2_is_enabled())
return;
/* someday we may want to write something extra here, but not today */
if (reason == TRACE2_PROCESS_INFO_EXIT)
return;
if (reason == TRACE2_PROCESS_INFO_STARTUP) {
/*
* NEEDSWORK: we could do the entire ptree in an array instead,
* see compat/win32/trace2_win32_process_info.c.
*/
struct strvec names = STRVEC_INIT;
get_ancestry_names(&names);
if (names.nr)
trace2_cmd_ancestry(names.v);
strvec_clear(&names);
}
return;
}

11
compat/stub/procinfo.c Normal file
Просмотреть файл

@ -0,0 +1,11 @@
#include "git-compat-util.h"
#include "trace2.h"
/*
* Stub. See sample implementations in compat/linux/procinfo.c and
* compat/win32/trace2_win32_process_info.c.
*/
void trace2_collect_process_info(enum trace2_process_info_reason reason)
{
}

Просмотреть файл

@ -58,6 +58,8 @@ ifeq ($(uname_S),Linux)
FREAD_READS_DIRECTORIES = UnfortunatelyYes FREAD_READS_DIRECTORIES = UnfortunatelyYes
BASIC_CFLAGS += -DHAVE_SYSINFO BASIC_CFLAGS += -DHAVE_SYSINFO
PROCFS_EXECUTABLE_PATH = /proc/self/exe PROCFS_EXECUTABLE_PATH = /proc/self/exe
HAVE_PLATFORM_PROCINFO = YesPlease
COMPAT_OBJS += compat/linux/procinfo.o
endif endif
ifeq ($(uname_S),GNU/kFreeBSD) ifeq ($(uname_S),GNU/kFreeBSD)
HAVE_ALLOCA_H = YesPlease HAVE_ALLOCA_H = YesPlease
@ -617,6 +619,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
ETAGS_TARGET = ETAGS ETAGS_TARGET = ETAGS
NO_POSIX_GOODIES = UnfortunatelyYes NO_POSIX_GOODIES = UnfortunatelyYes
DEFAULT_HELP_FORMAT = html DEFAULT_HELP_FORMAT = html
HAVE_PLATFORM_PROCINFO = YesPlease
BASIC_LDFLAGS += -municode BASIC_LDFLAGS += -municode
COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32 COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"

Просмотреть файл

@ -42,6 +42,12 @@ while (<>) {
# so just omit it for testing purposes. # so just omit it for testing purposes.
# print "cmd_path _EXE_\n"; # print "cmd_path _EXE_\n";
} }
elsif ($line =~ m/^cmd_ancestry/) {
# 'cmd_ancestry' is not implemented everywhere, so for portability's
# sake, skip it when parsing normal.
#
# print "$line";
}
else { else {
print "$line"; print "$line";
} }

Просмотреть файл

@ -44,6 +44,11 @@ while (<>) {
# $tokens[$col_rest] = "_EXE_"; # $tokens[$col_rest] = "_EXE_";
goto SKIP_LINE; goto SKIP_LINE;
} }
elsif ($tokens[$col_event] =~ m/cmd_ancestry/) {
# 'cmd_ancestry' is platform-specific and not implemented everywhere,
# so skip it.
goto SKIP_LINE;
}
elsif ($tokens[$col_event] =~ m/child_exit/) { elsif ($tokens[$col_event] =~ m/child_exit/) {
$tokens[$col_rest] =~ s/ pid:\d* / pid:_PID_ /; $tokens[$col_rest] =~ s/ pid:\d* / pid:_PID_ /;
} }

Просмотреть файл

@ -132,7 +132,10 @@ while (<>) {
# just omit it for testing purposes. # just omit it for testing purposes.
# $processes->{$sid}->{'path'} = "_EXE_"; # $processes->{$sid}->{'path'} = "_EXE_";
} }
elsif ($event eq 'cmd_ancestry') {
# 'cmd_ancestry' is platform-specific and not implemented everywhere, so
# just skip it for testing purposes.
}
elsif ($event eq 'cmd_name') { elsif ($event eq 'cmd_name') {
$processes->{$sid}->{'name'} = $line->{'name'}; $processes->{$sid}->{'name'} = $line->{'name'};
$processes->{$sid}->{'hierarchy'} = $line->{'hierarchy'}; $processes->{$sid}->{'hierarchy'} = $line->{'hierarchy'};

Просмотреть файл

@ -260,6 +260,19 @@ void trace2_cmd_path_fl(const char *file, int line, const char *pathname)
tgt_j->pfn_command_path_fl(file, line, pathname); tgt_j->pfn_command_path_fl(file, line, pathname);
} }
void trace2_cmd_ancestry_fl(const char *file, int line, const char **parent_names)
{
struct tr2_tgt *tgt_j;
int j;
if (!trace2_enabled)
return;
for_each_wanted_builtin (j, tgt_j)
if (tgt_j->pfn_command_ancestry_fl)
tgt_j->pfn_command_ancestry_fl(file, line, parent_names);
}
void trace2_cmd_name_fl(const char *file, int line, const char *name) void trace2_cmd_name_fl(const char *file, int line, const char *name)
{ {
struct tr2_tgt *tgt_j; struct tr2_tgt *tgt_j;

Просмотреть файл

@ -133,6 +133,16 @@ void trace2_cmd_path_fl(const char *file, int line, const char *pathname);
#define trace2_cmd_path(p) trace2_cmd_path_fl(__FILE__, __LINE__, (p)) #define trace2_cmd_path(p) trace2_cmd_path_fl(__FILE__, __LINE__, (p))
/*
* Emit an 'ancestry' event with the process name of the current process's
* parent process.
* This gives post-processors a way to determine what invoked the command and
* learn more about usage patterns.
*/
void trace2_cmd_ancestry_fl(const char *file, int line, const char **parent_names);
#define trace2_cmd_ancestry(v) trace2_cmd_ancestry_fl(__FILE__, __LINE__, (v))
/* /*
* Emit a 'cmd_name' event with the canonical name of the command. * Emit a 'cmd_name' event with the canonical name of the command.
* This gives post-processors a simple field to identify the command * This gives post-processors a simple field to identify the command
@ -492,13 +502,7 @@ enum trace2_process_info_reason {
TRACE2_PROCESS_INFO_EXIT, TRACE2_PROCESS_INFO_EXIT,
}; };
#if defined(GIT_WINDOWS_NATIVE)
void trace2_collect_process_info(enum trace2_process_info_reason reason); void trace2_collect_process_info(enum trace2_process_info_reason reason);
#else
#define trace2_collect_process_info(reason) \
do { \
} while (0)
#endif
const char *trace2_session_id(void); const char *trace2_session_id(void);

Просмотреть файл

@ -27,6 +27,8 @@ typedef void(tr2_tgt_evt_error_va_fl_t)(const char *file, int line,
typedef void(tr2_tgt_evt_command_path_fl_t)(const char *file, int line, typedef void(tr2_tgt_evt_command_path_fl_t)(const char *file, int line,
const char *command_path); const char *command_path);
typedef void(tr2_tgt_evt_command_ancestry_fl_t)(const char *file, int line,
const char **parent_names);
typedef void(tr2_tgt_evt_command_name_fl_t)(const char *file, int line, typedef void(tr2_tgt_evt_command_name_fl_t)(const char *file, int line,
const char *name, const char *name,
const char *hierarchy); const char *hierarchy);
@ -108,6 +110,7 @@ struct tr2_tgt {
tr2_tgt_evt_atexit_t *pfn_atexit; tr2_tgt_evt_atexit_t *pfn_atexit;
tr2_tgt_evt_error_va_fl_t *pfn_error_va_fl; tr2_tgt_evt_error_va_fl_t *pfn_error_va_fl;
tr2_tgt_evt_command_path_fl_t *pfn_command_path_fl; tr2_tgt_evt_command_path_fl_t *pfn_command_path_fl;
tr2_tgt_evt_command_ancestry_fl_t *pfn_command_ancestry_fl;
tr2_tgt_evt_command_name_fl_t *pfn_command_name_fl; tr2_tgt_evt_command_name_fl_t *pfn_command_name_fl;
tr2_tgt_evt_command_mode_fl_t *pfn_command_mode_fl; tr2_tgt_evt_command_mode_fl_t *pfn_command_mode_fl;
tr2_tgt_evt_alias_fl_t *pfn_alias_fl; tr2_tgt_evt_alias_fl_t *pfn_alias_fl;

Просмотреть файл

@ -261,6 +261,26 @@ static void fn_command_path_fl(const char *file, int line, const char *pathname)
jw_release(&jw); jw_release(&jw);
} }
static void fn_command_ancestry_fl(const char *file, int line, const char **parent_names)
{
const char *event_name = "cmd_ancestry";
const char *parent_name = NULL;
struct json_writer jw = JSON_WRITER_INIT;
jw_object_begin(&jw, 0);
event_fmt_prepare(event_name, file, line, NULL, &jw);
jw_object_inline_begin_array(&jw, "ancestry");
while ((parent_name = *parent_names++))
jw_array_string(&jw, parent_name);
jw_end(&jw); /* 'ancestry' array */
jw_end(&jw); /* event object */
tr2_dst_write_line(&tr2dst_event, &jw.json);
jw_release(&jw);
}
static void fn_command_name_fl(const char *file, int line, const char *name, static void fn_command_name_fl(const char *file, int line, const char *name,
const char *hierarchy) const char *hierarchy)
{ {
@ -584,6 +604,7 @@ struct tr2_tgt tr2_tgt_event = {
fn_atexit, fn_atexit,
fn_error_va_fl, fn_error_va_fl,
fn_command_path_fl, fn_command_path_fl,
fn_command_ancestry_fl,
fn_command_name_fl, fn_command_name_fl,
fn_command_mode_fl, fn_command_mode_fl,
fn_alias_fl, fn_alias_fl,

Просмотреть файл

@ -160,6 +160,24 @@ static void fn_command_path_fl(const char *file, int line, const char *pathname)
strbuf_release(&buf_payload); strbuf_release(&buf_payload);
} }
static void fn_command_ancestry_fl(const char *file, int line, const char **parent_names)
{
const char *parent_name = NULL;
struct strbuf buf_payload = STRBUF_INIT;
/* cmd_ancestry parent <- grandparent <- great-grandparent */
strbuf_addstr(&buf_payload, "cmd_ancestry ");
while ((parent_name = *parent_names++)) {
strbuf_addstr(&buf_payload, parent_name);
/* if we'll write another one after this, add a delimiter */
if (parent_names && *parent_names)
strbuf_addstr(&buf_payload, " <- ");
}
normal_io_write_fl(file, line, &buf_payload);
strbuf_release(&buf_payload);
}
static void fn_command_name_fl(const char *file, int line, const char *name, static void fn_command_name_fl(const char *file, int line, const char *name,
const char *hierarchy) const char *hierarchy)
{ {
@ -306,6 +324,7 @@ struct tr2_tgt tr2_tgt_normal = {
fn_atexit, fn_atexit,
fn_error_va_fl, fn_error_va_fl,
fn_command_path_fl, fn_command_path_fl,
fn_command_ancestry_fl,
fn_command_name_fl, fn_command_name_fl,
fn_command_mode_fl, fn_command_mode_fl,
fn_alias_fl, fn_alias_fl,

Просмотреть файл

@ -253,6 +253,21 @@ static void fn_command_path_fl(const char *file, int line, const char *pathname)
strbuf_release(&buf_payload); strbuf_release(&buf_payload);
} }
static void fn_command_ancestry_fl(const char *file, int line, const char **parent_names)
{
const char *event_name = "cmd_ancestry";
struct strbuf buf_payload = STRBUF_INIT;
strbuf_addstr(&buf_payload, "ancestry:[");
/* It's not an argv but the rules are basically the same. */
sq_append_quote_argv_pretty(&buf_payload, parent_names);
strbuf_addch(&buf_payload, ']');
perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
&buf_payload);
strbuf_release(&buf_payload);
}
static void fn_command_name_fl(const char *file, int line, const char *name, static void fn_command_name_fl(const char *file, int line, const char *name,
const char *hierarchy) const char *hierarchy)
{ {
@ -532,6 +547,7 @@ struct tr2_tgt tr2_tgt_perf = {
fn_atexit, fn_atexit,
fn_error_va_fl, fn_error_va_fl,
fn_command_path_fl, fn_command_path_fl,
fn_command_ancestry_fl,
fn_command_name_fl, fn_command_name_fl,
fn_command_mode_fl, fn_command_mode_fl,
fn_alias_fl, fn_alias_fl,