about summary refs log tree commit diff
path: root/third_party/git/trace2
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2020-11-21T18·20+0100
committerVincent Ambo <mail@tazj.in>2020-11-21T18·45+0100
commitf4609b896fac842433bd495c166d5987852a6a73 (patch)
tree95511c465c54c4f5d27e5d39ce187e2a1dd82bd3 /third_party/git/trace2
parent082c006c04343a78d87b6c6ab3608c25d6213c3f (diff)
merge(3p/git): Merge git subtree at v2.29.2 r/1890
This also bumps the stable nixpkgs to 20.09 as of 2020-11-21, because
there is some breakage in the git build related to the netrc
credentials helper which someone has taken care of in nixpkgs.

The stable channel is not used for anything other than git, so this
should be fine.

Change-Id: I3575a19dab09e1e9556cf8231d717de9890484fb
Diffstat (limited to 'third_party/git/trace2')
-rw-r--r--third_party/git/trace2/tr2_cfg.c58
-rw-r--r--third_party/git/trace2/tr2_cfg.h8
-rw-r--r--third_party/git/trace2/tr2_dst.c120
-rw-r--r--third_party/git/trace2/tr2_dst.h1
-rw-r--r--third_party/git/trace2/tr2_sid.c2
-rw-r--r--third_party/git/trace2/tr2_sysenv.c5
-rw-r--r--third_party/git/trace2/tr2_sysenv.h3
-rw-r--r--third_party/git/trace2/tr2_tgt_event.c36
-rw-r--r--third_party/git/trace2/tr2_tgt_normal.c37
-rw-r--r--third_party/git/trace2/tr2_tgt_perf.c108
10 files changed, 283 insertions, 95 deletions
diff --git a/third_party/git/trace2/tr2_cfg.c b/third_party/git/trace2/tr2_cfg.c
index caa7f06948..ec9ac1a6ef 100644
--- a/third_party/git/trace2/tr2_cfg.c
+++ b/third_party/git/trace2/tr2_cfg.c
@@ -7,6 +7,10 @@ static struct strbuf **tr2_cfg_patterns;
 static int tr2_cfg_count_patterns;
 static int tr2_cfg_loaded;
 
+static struct strbuf **tr2_cfg_env_vars;
+static int tr2_cfg_env_vars_count;
+static int tr2_cfg_env_vars_loaded;
+
 /*
  * Parse a string containing a comma-delimited list of config keys
  * or wildcard patterns into a list of strbufs.
@@ -46,6 +50,45 @@ void tr2_cfg_free_patterns(void)
 	tr2_cfg_loaded = 0;
 }
 
+/*
+ * Parse a string containing a comma-delimited list of environment variable
+ * names into a list of strbufs.
+ */
+static int tr2_load_env_vars(void)
+{
+	struct strbuf **s;
+	const char *varlist;
+
+	if (tr2_cfg_env_vars_loaded)
+		return tr2_cfg_env_vars_count;
+	tr2_cfg_env_vars_loaded = 1;
+
+	varlist = tr2_sysenv_get(TR2_SYSENV_ENV_VARS);
+	if (!varlist || !*varlist)
+		return tr2_cfg_env_vars_count;
+
+	tr2_cfg_env_vars = strbuf_split_buf(varlist, strlen(varlist), ',', -1);
+	for (s = tr2_cfg_env_vars; *s; s++) {
+		struct strbuf *buf = *s;
+
+		if (buf->len && buf->buf[buf->len - 1] == ',')
+			strbuf_setlen(buf, buf->len - 1);
+		strbuf_trim_trailing_newline(*s);
+		strbuf_trim(*s);
+	}
+
+	tr2_cfg_env_vars_count = s - tr2_cfg_env_vars;
+	return tr2_cfg_env_vars_count;
+}
+
+void tr2_cfg_free_env_vars(void)
+{
+	if (tr2_cfg_env_vars)
+		strbuf_list_free(tr2_cfg_env_vars);
+	tr2_cfg_env_vars_count = 0;
+	tr2_cfg_env_vars_loaded = 0;
+}
+
 struct tr2_cfg_data {
 	const char *file;
 	int line;
@@ -79,6 +122,21 @@ void tr2_cfg_list_config_fl(const char *file, int line)
 		read_early_config(tr2_cfg_cb, &data);
 }
 
