From 444665735a1a57ece9c7dc0635ad523aa58a5a09 Mon Sep 17 00:00:00 2001
From: Adam Hendel <hendel.adam@gmail.com>
Date: Thu, 9 Nov 2023 13:34:19 -0600
Subject: [PATCH v2] Adds colum headers to the log file produced by pgbench

Previously, users would be required to manually look up column names in the
documentation when reading and processing pgbench log files. Adding column
headers makes it it easy to process programatically.
---
 src/bin/pgbench/pgbench.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index e3919395ea..78cdc68088 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -822,6 +822,7 @@ static void setDoubleValue(PgBenchValue *pv, double dval);
 static bool evaluateExpr(CState *st, PgBenchExpr *expr,
 						 PgBenchValue *retval);
 static ConnectionStateEnum executeMetaCommand(CState *st, pg_time_usec_t *now);
+static void doLogHeader(FILE *logfile, double throttle_delay, uint32 retries);
 static void doLog(TState *thread, CState *st,
 				  StatsData *agg, bool skipped, double latency, double lag);
 static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now,
@@ -4500,6 +4501,34 @@ getResultString(bool skipped, EStatus estatus)
 		return "failed";
 }
 
+/*
+ * Generates column headers for the log file
+ *
+ */
+void doLogHeader(FILE *logfile, double throttle_delay, uint32 retries)
+{
+    // header fields present in all cases
+    fprintf(logfile, "client_id transaction_no time script_no time_epoch time_us");
+    
+    // Append "schedule_lag" if the schedule_lag is true
+    if (throttle_delay)
+    {
+        fprintf(logfile, " schedule_lag");
+    }
+
+    // Append "retries" when set
+    if (retries > 1)
+    {
+        fprintf(logfile, " retries");
+    }
+
+    fprintf(logfile, "\n");
+
+	// flush the buffer to ensure the header is written immediately
+	fflush(logfile);
+}
+
+
 /*
  * Print log entry after completing one transaction.
  *
@@ -4517,7 +4546,6 @@ doLog(TState *thread, CState *st,
 	pg_time_usec_t now = pg_time_now() + epoch_shift;
 
 	Assert(use_log);
-
 	/*
 	 * Skip the log entry if sampling is enabled and this row doesn't belong
 	 * to the random sample.
@@ -7380,6 +7408,11 @@ threadRun(void *arg)
 
 		if (thread->logfile == NULL)
 			pg_fatal("could not open logfile \"%s\": %m", logpath);
+		else
+			// only log header from the main thread
+			if (thread->tid == 0) {
+				doLogHeader(thread->logfile, throttle_delay, max_tries);
+			}
 	}
 
 	/* explicitly initialize the state machines */
-- 
2.39.3 (Apple Git-145)

