Skip to content

Commit f0d5a7b

Browse files
committed
trace: add GIT_TRACE_STDIN
Sometimes tracing the invocation of git programs with GIT_TRACE is not quite enough to replay a situation; the interesting input to the program often comes over its standard input. For instance, if you want to replay a particular fetch (e.g., for performance analysis or debugging), you would want both the arguments and stdin sent to pack-objects. This patch lets you capture the stdin of any git process. For instance: GIT_TRACE=/tmp/processes.out \ GIT_TRACE_STDIN=/tmp/stdin.%p \ git daemon ... After a fetch, processes.out will contain a line like: 15:19:08.275493 [pid=13196] git.c:348 trace: built-in: git 'pack-objects' '--revs' '--thin' '--stdout' '--progress' '--delta-base-offset' And stdin.13196 (the pid picked from the above line) will contain its stdin. Signed-off-by: Jeff King <peff@peff.net>
1 parent 562a4d8 commit f0d5a7b

1 file changed

Lines changed: 60 additions & 0 deletions

File tree

git.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,65 @@ static int run_argv(struct strvec *args)
913913
return done_alias;
914914
}
915915

916+
static int copy_stdin(int in, int out, void *data)
917+
{
918+
struct trace_key *key = data;
919+
while (1) {
920+
char buf[8192];
921+
ssize_t len = xread(in, buf, sizeof(buf));
922+
if (!len)
923+
break;
924+
if (len < 0) {
925+
warning("error reading stdin trace: %s",
926+
strerror(errno));
927+
break;
928+
}
929+
930+
trace_verbatim(key, buf, len);
931+
if (write_in_full(out, buf, len) < 0) {
932+
warning("error writing stdin trace: %s",
933+
strerror(errno));
934+
break;
935+
}
936+
}
937+
close(in);
938+
close(out);
939+
return 0;
940+
}
941+
942+
static void trace_stdin(void)
943+
{
944+
static struct trace_key key = TRACE_KEY_INIT(STDIN);
945+
static struct async async;
946+
947+
if (!trace_want(&key))
948+
return;
949+
950+
memset(&async, 0, sizeof(async));
951+
async.proc = copy_stdin;
952+
async.data = &key;
953+
async.in = dup(0);
954+
async.out = -1;
955+
956+
if (async.in < 0 || start_async(&async) < 0) {
957+
warning("unable to trace stdin: %s", strerror(errno));
958+
return ;
959+
}
960+
961+
/*
962+
* At this point we've handed stdin off to the async process,
963+
* so there we are past the point of no return.
964+
*/
965+
if (dup2(async.out, 0))
966+
die_errno("unable to redirect stdin from async process");
967+
close(async.out);
968+
969+
/*
970+
* leak async; we would know to finish_async() only when we are
971+
* exiting, and there is no point then
972+
*/
973+
}
974+
916975
int cmd_main(int argc, const char **argv)
917976
{
918977
struct strvec args = STRVEC_INIT;
@@ -929,6 +988,7 @@ int cmd_main(int argc, const char **argv)
929988
}
930989

931990
trace_command_performance(argv);
991+
trace_stdin();
932992

933993
/*
934994
* "git-xxxx" is the same as "git xxxx", but we obviously:

0 commit comments

Comments
 (0)