зеркало из https://github.com/microsoft/git.git
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:
Коммит
6f64eeab60
|
@ -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.
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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'};
|
||||||
|
|
13
trace2.c
13
trace2.c
|
@ -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;
|
||||||
|
|
16
trace2.h
16
trace2.h
|
@ -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,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче