On Thu, Mar 21 2019, Josh Steadmon wrote: > When the value of a trace2 environment variable is an absolute path > referring to an existing directory, write output to files (one per > process) underneath the given directory. Files will be named according > to the final component of the trace2 SID, followed by a counter to avoid > potential collisions. Is this "counter to avoid collisions" something you've seen the need to have in practice, or could we just squash this on top: diff --git a/trace2/tr2_dst.c b/trace2/tr2_dst.c index c3d82ca6a4..06cbef5837 100644 --- a/trace2/tr2_dst.c +++ b/trace2/tr2_dst.c @@ -13,11 +13,6 @@ */ #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; @@ -48,7 +43,6 @@ static int tr2_dst_try_auto_path(struct tr2_dst *dst, const char *tgt_prefix) 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) @@ -60,17 +54,7 @@ static int tr2_dst_try_auto_path(struct tr2_dst *dst, const char *tgt_prefix) 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; - } - + fd = open(path.buf, O_WRONLY | O_CREAT | O_EXCL, 0666); if (fd == -1) { if (tr2_dst_want_warning()) warning("trace2: could not open '%.*s' for '%s' tracing: %s", The reason I'm raising this is that it seems like sweeping an existing issue under the rug. We document that the "sid" is "unique", and it's just: <nanotime / 1000 (i.e. *nix time in microseconds)>-<pid> So that might be a lie, and in particular I can imagine that say if every machine at Google is logging traces into some magic mounted FS that there'll be collisions there. But then let's *fix that*, because we're also e.g. going to have other consumers of these traces using the sid's as primary keys in a logging system. I wonder if we should just make it a bit longer, human-readable, and include a hash of the hostname: perl -MTime::HiRes=gettimeofday -MSys::Hostname -MDigest::SHA=sha1_hex -MPOSIX=strftime -wE ' my ($t, $m) = gettimeofday; my $host_hex = substr sha1_hex(hostname()), 0, 8; my $htime = strftime("%Y%m%d%H%M%S", localtime); my $sid = sprintf("%s-%6d-%s-%s", $htime, $m, $host_hex, $$ & 0xFFFF, ); say $sid; ' Which gets you a SID like: 20190323213918-404788-c2f5b994-19027 I.e.: <YYYYMMDDHHMMSS>-<microsecond-offset>-<8 chars of sha1(hostname -f)>-<pid> There's obviously ways to make that more compact, but in this case I couldn't see a reason to, also using UTC would be a good idea. All the trace2 tests pass if I fake that up. Jeff H: Do you have anything that relies on the current format? > This makes it more convenient to collect traces for every git invocation > by unconditionally setting the relevant trace2 envvar to a constant > directory name. > > Signed-off-by: Josh Steadmon <steadmon@xxxxxxxxxx> > --- > Documentation/technical/api-trace2.txt | 5 ++ > t/t0210-trace2-normal.sh | 15 ++++++ > 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))