Finer grain log timestamps
Folks,
Please find attached a patch to change the sub-second granularity of
log timestamps from milliseconds to microseconds.
I started out working on a longer patch that will give people
more choices than whole seconds and microseconds, but there were a lot
of odd corner cases, including what I believe might have been a
requirement for C11, should be wish to get sub-microsecond
granularity.
Best,
David.
--
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
Attachments:
v1-0001-Change-log-timestamps-from-milli-to-microseconds.patchtext/x-diff; charset=us-asciiDownload
From f4881d1669526597bdf608c7c59858f88314f8d1 Mon Sep 17 00:00:00 2001
From: David Fetter <david@fetter.org>
Date: Sun, 8 May 2022 13:24:33 -0700
Subject: [PATCH v1] Change log timestamps from milli- to microseconds
---
doc/src/sgml/config.sgml | 12 ++++++------
src/backend/utils/error/elog.c | 14 +++++++-------
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git doc/src/sgml/config.sgml doc/src/sgml/config.sgml
index 03986946a8..f00db09547 100644
--- doc/src/sgml/config.sgml
+++ doc/src/sgml/config.sgml
@@ -7174,17 +7174,17 @@ local0.* /var/log/postgresql
</row>
<row>
<entry><literal>%t</literal></entry>
- <entry>Time stamp without milliseconds</entry>
+ <entry>Time stamp at second resolution</entry>
<entry>no</entry>
</row>
<row>
<entry><literal>%m</literal></entry>
- <entry>Time stamp with milliseconds</entry>
+ <entry>Time stamp with microseconds</entry>
<entry>no</entry>
</row>
<row>
<entry><literal>%n</literal></entry>
- <entry>Time stamp with milliseconds (as a Unix epoch)</entry>
+ <entry>Time stamp with microseconds (as a Unix epoch)</entry>
<entry>no</entry>
</row>
<row>
@@ -7526,7 +7526,7 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
This option emits log lines in comma-separated-values
(<acronym>CSV</acronym>) format,
with these columns:
- time stamp with milliseconds,
+ time stamp with microseconds,
user name,
database name,
process ID,
@@ -7557,7 +7557,7 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
<programlisting>
CREATE TABLE postgres_log
(
- log_time timestamp(3) with time zone,
+ log_time timestamp(6) with time zone,
user_name text,
database_name text,
process_id integer,
@@ -7682,7 +7682,7 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
<row>
<entry><literal>timestamp</literal></entry>
<entry>string</entry>
- <entry>Time stamp with milliseconds</entry>
+ <entry>Time stamp with microseconds</entry>
</row>
<row>
<entry><literal>user</literal></entry>
diff --git src/backend/utils/error/elog.c src/backend/utils/error/elog.c
index 55ee5423af..4698e32ab7 100644
--- src/backend/utils/error/elog.c
+++ src/backend/utils/error/elog.c
@@ -2295,7 +2295,7 @@ char *
get_formatted_log_time(void)
{
pg_time_t stamp_time;
- char msbuf[13];
+ char msbuf[16];
/* leave if already computed */
if (formatted_log_time[0] != '\0')
@@ -2315,13 +2315,13 @@ get_formatted_log_time(void)
* nonempty or CSV mode can be selected.
*/
pg_strftime(formatted_log_time, FORMATTED_TS_LEN,
- /* leave room for milliseconds... */
- "%Y-%m-%d %H:%M:%S %Z",
+ /* leave room for microseconds... */
+ "%Y-%m-%d %H:%M:%S %Z",
pg_localtime(&stamp_time, log_timezone));
/* 'paste' milliseconds into place... */
- sprintf(msbuf, ".%03d", (int) (saved_timeval.tv_usec / 1000));
- memcpy(formatted_log_time + 19, msbuf, 4);
+ sprintf(msbuf, ".%06d", saved_timeval.tv_usec );
+ memcpy(formatted_log_time + 19, msbuf, 7);
return formatted_log_time;
}
@@ -2652,9 +2652,9 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
saved_timeval_set = true;
}
- snprintf(strfbuf, sizeof(strfbuf), "%ld.%03d",
+ snprintf(strfbuf, sizeof(strfbuf), "%ld.%06d",
(long) saved_timeval.tv_sec,
- (int) (saved_timeval.tv_usec / 1000));
+ saved_timeval.tv_usec);
if (padding != 0)
appendStringInfo(buf, "%*s", padding, strfbuf);
--
2.35.1
On Sun, May 08, 2022 at 08:44:51PM +0000, David Fetter wrote:
CREATE TABLE postgres_log ( - log_time timestamp(3) with time zone, + log_time timestamp(6) with time zone,
Please also update the corresponding thing in doc/src/sgml/file-fdw.sgml
It looks like the patch I suggested to include a reminder about this was never
applied.
/messages/by-id/10995044.nUPlyArG6x@aivenronan
See also:
e568ed0eb07239b7e53d948565ebaeb6f379630f
0830d21f5b01064837dc8bd910ab31a5b7a1101a
On Sun, May 08, 2022 at 04:12:27PM -0500, Justin Pryzby wrote:
On Sun, May 08, 2022 at 08:44:51PM +0000, David Fetter wrote:
CREATE TABLE postgres_log ( - log_time timestamp(3) with time zone, + log_time timestamp(6) with time zone,Please also update the corresponding thing in doc/src/sgml/file-fdw.sgml
Thanks for looking this over, and please find attached the next
version.
Best,
David.
--
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
Attachments:
v2-0001-Change-log-timestamps-from-milli-to-microseconds.patchtext/x-diff; charset=us-asciiDownload
From f6772fc0378879fd5c7fbf8cb320ee68f66341d2 Mon Sep 17 00:00:00 2001
From: David Fetter <david@fetter.org>
Date: Sun, 8 May 2022 13:24:33 -0700
Subject: [PATCH v2] Change log timestamps from milli- to microseconds
---
doc/src/sgml/config.sgml | 12 ++++++------
doc/src/sgml/file-fdw.sgml | 2 +-
src/backend/utils/error/elog.c | 14 +++++++-------
3 files changed, 14 insertions(+), 14 deletions(-)
diff --git doc/src/sgml/config.sgml doc/src/sgml/config.sgml
index 03986946a8..f00db09547 100644
--- doc/src/sgml/config.sgml
+++ doc/src/sgml/config.sgml
@@ -7174,17 +7174,17 @@ local0.* /var/log/postgresql
</row>
<row>
<entry><literal>%t</literal></entry>
- <entry>Time stamp without milliseconds</entry>
+ <entry>Time stamp at second resolution</entry>
<entry>no</entry>
</row>
<row>
<entry><literal>%m</literal></entry>
- <entry>Time stamp with milliseconds</entry>
+ <entry>Time stamp with microseconds</entry>
<entry>no</entry>
</row>
<row>
<entry><literal>%n</literal></entry>
- <entry>Time stamp with milliseconds (as a Unix epoch)</entry>
+ <entry>Time stamp with microseconds (as a Unix epoch)</entry>
<entry>no</entry>
</row>
<row>
@@ -7526,7 +7526,7 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
This option emits log lines in comma-separated-values
(<acronym>CSV</acronym>) format,
with these columns:
- time stamp with milliseconds,
+ time stamp with microseconds,
user name,
database name,
process ID,
@@ -7557,7 +7557,7 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
<programlisting>
CREATE TABLE postgres_log
(
- log_time timestamp(3) with time zone,
+ log_time timestamp(6) with time zone,
user_name text,
database_name text,
process_id integer,
@@ -7682,7 +7682,7 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
<row>
<entry><literal>timestamp</literal></entry>
<entry>string</entry>
- <entry>Time stamp with milliseconds</entry>
+ <entry>Time stamp with microseconds</entry>
</row>
<row>
<entry><literal>user</literal></entry>
diff --git doc/src/sgml/file-fdw.sgml doc/src/sgml/file-fdw.sgml
index 5b98782064..c3efcbd679 100644
--- doc/src/sgml/file-fdw.sgml
+++ doc/src/sgml/file-fdw.sgml
@@ -242,7 +242,7 @@ CREATE SERVER pglog FOREIGN DATA WRAPPER file_fdw;
<programlisting>
CREATE FOREIGN TABLE pglog (
- log_time timestamp(3) with time zone,
+ log_time timestamp(6) with time zone,
user_name text,
database_name text,
process_id integer,
diff --git src/backend/utils/error/elog.c src/backend/utils/error/elog.c
index 55ee5423af..4698e32ab7 100644
--- src/backend/utils/error/elog.c
+++ src/backend/utils/error/elog.c
@@ -2295,7 +2295,7 @@ char *
get_formatted_log_time(void)
{
pg_time_t stamp_time;
- char msbuf[13];
+ char msbuf[16];
/* leave if already computed */
if (formatted_log_time[0] != '\0')
@@ -2315,13 +2315,13 @@ get_formatted_log_time(void)
* nonempty or CSV mode can be selected.
*/
pg_strftime(formatted_log_time, FORMATTED_TS_LEN,
- /* leave room for milliseconds... */
- "%Y-%m-%d %H:%M:%S %Z",
+ /* leave room for microseconds... */
+ "%Y-%m-%d %H:%M:%S %Z",
pg_localtime(&stamp_time, log_timezone));
/* 'paste' milliseconds into place... */
- sprintf(msbuf, ".%03d", (int) (saved_timeval.tv_usec / 1000));
- memcpy(formatted_log_time + 19, msbuf, 4);
+ sprintf(msbuf, ".%06d", saved_timeval.tv_usec );
+ memcpy(formatted_log_time + 19, msbuf, 7);
return formatted_log_time;
}
@@ -2652,9 +2652,9 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
saved_timeval_set = true;
}
- snprintf(strfbuf, sizeof(strfbuf), "%ld.%03d",
+ snprintf(strfbuf, sizeof(strfbuf), "%ld.%06d",
(long) saved_timeval.tv_sec,
- (int) (saved_timeval.tv_usec / 1000));
+ saved_timeval.tv_usec);
if (padding != 0)
appendStringInfo(buf, "%*s", padding, strfbuf);
--
2.35.1
David Fetter <david@fetter.org> writes:
diff --git src/backend/utils/error/elog.c src/backend/utils/error/elog.c index 55ee5423af..4698e32ab7 100644 --- src/backend/utils/error/elog.c +++ src/backend/utils/error/elog.c @@ -2295,7 +2295,7 @@ char * get_formatted_log_time(void) { pg_time_t stamp_time; - char msbuf[13]; + char msbuf[16];
Now that it holds microseconds (µs), not milliseconds (ms), should it
not be renamed to `usbuf`?
- ilmari
On Mon, May 09, 2022 at 11:21:26AM +0100, Dagfinn Ilmari Manns�ker wrote:
David Fetter <david@fetter.org> writes:
diff --git src/backend/utils/error/elog.c src/backend/utils/error/elog.c index 55ee5423af..4698e32ab7 100644 --- src/backend/utils/error/elog.c +++ src/backend/utils/error/elog.c @@ -2295,7 +2295,7 @@ char * get_formatted_log_time(void) { pg_time_t stamp_time; - char msbuf[13]; + char msbuf[16];Now that it holds microseconds (�s), not milliseconds (ms), should it
not be renamed to `usbuf`?
Good point.
Best,
David.
--
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
Attachments:
v3-0001-Change-log-timestamps-from-milli-to-microseconds.patchtext/x-diff; charset=us-asciiDownload
From 9283d9ae4d8d10876aee1da0753e7db4257e7a11 Mon Sep 17 00:00:00 2001
From: David Fetter <david@fetter.org>
Date: Mon, 13 Jun 2022 00:01:04 -0700
Subject: [PATCH v3] Change log timestamps from milli- to microseconds
---
doc/src/sgml/config.sgml | 12 ++++++------
doc/src/sgml/file-fdw.sgml | 2 +-
src/backend/utils/error/elog.c | 14 +++++++-------
3 files changed, 14 insertions(+), 14 deletions(-)
diff --git doc/src/sgml/config.sgml doc/src/sgml/config.sgml
index 5b7ce6531d..adc4fc090a 100644
--- doc/src/sgml/config.sgml
+++ doc/src/sgml/config.sgml
@@ -7174,17 +7174,17 @@ local0.* /var/log/postgresql
</row>
<row>
<entry><literal>%t</literal></entry>
- <entry>Time stamp without milliseconds</entry>
+ <entry>Time stamp at second resolution</entry>
<entry>no</entry>
</row>
<row>
<entry><literal>%m</literal></entry>
- <entry>Time stamp with milliseconds</entry>
+ <entry>Time stamp with microseconds</entry>
<entry>no</entry>
</row>
<row>
<entry><literal>%n</literal></entry>
- <entry>Time stamp with milliseconds (as a Unix epoch)</entry>
+ <entry>Time stamp with microseconds (as a Unix epoch)</entry>
<entry>no</entry>
</row>
<row>
@@ -7526,7 +7526,7 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
This option emits log lines in comma-separated-values
(<acronym>CSV</acronym>) format,
with these columns:
- time stamp with milliseconds,
+ time stamp with microseconds,
user name,
database name,
process ID,
@@ -7557,7 +7557,7 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
<programlisting>
CREATE TABLE postgres_log
(
- log_time timestamp(3) with time zone,
+ log_time timestamp(6) with time zone,
user_name text,
database_name text,
process_id integer,
@@ -7682,7 +7682,7 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
<row>
<entry><literal>timestamp</literal></entry>
<entry>string</entry>
- <entry>Time stamp with milliseconds</entry>
+ <entry>Time stamp with microseconds</entry>
</row>
<row>
<entry><literal>user</literal></entry>
diff --git doc/src/sgml/file-fdw.sgml doc/src/sgml/file-fdw.sgml
index 5b98782064..c3efcbd679 100644
--- doc/src/sgml/file-fdw.sgml
+++ doc/src/sgml/file-fdw.sgml
@@ -242,7 +242,7 @@ CREATE SERVER pglog FOREIGN DATA WRAPPER file_fdw;
<programlisting>
CREATE FOREIGN TABLE pglog (
- log_time timestamp(3) with time zone,
+ log_time timestamp(6) with time zone,
user_name text,
database_name text,
process_id integer,
diff --git src/backend/utils/error/elog.c src/backend/utils/error/elog.c
index 55ee5423af..1ee49ce2be 100644
--- src/backend/utils/error/elog.c
+++ src/backend/utils/error/elog.c
@@ -2295,7 +2295,7 @@ char *
get_formatted_log_time(void)
{
pg_time_t stamp_time;
- char msbuf[13];
+ char usbuf[16];
/* leave if already computed */
if (formatted_log_time[0] != '\0')
@@ -2315,13 +2315,13 @@ get_formatted_log_time(void)
* nonempty or CSV mode can be selected.
*/
pg_strftime(formatted_log_time, FORMATTED_TS_LEN,
- /* leave room for milliseconds... */
- "%Y-%m-%d %H:%M:%S %Z",
+ /* leave room for microseconds... */
+ "%Y-%m-%d %H:%M:%S %Z",
pg_localtime(&stamp_time, log_timezone));
/* 'paste' milliseconds into place... */
- sprintf(msbuf, ".%03d", (int) (saved_timeval.tv_usec / 1000));
- memcpy(formatted_log_time + 19, msbuf, 4);
+ sprintf(usbuf, ".%06d", saved_timeval.tv_usec );
+ memcpy(formatted_log_time + 19, usbuf, 7);
return formatted_log_time;
}
@@ -2652,9 +2652,9 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
saved_timeval_set = true;
}
- snprintf(strfbuf, sizeof(strfbuf), "%ld.%03d",
+ snprintf(strfbuf, sizeof(strfbuf), "%ld.%06d",
(long) saved_timeval.tv_sec,
- (int) (saved_timeval.tv_usec / 1000));
+ saved_timeval.tv_usec);
if (padding != 0)
appendStringInfo(buf, "%*s", padding, strfbuf);
--
2.36.1
On Sun, May 8, 2022 at 4:45 PM David Fetter <david@fetter.org> wrote:
Please find attached a patch to change the sub-second granularity of
log timestamps from milliseconds to microseconds.
Why is this a good idea?
--
Robert Haas
EDB: http://www.enterprisedb.com
Robert Haas <robertmhaas@gmail.com> writes:
On Sun, May 8, 2022 at 4:45 PM David Fetter <david@fetter.org> wrote:
Please find attached a patch to change the sub-second granularity of
log timestamps from milliseconds to microseconds.
Why is this a good idea?
I can imagine that some people would have a use for microsecond
resolution in log files, and I can also imagine that as machines
get faster more people will want that. As against that, this
will bloat log files by a non-microscopic amount, and it's pretty
likely to break some log-scanning tools too. It's unclear to me
that that's a tradeoff we should force on everyone.
I think a proposal less likely to have push-back would be to invent
a different log_line_prefix %-escape to produce microseconds.
Sadly, "%u" is already taken, but perhaps we could use "%U"?
A different line of thought is to extend %t to provide a precision
field a la sprintf, so that for example "%.3t" is equivalent to
"%m" and "%.6t" does what David wants, and we won't have to
search for a new escape letter when the day arrives that
somebody wants nanosecond resolution. The same could be done
with %n, avoiding the need to find a different escape letter
for that.
regards, tom lane
On Mon, Jun 13, 2022 at 04:22:42PM -0400, Tom Lane wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Sun, May 8, 2022 at 4:45 PM David Fetter <david@fetter.org> wrote:
Please find attached a patch to change the sub-second granularity of
log timestamps from milliseconds to microseconds.Why is this a good idea?
I can imagine that some people would have a use for microsecond
resolution in log files, and I can also imagine that as machines
get faster more people will want that.
Your imagination matches situations I've seen in production where
there was some ambiguity as to what happened when inside a millisecond
boundary, and I'm sure I'm not alone in this. I've gotten this
request from at least three people who to my knowledge knew nothing
about each other, and as I recall, the first time someone brought it
up to me was over five years back.
As against that, this will bloat log files by a non-microscopic
amount, and it's pretty likely to break some log-scanning tools too.
Three bytes per line, and log-scanning parsers that finicky are
already breaking all the time, respectively.
It's unclear to me that that's a tradeoff we should force on
everyone.
The tradeoff we're forcing on people at the moment is a loss of
precision they didn't ask for, implemented by some extra instructions
they didn't ask us to execute in a part of the code that's a hot path
at exactly the times when the machine is busiest.
I think a proposal less likely to have push-back would be to invent
a different log_line_prefix %-escape to produce microseconds.
Sadly, "%u" is already taken, but perhaps we could use "%U"?A different line of thought is to extend %t to provide a precision
field a la sprintf, so that for example "%.3t" is equivalent to
"%m" and "%.6t" does what David wants, and we won't have to
search for a new escape letter when the day arrives that
somebody wants nanosecond resolution. The same could be done
with %n, avoiding the need to find a different escape letter
for that.
I'll build this more sprintf-like thing if not doing so prevents the
change from happening, but frankly, I don't really see a point in it
because the next "log timestamps at some random negative power of 10
second granularity" requirement I see will be the first.
Best,
David.
--
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
On 2022-Jun-14, David Fetter wrote:
On Mon, Jun 13, 2022 at 04:22:42PM -0400, Tom Lane wrote:
A different line of thought is to extend %t to provide a precision
field a la sprintf, so that for example "%.3t" is equivalent to
"%m" and "%.6t" does what David wants, and we won't have to
search for a new escape letter when the day arrives that
somebody wants nanosecond resolution. The same could be done
with %n, avoiding the need to find a different escape letter
for that.I'll build this more sprintf-like thing if not doing so prevents the
change from happening, but frankly, I don't really see a point in it
because the next "log timestamps at some random negative power of 10
second granularity" requirement I see will be the first.
Do we *have* to provide support for arbitrary numbers of digits, though?
We could provide support for only %.3t and %.6t specifically, and not
worry about other cases (error: width not supported). When somebody
wants %.9t in ten years, we won't have to fight for which letter to
pick. And I agree that widening %m for everybody without recourse is
not great.
--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
Alvaro Herrera <alvherre@alvh.no-ip.org> writes:
Do we *have* to provide support for arbitrary numbers of digits, though?
We could provide support for only %.3t and %.6t specifically, and not
worry about other cases (error: width not supported).
If I were coding it, I would allow only exactly 1 digit (%.Nt) to simplify
the parsing side of things and bound the required buffer size. Without
having written it, it's not clear to me whether further restricting the
set of supported values would save much code. I will point out, though,
that throwing an error during log_line_prefix processing will lead
straight to infinite recursion.
regards, tom lane
On Mon, 20 Jun 2022 at 11:01, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alvaro Herrera <alvherre@alvh.no-ip.org> writes:
If I were coding it, I would allow only exactly 1 digit (%.Nt) to simplify
the parsing side of things and bound the required buffer size. Without
having written it, it's not clear to me whether further restricting the
set of supported values would save much code. I will point out, though,
that throwing an error during log_line_prefix processing will lead
straight to infinite recursion.
I would parse the log_line_prefix when it is set. Then if there is a
problem you just log it using whatever format is in effect and don't change
the setting. Then the worst that happens is that logs show up in a format
log processing isn't prepared to accept.
That being said, I think I fall in the “just start putting more digits in
the log” camp, although it is conceivable the counter arguments might be
convincing.
This entry has been waiting on author input for a while (our current
threshold is roughly two weeks), so I've marked it Returned with
Feedback.
Once you think the patchset is ready for review again, you (or any
interested party) can resurrect the patch entry by visiting
https://commitfest.postgresql.org/38/3683/
and changing the status to "Needs Review", and then changing the
status again to "Move to next CF". (Don't forget the second step;
hopefully we will have streamlined this in the near future!)
Thanks,
--Jacob