diff options
-rw-r--r-- | Documentation/technical/api-trace2.txt | 5 | ||||
-rwxr-xr-x | t/t0210-trace2-normal.sh | 15 | ||||
-rw-r--r-- | trace2/tr2_dst.c | 63 |
3 files changed, 81 insertions, 2 deletions
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt index 2de565fa3d..d0948ba250 100644 --- a/Documentation/technical/api-trace2.txt +++ b/Documentation/technical/api-trace2.txt @@ -109,6 +109,11 @@ values are recognized. Enables the target, opens and writes to the file in append mode. + If the target already exists and is a directory, the traces will be + written to files (one per process) underneath the given directory. They + will be named according to the last component of the SID (optionally + followed by a counter to avoid filename collisions). + `af_unix:[<socket_type>:]<absolute-pathname>`:: Enables the target, opens and writes to a Unix Domain Socket diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh index 03a0aedb1d..819430658b 100755 --- a/t/t0210-trace2-normal.sh +++ b/t/t0210-trace2-normal.sh @@ -80,6 +80,21 @@ test_expect_success 'normal stream, return code 1' ' test_cmp expect actual ' +test_expect_success 'automatic filename' ' + test_when_finished "rm -r traces actual expect" && + mkdir traces && + GIT_TR2="$(pwd)/traces" test-tool trace2 001return 0 && + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <"$(ls traces/*)" >actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 001return 0 + cmd_name trace2 (trace2) + exit elapsed:_TIME_ code:0 + atexit elapsed:_TIME_ code:0 + EOF + test_cmp expect actual +' + # Verb 002exit # # Explicit exit(code) from within cmd_<verb> propagates <code>. diff --git a/trace2/tr2_dst.c b/trace2/tr2_dst.c index fd490a43ad..c3d82ca6a4 100644 --- a/trace2/tr2_dst.c +++ b/trace2/tr2_dst.c @@ -1,5 +1,6 @@ #include "cache.h" #include "trace2/tr2_dst.h" +#include "trace2/tr2_sid.h" /* * If a Trace2 target cannot be opened for writing, we should issue a @@ -12,6 +13,11 @@ */ #define TR2_ENVVAR_DST_DEBUG "GIT_TR2_DST_DEBUG" +/* + * How many attempts we will make at creating an automatically-named trace file. + */ +#define MAX_AUTO_ATTEMPTS 10 + static int tr2_dst_want_warning(void) { static int tr2env_dst_debug = -1; @@ -36,6 +42,55 @@ void tr2_dst_trace_disable(struct tr2_dst *dst) dst->need_close = 0; } +static int tr2_dst_try_auto_path(struct tr2_dst *dst, const char *tgt_prefix) +{ + int fd; + const char *last_slash, *sid = tr2_sid_get(); + struct strbuf path = STRBUF_INIT; + size_t base_path_len; + unsigned attempt_count; + + last_slash = strrchr(sid, '/'); + if (last_slash) + sid = last_slash + 1; + + strbuf_addstr(&path, tgt_prefix); + if (!is_dir_sep(path.buf[path.len - 1])) + strbuf_addch(&path, '/'); + strbuf_addstr(&path, sid); + base_path_len = path.len; + + for (attempt_count = 0; attempt_count < MAX_AUTO_ATTEMPTS; attempt_count++) { + if (attempt_count > 0) { + strbuf_setlen(&path, base_path_len); + strbuf_addf(&path, ".%d", attempt_count); + } + + fd = open(path.buf, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (fd != -1) + break; + } + + if (fd == -1) { + if (tr2_dst_want_warning()) + warning("trace2: could not open '%.*s' for '%s' tracing: %s", + (int) base_path_len, path.buf, + dst->env_var_name, strerror(errno)); + + tr2_dst_trace_disable(dst); + strbuf_release(&path); + return 0; + } + + strbuf_release(&path); + + dst->fd = fd; + dst->need_close = 1; + dst->initialized = 1; + + return dst->fd; +} + static int tr2_dst_try_path(struct tr2_dst *dst, const char *tgt_value) { int fd = open(tgt_value, O_WRONLY | O_APPEND | O_CREAT, 0666); @@ -202,8 +257,12 @@ int tr2_dst_get_trace_fd(struct tr2_dst *dst) return dst->fd; } - if (is_absolute_path(tgt_value)) - return tr2_dst_try_path(dst, tgt_value); + if (is_absolute_path(tgt_value)) { + if (is_directory(tgt_value)) + return tr2_dst_try_auto_path(dst, tgt_value); + else + return tr2_dst_try_path(dst, tgt_value); + } #ifndef NO_UNIX_SOCKETS if (starts_with(tgt_value, PREFIX_AF_UNIX)) |