+void tr2_list_env_vars_fl(const char *file, int line)
+{
+	struct strbuf **s;
+
+	if (tr2_load_env_vars() <= 0)
+		return;
+
+	for (s = tr2_cfg_env_vars; *s; s++) {
+		struct strbuf *buf = *s;
+		const char *val = getenv(buf->buf);
+		if (val && *val)
+			trace2_def_param_fl(file, line, buf->buf, val);
+	}
+}
+
 void tr2_cfg_set_fl(const char *file, int line, const char *key,
 		    const char *value)
 {
diff --git a/third_party/git/trace2/tr2_cfg.h b/third_party/git/trace2/tr2_cfg.h
index d9c98f64dd..a11d71feb5 100644
--- a/third_party/git/trace2/tr2_cfg.h
+++ b/third_party/git/trace2/tr2_cfg.h
@@ -8,6 +8,12 @@
 void tr2_cfg_list_config_fl(const char *file, int line);
 
 /*
+ * Iterate over all "interesting" environment variables and emit 'def_param'
+ * events for them to TRACE2.
+ */
+void tr2_list_env_vars_fl(const char *file, int line);
+
+/*
  * Emit a "def_param" event for the given key/value pair IF we consider
  * the key to be "interesting".
  */
@@ -16,4 +22,6 @@ void tr2_cfg_set_fl(const char *file, int line, const char *key,
 
 void tr2_cfg_free_patterns(void);
 
+void tr2_cfg_free_env_vars(void);
+
 #endif /* TR2_CFG_H */
diff --git a/third_party/git/trace2/tr2_dst.c b/third_party/git/trace2/tr2_dst.c
index 5dda0ca1cd..ae052a07fe 100644
--- a/third_party/git/trace2/tr2_dst.c
+++ b/third_party/git/trace2/tr2_dst.c
@@ -8,6 +8,19 @@
  */
 #define MAX_AUTO_ATTEMPTS 10
 
+/*
+ * Sentinel file used to detect when we should discard new traces to avoid
+ * writing too many trace files to a directory.
+ */
+#define DISCARD_SENTINEL_NAME "git-trace2-discard"
+
+/*
+ * When set to zero, disables directory file count checks. Otherwise, controls
+ * how many files we can write to a directory before entering discard mode.
+ * This can be overridden via the TR2_SYSENV_MAX_FILES setting.
+ */
+static int tr2env_max_files = 0;
+
 static int tr2_dst_want_warning(void)
 {
 	static int tr2env_dst_debug = -1;
@@ -32,9 +45,75 @@ void tr2_dst_trace_disable(struct tr2_dst *dst)
 	dst->need_close = 0;
 }
 
+/*
+ * Check to make sure we're not overloading the target directory with too many
+ * files. First get the threshold (if present) from the config or envvar. If
+ * it's zero or unset, disable this check. Next check for the presence of a
+ * sentinel file, then check file count.
+ *
+ * Returns 0 if tracing should proceed as normal. Returns 1 if the sentinel file
+ * already exists, which means tracing should be disabled. Returns -1 if there
+ * are too many files but there was no sentinel file, which means we have
+ * created and should write traces to the sentinel file.
+ *
+ * We expect that some trace processing system is gradually collecting files
+ * from the target directory; after it removes the sentinel file we'll start
+ * writing traces again.
+ */
+static int tr2_dst_too_many_files(struct tr2_dst *dst, const char *tgt_prefix)
+{
+	int file_count = 0, max_files = 0, ret = 0;
+	const char *max_files_var;
+	DIR *dirp;
+	struct strbuf path = STRBUF_INIT, sentinel_path = STRBUF_INIT;
+	struct stat statbuf;
+
+	/* Get the config or envvar and decide if we should continue this check */
+	max_files_var = tr2_sysenv_get(TR2_SYSENV_MAX_FILES);
+	if (max_files_var && *max_files_var && ((max_files = atoi(max_files_var)) >= 0))
+		tr2env_max_files = max_files;
+
+	if (!tr2env_max_files) {
+		ret = 0;
+		goto cleanup;
+	}
+
+	strbuf_addstr(&path, tgt_prefix);
+	if (!is_dir_sep(path.buf[path.len - 1])) {
+		strbuf_addch(&path, '/');
+	}
+
+	/* check sentinel */
+	strbuf_addbuf(&sentinel_path, &path);
+	strbuf_addstr(&sentinel_path, DISCARD_SENTINEL_NAME);
+	if (!stat(sentinel_path.buf, &statbuf)) {
+		ret = 1;
+		goto cleanup;
+	}
+
+	/* check file count */
+	dirp = opendir(path.buf);
+	while (file_count < tr2env_max_files && dirp && readdir(dirp))
+		file_count++;
+	if (dirp)
+		closedir(dirp);
+
+	if (file_count >= tr2env_max_files) {
+		dst->too_many_files = 1;
+		dst->fd = open(sentinel_path.buf, O_WRONLY | O_CREAT | O_EXCL, 0666);
+		ret = -1;
+		goto cleanup;
+	}
+
+cleanup:
+	strbuf_release(&path);
+	strbuf_release(&sentinel_path);
+	return ret;
+}
+
 static int tr2_dst_try_auto_path(struct tr2_dst *dst, const char *tgt_prefix)
 {
-	int fd;
+	int too_many_files;
 	const char *last_slash, *sid = tr2_sid_get();
 	struct strbuf path = STRBUF_INIT;
 	size_t base_path_len;
@@ -50,18 +129,29 @@ 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);
+	too_many_files = tr2_dst_too_many_files(dst, tgt_prefix);
+	if (!too_many_files) {
+		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);
+			}
+
+			dst->fd = open(path.buf, O_WRONLY | O_CREAT | O_EXCL, 0666);
+			if (dst->fd != -1)
+				break;
 		}
