summaryrefslogtreecommitdiff
path: root/trace2
diff options
context:
space:
mode:
Diffstat (limited to 'trace2')
-rw-r--r--trace2/tr2_cmd_name.c2
-rw-r--r--trace2/tr2_dst.c67
-rw-r--r--trace2/tr2_sid.c55
-rw-r--r--trace2/tr2_sysenv.c20
-rw-r--r--trace2/tr2_sysenv.h2
-rw-r--r--trace2/tr2_tbuf.c19
-rw-r--r--trace2/tr2_tbuf.h5
-rw-r--r--trace2/tr2_tgt_event.c4
-rw-r--r--trace2/tr2_tgt_normal.c2
-rw-r--r--trace2/tr2_tgt_perf.c2
-rw-r--r--trace2/tr2_tls.c12
11 files changed, 155 insertions, 35 deletions
diff --git a/trace2/tr2_cmd_name.c b/trace2/tr2_cmd_name.c
index e999592..dd31320 100644
--- a/trace2/tr2_cmd_name.c
+++ b/trace2/tr2_cmd_name.c
@@ -1,7 +1,7 @@
#include "cache.h"
#include "trace2/tr2_cmd_name.h"
-#define TR2_ENVVAR_PARENT_NAME "GIT_TR2_PARENT_NAME"
+#define TR2_ENVVAR_PARENT_NAME "GIT_TRACE2_PARENT_NAME"
static struct strbuf tr2cmdname_hierarchy = STRBUF_INIT;
diff --git a/trace2/tr2_dst.c b/trace2/tr2_dst.c
index 6c425f1..c698575 100644
--- a/trace2/tr2_dst.c
+++ b/trace2/tr2_dst.c
@@ -1,14 +1,13 @@
#include "cache.h"
#include "trace2/tr2_dst.h"
+#include "trace2/tr2_sid.h"
#include "trace2/tr2_sysenv.h"
/*
- * If a Trace2 target cannot be opened for writing, we should issue a
- * warning to stderr, but this is very annoying if the target is a pipe
- * or socket and beyond the user's control -- especially since every
- * git command (and sub-command) will print the message. So we silently
- * eat these warnings and just discard the trace data.
+ * 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;
@@ -33,6 +32,56 @@ 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,
+ tr2_sysenv_display_name(dst->sysenv_var),
+ 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);
@@ -198,8 +247,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))
diff --git a/trace2/tr2_sid.c b/trace2/tr2_sid.c
index 984524a..6948fd4 100644
--- a/trace2/tr2_sid.c
+++ b/trace2/tr2_sid.c
@@ -1,12 +1,60 @@
#include "cache.h"
+#include "trace2/tr2_tbuf.h"
#include "trace2/tr2_sid.h"
-#define TR2_ENVVAR_PARENT_SID "GIT_TR2_PARENT_SID"
+#define TR2_ENVVAR_PARENT_SID "GIT_TRACE2_PARENT_SID"
static struct strbuf tr2sid_buf = STRBUF_INIT;
static int tr2sid_nr_git_parents;
/*
+ * Compute the final component of the SID representing the current process.
+ * This should uniquely identify the process and be a valid filename (to
+ * allow writing trace2 data to per-process files). It should also be fixed
+ * length for possible use as a database key.
+ *
+ * "<yyyymmdd>T<hhmmss>.<fraction>Z-<host>-<process>"
+ *
+ * where <host> is a 9 character string:
+ * "H<first_8_chars_of_sha1_of_hostname>"
+ * "Localhost" when no hostname.
+ *
+ * where <process> is a 9 character string containing the least signifcant
+ * 32 bits in the process-id.
+ * "P<pid>"
+ * (This is an abribrary choice. On most systems pid_t is a 32 bit value,
+ * so limit doesn't matter. On larger systems, a truncated value is fine
+ * for our purposes here.)
+ */
+static void tr2_sid_append_my_sid_component(void)
+{
+ const struct git_hash_algo *algo = &hash_algos[GIT_HASH_SHA1];
+ struct tr2_tbuf tb_now;
+ git_hash_ctx ctx;
+ pid_t pid = getpid();
+ unsigned char hash[GIT_MAX_RAWSZ + 1];
+ char hex[GIT_MAX_HEXSZ + 1];
+ char hostname[HOST_NAME_MAX + 1];
+
+ tr2_tbuf_utc_datetime(&tb_now);
+ strbuf_addstr(&tr2sid_buf, tb_now.buf);
+
+ strbuf_addch(&tr2sid_buf, '-');
+ if (xgethostname(hostname, sizeof(hostname)))
+ strbuf_add(&tr2sid_buf, "Localhost", 9);
+ else {
+ algo->init_fn(&ctx);
+ algo->update_fn(&ctx, hostname, strlen(hostname));
+ algo->final_fn(hash, &ctx);
+ hash_to_hex_algop_r(hex, hash, algo);
+ strbuf_addch(&tr2sid_buf, 'H');
+ strbuf_add(&tr2sid_buf, hex, 8);
+ }
+
+ strbuf_addf(&tr2sid_buf, "-P%08"PRIx32, (uint32_t)pid);
+}
+
+/*
* Compute a "unique" session id (SID) for the current process. This allows
* all events from this process to have a single label (much like a PID).
*
@@ -20,7 +68,6 @@ static int tr2sid_nr_git_parents;
*/
static void tr2_sid_compute(void)
{
- uint64_t us_now;
const char *parent_sid;
if (tr2sid_buf.len)
@@ -38,9 +85,7 @@ static void tr2_sid_compute(void)
tr2sid_nr_git_parents++;
}
- us_now = getnanotime() / 1000;
- strbuf_addf(&tr2sid_buf, "%" PRIuMAX "-%" PRIdMAX, (uintmax_t)us_now,
- (intmax_t)getpid());
+ tr2_sid_append_my_sid_component();
setenv(TR2_ENVVAR_PARENT_SID, tr2sid_buf.buf, 1);
}
diff --git a/trace2/tr2_sysenv.c b/trace2/tr2_sysenv.c
index 9025b86..5958cfc 100644
--- a/trace2/tr2_sysenv.c
+++ b/trace2/tr2_sysenv.c
@@ -21,33 +21,33 @@ struct tr2_sysenv_entry {
* The strings in this table are constant and must match the published
* config and environment variable names as described in the documentation.
*
- * We do not define entries for the GIT_TR2_PARENT_* environment
+ * We do not define entries for the GIT_TRACE2_PARENT_* environment
* variables because they are transient and used to pass information
* from parent to child git processes, rather than settings.
*/
/* clang-format off */
static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
- [TR2_SYSENV_CFG_PARAM] = { "GIT_TR2_CONFIG_PARAMS",
+ [TR2_SYSENV_CFG_PARAM] = { "GIT_TRACE2_CONFIG_PARAMS",
"trace2.configparams" },
- [TR2_SYSENV_DST_DEBUG] = { "GIT_TR2_DST_DEBUG",
+ [TR2_SYSENV_DST_DEBUG] = { "GIT_TRACE2_DST_DEBUG",
"trace2.destinationdebug" },
- [TR2_SYSENV_NORMAL] = { "GIT_TR2",
+ [TR2_SYSENV_NORMAL] = { "GIT_TRACE2",
"trace2.normaltarget" },
- [TR2_SYSENV_NORMAL_BRIEF] = { "GIT_TR2_BRIEF",
+ [TR2_SYSENV_NORMAL_BRIEF] = { "GIT_TRACE2_BRIEF",
"trace2.normalbrief" },
- [TR2_SYSENV_EVENT] = { "GIT_TR2_EVENT",
+ [TR2_SYSENV_EVENT] = { "GIT_TRACE2_EVENT",
"trace2.eventtarget" },
- [TR2_SYSENV_EVENT_BRIEF] = { "GIT_TR2_EVENT_BRIEF",
+ [TR2_SYSENV_EVENT_BRIEF] = { "GIT_TRACE2_EVENT_BRIEF",
"trace2.eventbrief" },
- [TR2_SYSENV_EVENT_NESTING] = { "GIT_TR2_EVENT_NESTING",
+ [TR2_SYSENV_EVENT_NESTING] = { "GIT_TRACE2_EVENT_NESTING",
"trace2.eventnesting" },
- [TR2_SYSENV_PERF] = { "GIT_TR2_PERF",
+ [TR2_SYSENV_PERF] = { "GIT_TRACE2_PERF",
"trace2.perftarget" },
- [TR2_SYSENV_PERF_BRIEF] = { "GIT_TR2_PERF_BRIEF",
+ [TR2_SYSENV_PERF_BRIEF] = { "GIT_TRACE2_PERF_BRIEF",
"trace2.perfbrief" },
};
/* clang-format on */
diff --git a/trace2/tr2_sysenv.h b/trace2/tr2_sysenv.h
index 369b20b..8dd82a7 100644
--- a/trace2/tr2_sysenv.h
+++ b/trace2/tr2_sysenv.h
@@ -7,7 +7,7 @@
*
* Note that this set does not contain any of the transient
* environment variables used to pass information from parent
- * to child git processes, such "GIT_TR2_PARENT_SID".
+ * to child git processes, such "GIT_TRACE2_PARENT_SID".
*/
enum tr2_sysenv_variable {
TR2_SYSENV_CFG_PARAM = 0,
diff --git a/trace2/tr2_tbuf.c b/trace2/tr2_tbuf.c
index 0844910..2498482 100644
--- a/trace2/tr2_tbuf.c
+++ b/trace2/tr2_tbuf.c
@@ -15,7 +15,7 @@ void tr2_tbuf_local_time(struct tr2_tbuf *tb)
tm.tm_min, tm.tm_sec, (long)tv.tv_usec);
}
-void tr2_tbuf_utc_time(struct tr2_tbuf *tb)
+void tr2_tbuf_utc_datetime_extended(struct tr2_tbuf *tb)
{
struct timeval tv;
struct tm tm;
@@ -26,7 +26,22 @@ void tr2_tbuf_utc_time(struct tr2_tbuf *tb)
gmtime_r(&secs, &tm);
xsnprintf(tb->buf, sizeof(tb->buf),
- "%4d-%02d-%02d %02d:%02d:%02d.%06ld", tm.tm_year + 1900,
+ "%4d-%02d-%02dT%02d:%02d:%02d.%06ldZ", tm.tm_year + 1900,
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
(long)tv.tv_usec);
}
+
+void tr2_tbuf_utc_datetime(struct tr2_tbuf *tb)
+{
+ struct timeval tv;
+ struct tm tm;
+ time_t secs;
+
+ gettimeofday(&tv, NULL);
+ secs = tv.tv_sec;
+ gmtime_r(&secs, &tm);
+
+ xsnprintf(tb->buf, sizeof(tb->buf), "%4d%02d%02dT%02d%02d%02d.%06ldZ",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
+ tm.tm_min, tm.tm_sec, (long)tv.tv_usec);
+}
diff --git a/trace2/tr2_tbuf.h b/trace2/tr2_tbuf.h
index 9cdefa3..fa853d8 100644
--- a/trace2/tr2_tbuf.h
+++ b/trace2/tr2_tbuf.h
@@ -16,8 +16,9 @@ struct tr2_tbuf {
void tr2_tbuf_local_time(struct tr2_tbuf *tb);
/*
- * Fill buffer with formatted UTC time string.
+ * Fill buffer with formatted UTC datatime string.
*/
-void tr2_tbuf_utc_time(struct tr2_tbuf *tb);
+void tr2_tbuf_utc_datetime_extended(struct tr2_tbuf *tb);
+void tr2_tbuf_utc_datetime(struct tr2_tbuf *tb);
#endif /* TR2_TBUF_H */
diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c
index 48d9193..c2852d1 100644
--- a/trace2/tr2_tgt_event.c
+++ b/trace2/tr2_tgt_event.c
@@ -94,7 +94,7 @@ static void event_fmt_prepare(const char *event_name, const char *file,
*/
if (!tr2env_event_be_brief || !strcmp(event_name, "version") ||
!strcmp(event_name, "atexit")) {
- tr2_tbuf_utc_time(&tb_now);
+ tr2_tbuf_utc_datetime_extended(&tb_now);
jw_object_string(jw, "time", tb_now.buf);
}
@@ -193,7 +193,7 @@ static void fn_atexit(uint64_t us_elapsed_absolute, int code)
static void maybe_add_string_va(struct json_writer *jw, const char *field_name,
const char *fmt, va_list ap)
{
- if (fmt && *fmt && ap) {
+ if (fmt && *fmt) {
va_list copy_ap;
struct strbuf buf = STRBUF_INIT;
diff --git a/trace2/tr2_tgt_normal.c b/trace2/tr2_tgt_normal.c
index 1ce6f97..00b116d 100644
--- a/trace2/tr2_tgt_normal.c
+++ b/trace2/tr2_tgt_normal.c
@@ -127,7 +127,7 @@ static void fn_atexit(uint64_t us_elapsed_absolute, int code)
static void maybe_append_string_va(struct strbuf *buf, const char *fmt,
va_list ap)
{
- if (fmt && *fmt && ap) {
+ if (fmt && *fmt) {
va_list copy_ap;
va_copy(copy_ap, ap);
diff --git a/trace2/tr2_tgt_perf.c b/trace2/tr2_tgt_perf.c
index 328d223..ea0cbbe 100644
--- a/trace2/tr2_tgt_perf.c
+++ b/trace2/tr2_tgt_perf.c
@@ -212,7 +212,7 @@ static void fn_atexit(uint64_t us_elapsed_absolute, int code)
static void maybe_append_string_va(struct strbuf *buf, const char *fmt,
va_list ap)
{
- if (fmt && *fmt && ap) {
+ if (fmt && *fmt) {
va_list copy_ap;
va_copy(copy_ap, ap);
diff --git a/trace2/tr2_tls.c b/trace2/tr2_tls.c
index e76d8c5..067c237 100644
--- a/trace2/tr2_tls.c
+++ b/trace2/tr2_tls.c
@@ -61,7 +61,12 @@ struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name,
struct tr2tls_thread_ctx *tr2tls_get_self(void)
{
- struct tr2tls_thread_ctx *ctx = pthread_getspecific(tr2tls_key);
+ struct tr2tls_thread_ctx *ctx;
+
+ if (!HAVE_THREADS)
+ return tr2tls_thread_main;
+
+ ctx = pthread_getspecific(tr2tls_key);
/*
* If the thread-proc did not call trace2_thread_start(), we won't
@@ -76,9 +81,10 @@ struct tr2tls_thread_ctx *tr2tls_get_self(void)
int tr2tls_is_main_thread(void)
{
- struct tr2tls_thread_ctx *ctx = pthread_getspecific(tr2tls_key);
+ if (!HAVE_THREADS)
+ return 1;
- return ctx == tr2tls_thread_main;
+ return pthread_getspecific(tr2tls_key) == tr2tls_thread_main;
}
void tr2tls_unset_self(void)