-
-		fd = open(path.buf, O_WRONLY | O_CREAT | O_EXCL, 0666);
-		if (fd != -1)
-			break;
+	} else if (too_many_files == 1) {
+		strbuf_release(&path);
+		if (tr2_dst_want_warning())
+			warning("trace2: not opening %s trace file due to too "
+				"many files in target directory %s",
+				tr2_sysenv_display_name(dst->sysenv_var),
+				tgt_prefix);
+		return 0;
 	}
 
-	if (fd == -1) {
+	if (dst->fd == -1) {
 		if (tr2_dst_want_warning())
 			warning("trace2: could not open '%.*s' for '%s' tracing: %s",
 				(int) base_path_len, path.buf,
@@ -75,7 +165,6 @@ static int tr2_dst_try_auto_path(struct tr2_dst *dst, const char *tgt_prefix)
 
 	strbuf_release(&path);
 
-	dst->fd = fd;
 	dst->need_close = 1;
 	dst->initialized = 1;
 
@@ -215,13 +304,8 @@ connected:
 static void tr2_dst_malformed_warning(struct tr2_dst *dst,
 				      const char *tgt_value)
 {
-	struct strbuf buf = STRBUF_INIT;
-
-	strbuf_addf(&buf, "trace2: unknown value for '%s': '%s'",
-		    tr2_sysenv_display_name(dst->sysenv_var), tgt_value);
-	warning("%s", buf.buf);
-
-	strbuf_release(&buf);
+	warning("trace2: unknown value for '%s': '%s'",
+		tr2_sysenv_display_name(dst->sysenv_var), tgt_value);
 }
 
 int tr2_dst_get_trace_fd(struct tr2_dst *dst)
diff --git a/third_party/git/trace2/tr2_dst.h b/third_party/git/trace2/tr2_dst.h
index 3adf3bac13..b1a8c144e0 100644
--- a/third_party/git/trace2/tr2_dst.h
+++ b/third_party/git/trace2/tr2_dst.h
@@ -9,6 +9,7 @@ struct tr2_dst {
 	int fd;
 	unsigned int initialized : 1;
 	unsigned int need_close : 1;
+	unsigned int too_many_files : 1;
 };
 
 /*
diff --git a/third_party/git/trace2/tr2_sid.c b/third_party/git/trace2/tr2_sid.c
index 6948fd4108..dc6e75ef13 100644
--- a/third_party/git/trace2/tr2_sid.c
+++ b/third_party/git/trace2/tr2_sid.c
@@ -19,7 +19,7 @@ static int tr2sid_nr_git_parents;
  *    "H<first_8_chars_of_sha1_of_hostname>"
  *    "Localhost" when no hostname.
  *
- * where <process> is a 9 character string containing the least signifcant
+ * where <process> is a 9 character string containing the least significant
  * 32 bits in the process-id.
  *    "P<pid>"
  * (This is an abribrary choice.  On most systems pid_t is a 32 bit value,
diff --git a/third_party/git/trace2/tr2_sysenv.c b/third_party/git/trace2/tr2_sysenv.c
index 5958cfc424..a380dcf910 100644
--- a/third_party/git/trace2/tr2_sysenv.c
+++ b/third_party/git/trace2/tr2_sysenv.c
@@ -29,6 +29,8 @@ struct tr2_sysenv_entry {
 static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
 	[TR2_SYSENV_CFG_PARAM]     = { "GIT_TRACE2_CONFIG_PARAMS",
 				       "trace2.configparams" },
+	[TR2_SYSENV_ENV_VARS]      = { "GIT_TRACE2_ENV_VARS",
+				       "trace2.envvars" },
 
 	[TR2_SYSENV_DST_DEBUG]     = { "GIT_TRACE2_DST_DEBUG",
 				       "trace2.destinationdebug" },
@@ -49,6 +51,9 @@ static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
 				       "trace2.perftarget" },
 	[TR2_SYSENV_PERF_BRIEF]    = { "GIT_TRACE2_PERF_BRIEF",
 				       "trace2.perfbrief" },
+
+	[TR2_SYSENV_MAX_FILES]     = { "GIT_TRACE2_MAX_FILES",
+				       "trace2.maxfiles" },
 };
 /* clang-format on */
 
diff --git a/third_party/git/trace2/tr2_sysenv.h b/third_party/git/trace2/tr2_sysenv.h
index 8dd82a7a56..3292ee15bc 100644
--- a/third_party/git/trace2/tr2_sysenv.h
+++ b/third_party/git/trace2/tr2_sysenv.h
@@ -11,6 +11,7 @@
  */
 enum tr2_sysenv_variable {
 	TR2_SYSENV_CFG_PARAM = 0,
+	TR2_SYSENV_ENV_VARS,
 
 	TR2_SYSENV_DST_DEBUG,
 
@@ -24,6 +25,8 @@ enum tr2_sysenv_variable {
 	TR2_SYSENV_PERF,
 	TR2_SYSENV_PERF_BRIEF,
 
+	TR2_SYSENV_MAX_FILES,
+
 	TR2_SYSENV_MUST_BE_LAST
 };
 
diff --git a/third_party/git/trace2/tr2_tgt_event.c b/third_party/git/trace2/tr2_tgt_event.c
index c2852d1bd2..6353e8ad91 100644
--- a/third_party/git/trace2/tr2_tgt_event.c
+++ b/third_party/git/trace2/tr2_tgt_event.c
@@ -10,16 +10,17 @@
 #include "trace2/tr2_tgt.h"
 #include "trace2/tr2_tls.h"
 
-static struct tr2_dst tr2dst_event = { TR2_SYSENV_EVENT, 0, 0, 0 };
+static struct tr2_dst tr2dst_event = { TR2_SYSENV_EVENT, 0, 0, 0, 0 };
 
 /*
- * The version number of the JSON data generated by the EVENT target
- * in this source file.  Update this if you make a significant change
- * to the JSON fields or message structure.  You probably do not need
- * to update this if you just add another call to one of the existing
- * TRACE2 API methods.
+ * The version number of the JSON data generated by the EVENT target in this
+ * source file. The version should be incremented if new event types are added,
+ * if existing fields are removed, or if there are significant changes in
+ * interpretation of existing events or fields. Smaller changes, such as adding
+ * a new field to an existing event, do not require an increment to the EVENT
+ * format version.
  */
-#define TR2_EVENT_VERSION "1"
+#define TR2_EVENT_VERSION "2"
 
 /*
  * Region nesting limit for messages written to the event target.
@@ -107,6 +108,19 @@ static void event_fmt_prepare(const char *event_name, const char *file,
 		jw_object_intmax(jw, "repo", repo->trace2_repo_id);
 }
 
+static void fn_too_many_files_fl(const char *file, int line)
+{
+	const char *event_name = "too_many_files";
+	struct json_writer jw = JSON_WRITER_INIT;
+
+	jw_object_begin(&jw, 0);
+	event_fmt_prepare(event_name, file, line, NULL, &jw);
+	jw_end(&jw);
+
+	tr2_dst_write_line(&tr2dst_event, &jw.json);
+	jw_release(&jw);
+}
+
 static void fn_version_fl(const char *file, int line)
 {
 	const char *event_name = "version";
@@ -120,6 +134,9 @@ static void fn_version_fl(const char *file, int line)
 
 	tr2_dst_write_line(&tr2dst_event, &jw.json);
 	jw_release(&jw);
+
+	if (tr2dst_event.too_many_files)
+		fn_too_many_files_fl(file, line);
 }
 
 static void fn_start_fl(const char *file, int line,
@@ -205,11 +222,6 @@ static void maybe_add_string_va(struct json_writer *jw, const char *field_name,
 		strbuf_release(&buf);
 		return;
 	}
-
-	if (fmt && *fmt) {
-		jw_object_string(jw, field_name, fmt);
-		return;
-	}
 }
 
 static void fn_error_va_fl(const char *file, int line, const char *fmt,
diff --git a/third_party/git/trace2/tr2_tgt_normal.c b/third_party/git/trace2/tr2_tgt_normal.c
index 00b116d797..31b602c171 100644
--- a/third_party/git/trace2/tr2_tgt_normal.c
+++ b/third_party/git/trace2/tr2_tgt_normal.c
@@ -9,7 +9,7 @@
 #include "trace2/tr2_tgt.h"
 #include "trace2/tr2_tls.h"
 
-static struct tr2_dst tr2dst_normal = { TR2_SYSENV_NORMAL, 0, 0, 0 };
+static struct tr2_dst tr2dst_normal = { TR2_SYSENV_NORMAL, 0, 0, 0, 0 };
 
 /*
  * Use the TR2_SYSENV_NORMAL_BRIEF setting to omit the "<time> <file>:<line>"
@@ -87,7 +87,7 @@ static void fn_start_fl(const char *file, int line,
 	struct strbuf buf_payload = STRBUF_INIT;
 
 	strbuf_addstr(&buf_payload, "start ");
-	sq_quote_argv_pretty(&buf_payload, argv);
+	sq_append_quote_argv_pretty(&buf_payload, argv);
 	normal_io_write_fl(file, line, &buf_payload);
 	strbuf_release(&buf_payload);
 }
@@ -135,11 +135,6 @@ static void maybe_append_string_va(struct strbuf *buf, const char *fmt,
 		va_end(copy_ap);
 		return;
 	}
-
-	if (fmt && *fmt) {
-		strbuf_addstr(buf, fmt);
-		return;
-	}
 }
 
 static void fn_error_va_fl(const char *file, int line, const char *fmt,
@@ -147,8 +142,11 @@ static void fn_error_va_fl(const char *file, int line, const char *fmt,
 {
 	struct strbuf buf_payload = STRBUF_INIT;
 
-	strbuf_addstr(&buf_payload, "error ");
-	maybe_append_string_va(&buf_payload, fmt, ap);
+	strbuf_addstr(&buf_payload, "error");
+	if (fmt && *fmt) {
+		strbuf_addch(&buf_payload, ' ');
+		maybe_append_string_va(&buf_payload, fmt, ap);
+	}
 	normal_io_write_fl(file, line, &buf_payload);
 	strbuf_release(&buf_payload);
 }
@@ -188,8 +186,8 @@ static void fn_alias_fl(const char *file, int line, const char *alias,
 {
 	struct strbuf buf_payload = STRBUF_INIT;
 
-	strbuf_addf(&buf_payload, "alias %s ->", alias);
-	sq_quote_argv_pretty(&buf_payload, argv);
+	strbuf_addf(&buf_payload, "alias %s -> ", alias);
+	sq_append_quote_argv_pretty(&buf_payload, argv);
 	normal_io_write_fl(file, line, &buf_payload);
 	strbuf_release(&buf_payload);
 }
@@ -200,12 +198,12 @@ static void fn_child_start_fl(const char *file, int line,
 {
 	struct strbuf buf_payload = STRBUF_INIT;
 
-	strbuf_addf(&buf_payload, "child_start[%d] ", cmd->trace2_child_id);
+	strbuf_addf(&buf_payload, "child_start[%d]", cmd->trace2_child_id);
 
 	if (cmd->dir) {
-		strbuf_addstr(&buf_payload, " cd");
+		strbuf_addstr(&buf_payload, " cd ");
 		sq_quote_buf_pretty(&buf_payload, cmd->dir);
-		strbuf_addstr(&buf_payload, "; ");
+		strbuf_addstr(&buf_payload, ";");
 	}
 
 	/*
@@ -213,9 +211,10 @@ static void fn_child_start_fl(const char *file, int line,
 	 * See trace_add_env() in run-command.c as used by original trace.c
 	 */
 
+	strbuf_addch(&buf_payload, ' ');
 	if (cmd->git_cmd)
-		strbuf_addstr(&buf_payload, "git");
-	sq_quote_argv_pretty(&buf_payload, cmd->argv);
+		strbuf_addstr(&buf_payload, "git ");
+	sq_append_quote_argv_pretty(&buf_payload, cmd->argv);
 
 	normal_io_write_fl(file, line, &buf_payload);
 	strbuf_release(&buf_payload);
@@ -240,9 +239,11 @@ static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
 	struct strbuf buf_payload = STRBUF_INIT;
 
 	strbuf_addf(&buf_payload, "exec[%d] ", exec_id);
-	if (exe)
+	if (exe) {
 		strbuf_addstr(&buf_payload, exe);
-	sq_quote_argv_pretty(&buf_payload, argv);
+		strbuf_addch(&buf_payload, ' ');
+	}
+	sq_append_quote_argv_pretty(&buf_payload, argv);
 	normal_io_write_fl(file, line, &buf_payload);
 	strbuf_release(&buf_payload);
 }
diff --git a/third_party/git/trace2/tr2_tgt_perf.c b/third_party/git/trace2/tr2_tgt_perf.c
index ea0cbbe13e..a8018f18cc 100644
--- a/third_party/git/trace2/tr2_tgt_perf.c
+++ b/third_party/git/trace2/tr2_tgt_perf.c
@@ -11,7 +11,7 @@
 #include "trace2/tr2_tgt.h"
 #include "trace2/tr2_tls.h"
 
-static struct tr2_dst tr2dst_perf = { TR2_SYSENV_PERF, 0, 0, 0 };
+static struct tr2_dst tr2dst_perf = { TR2_SYSENV_PERF, 0, 0, 0, 0 };
 
 /*
  * Use TR2_SYSENV_PERF_BRIEF to omit the "<time> <file>:<line>"
@@ -21,17 +21,14 @@ static struct tr2_dst tr2dst_perf = { TR2_SYSENV_PERF, 0, 0, 0 };
  */
 static int tr2env_perf_be_brief;
 
-#define TR2FMT_PERF_FL_WIDTH (50)
+#define TR2FMT_PERF_FL_WIDTH (28)
 #define TR2FMT_PERF_MAX_EVENT_NAME (12)
-#define TR2FMT_PERF_REPO_WIDTH (4)
-#define TR2FMT_PERF_CATEGORY_WIDTH (10)
+#define TR2FMT_PERF_REPO_WIDTH (3)
+#define TR2FMT_PERF_CATEGORY_WIDTH (12)
 
-#define TR2_DOTS_BUFFER_SIZE (100)
 #define TR2_INDENT (2)
 #define TR2_INDENT_LENGTH(ctx) (((ctx)->nr_open_regions - 1) * TR2_INDENT)
 
-static struct strbuf dots = STRBUF_INIT;
-
 static int fn_init(void)
 {
 	int want = tr2_dst_trace_want(&tr2dst_perf);
@@ -41,8 +38,6 @@ static int fn_init(void)
 	if (!want)
 		return want;
 
-	strbuf_addchars(&dots, '.', TR2_DOTS_BUFFER_SIZE);
-
 	brief = tr2_sysenv_get(TR2_SYSENV_PERF_BRIEF);
 	if (brief && *brief &&
 	    ((want_brief = git_parse_maybe_bool(brief)) != -1))
@@ -54,8 +49,6 @@ static int fn_init(void)
 static void fn_term(void)
 {
 	tr2_dst_trace_disable(&tr2dst_perf);
-
-	strbuf_release(&dots);
 }
 
 /*
@@ -79,17 +72,36 @@ static void perf_fmt_prepare(const char *event_name,
 
 	if (!tr2env_perf_be_brief) {
 		struct tr2_tbuf tb_now;
+		size_t fl_end_col;
 
 		tr2_tbuf_local_time(&tb_now);
 		strbuf_addstr(buf, tb_now.buf);
 		strbuf_addch(buf, ' ');
 
-		if (file && *file)
-			strbuf_addf(buf, "%s:%d ", file, line);
-		while (buf->len < TR2FMT_PERF_FL_WIDTH)
+		fl_end_col = buf->len + TR2FMT_PERF_FL_WIDTH;
+
+		if (file && *file) {
+			struct strbuf buf_fl = STRBUF_INIT;
+
+			strbuf_addf(&buf_fl, "%s:%d", file, line);
+
+			if (buf_fl.len <= TR2FMT_PERF_FL_WIDTH)
+				strbuf_addbuf(buf, &buf_fl);
+			else {
+				size_t avail = TR2FMT_PERF_FL_WIDTH - 3;
+				strbuf_addstr(buf, "...");
+				strbuf_add(buf,
+					   &buf_fl.buf[buf_fl.len - avail],
+					   avail);
+			}
+
+			strbuf_release(&buf_fl);
+		}
+
+		while (buf->len < fl_end_col)
 			strbuf_addch(buf, ' ');
 
-		strbuf_addstr(buf, "| ");
+		strbuf_addstr(buf, " | ");
 	}
 
 	strbuf_addf(buf, "d%d | ", tr2_sid_depth());
@@ -102,7 +114,7 @@ static void perf_fmt_prepare(const char *event_name,
 		strbuf_addf(buf, "r%d ", repo->trace2_repo_id);
 	while (buf->len < len)
 		strbuf_addch(buf, ' ');
-	strbuf_addstr(buf, "| ");
+	strbuf_addstr(buf, " | ");
 
 	if (p_us_elapsed_absolute)
 		strbuf_addf(buf, "%9.6f | ",
@@ -116,17 +128,11 @@ static void perf_fmt_prepare(const char *event_name,
 	else
 		strbuf_addf(buf, "%9s | ", " ");
 
-	strbuf_addf(buf, "%-*s | ", TR2FMT_PERF_CATEGORY_WIDTH,
-		    (category ? category : ""));
+	strbuf_addf(buf, "%-*.*s | ", TR2FMT_PERF_CATEGORY_WIDTH,
+		    TR2FMT_PERF_CATEGORY_WIDTH, (category ? category : ""));
 
-	if (ctx->nr_open_regions > 0) {
-		int len_indent = TR2_INDENT_LENGTH(ctx);
-		while (len_indent > dots.len) {
-			strbuf_addbuf(buf, &dots);
-			len_indent -= dots.len;
-		}
-		strbuf_addf(buf, "%.*s", len_indent, dots.buf);
-	}
+	if (ctx->nr_open_regions > 0)
+		strbuf_addchars(buf, '.', TR2_INDENT_LENGTH(ctx));
 }
 
 static void perf_io_write_fl(const char *file, int line, const char *event_name,
@@ -165,7 +171,7 @@ static void fn_start_fl(const char *file, int line,
 	const char *event_name = "start";
 	struct strbuf buf_payload = STRBUF_INIT;
 
-	sq_quote_argv_pretty(&buf_payload, argv);
+	sq_append_quote_argv_pretty(&buf_payload, argv);
 
 	perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
 			 NULL, NULL, &buf_payload);
@@ -220,11 +226,6 @@ static void maybe_append_string_va(struct strbuf *buf, const char *fmt,
 		va_end(copy_ap);
 		return;
 	}
-
-	if (fmt && *fmt) {
-		strbuf_addstr(buf, fmt);
-		return;
-	}
 }
 
 static void fn_error_va_fl(const char *file, int line, const char *fmt,
@@ -285,8 +286,9 @@ static void fn_alias_fl(const char *file, int line, const char *alias,
 	const char *event_name = "alias";
 	struct strbuf buf_payload = STRBUF_INIT;
 
-	strbuf_addf(&buf_payload, "alias:%s argv:", alias);
-	sq_quote_argv_pretty(&buf_payload, argv);
+	strbuf_addf(&buf_payload, "alias:%s argv:[", alias);
+	sq_append_quote_argv_pretty(&buf_payload, argv);
+	strbuf_addch(&buf_payload, ']');
 
 	perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
 			 &buf_payload);
@@ -315,10 +317,14 @@ static void fn_child_start_fl(const char *file, int line,
 		sq_quote_buf_pretty(&buf_payload, cmd->dir);
 	}
 
-	strbuf_addstr(&buf_payload, " argv:");
-	if (cmd->git_cmd)
-		strbuf_addstr(&buf_payload, " git");
-	sq_quote_argv_pretty(&buf_payload, cmd->argv);
+	strbuf_addstr(&buf_payload, " argv:[");
+	if (cmd->git_cmd) {
+		strbuf_addstr(&buf_payload, "git");
+		if (cmd->argv[0])
+			strbuf_addch(&buf_payload, ' ');
+	}
+	sq_append_quote_argv_pretty(&buf_payload, cmd->argv);
+	strbuf_addch(&buf_payload, ']');
 
 	perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
 			 NULL, NULL, &buf_payload);
@@ -369,10 +375,14 @@ static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
 	struct strbuf buf_payload = STRBUF_INIT;
 
 	strbuf_addf(&buf_payload, "id:%d ", exec_id);
-	strbuf_addstr(&buf_payload, "argv:");
-	if (exe)
-		strbuf_addf(&buf_payload, " %s", exe);
-	sq_quote_argv_pretty(&buf_payload, argv);
+	strbuf_addstr(&buf_payload, "argv:[");
+	if (exe) {
+		strbuf_addstr(&buf_payload, exe);
+		if (argv[0])
+			strbuf_addch(&buf_payload, ' ');
+	}
+	sq_append_quote_argv_pretty(&buf_payload, argv);
+	strbuf_addch(&buf_payload, ']');
 
 	perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
 			 NULL, NULL, &buf_payload);
@@ -433,8 +443,11 @@ static void fn_region_enter_printf_va_fl(const char *file, int line,
 	struct strbuf buf_payload = STRBUF_INIT;
 
 	if (label)
-		strbuf_addf(&buf_payload, "label:%s ", label);
-	maybe_append_string_va(&buf_payload, fmt, ap);
+		strbuf_addf(&buf_payload, "label:%s", label);
+	if (fmt && *fmt) {
+		strbuf_addch(&buf_payload, ' ');
+		maybe_append_string_va(&buf_payload, fmt, ap);
+	}
 
 	perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
 			 NULL, category, &buf_payload);
@@ -450,8 +463,11 @@ static void fn_region_leave_printf_va_fl(
 	struct strbuf buf_payload = STRBUF_INIT;
 
 	if (label)
-		strbuf_addf(&buf_payload, "label:%s ", label);
-	maybe_append_string_va(&buf_payload, fmt, ap);
+		strbuf_addf(&buf_payload, "label:%s", label);
+	if (fmt && *fmt) {
+		strbuf_addch(&buf_payload, ' ' );
+		maybe_append_string_va(&buf_payload, fmt, ap);
+	}
 
 	perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
 			 &us_elapsed_region, category, &buf_payload);