2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

vlog: Report timestamps in millisecond resolution in log messages.

To make debugging easier.

Signed-off-by: Ben Pfaff <blp@nicira.com>
Signed-off-by: Paul Ingram <pingram@nicira.com>
This commit is contained in:
Paul Ingram
2013-09-12 18:19:04 -07:00
committed by Ben Pfaff
parent 63a04c1b5f
commit 2b31d8e713
13 changed files with 98 additions and 29 deletions

2
NEWS
View File

@@ -1,5 +1,7 @@
Post-v2.0.0
---------------------
- Log files now report times with millisecond resolution. (Previous
versions only reported whole seconds.)
v2.0.0 - xx xxx xxxx

View File

@@ -183,21 +183,24 @@ ds_put_printable(struct ds *ds, const char *s, size_t n)
}
}
/* Writes time 'when' to 'string' based on 'template', in local time or UTC
* based on 'utc'. */
/* Writes the current time with optional millisecond resolution to 'string'
* based on 'template'.
* The current time is either localtime or UTC based on 'utc'. */
void
ds_put_strftime(struct ds *ds, const char *template, time_t when, bool utc)
ds_put_strftime_msec(struct ds *ds, const char *template, long long int when,
bool utc)
{
struct tm tm;
struct tm_msec tm;
if (utc) {
gmtime_r(&when, &tm);
gmtime_msec(when, &tm);
} else {
localtime_r(&when, &tm);
localtime_msec(when, &tm);
}
for (;;) {
size_t avail = ds->string ? ds->allocated - ds->length + 1 : 0;
size_t used = strftime(&ds->string[ds->length], avail, template, &tm);
size_t used = strftime_msec(&ds->string[ds->length], avail, template,
&tm);
if (used) {
ds->length += used;
return;
@@ -209,12 +212,12 @@ ds_put_strftime(struct ds *ds, const char *template, time_t when, bool utc)
/* Returns a malloc()'d string for time 'when' based on 'template', in local
* time or UTC based on 'utc'. */
char *
xastrftime(const char *template, time_t when, bool utc)
xastrftime_msec(const char *template, long long int when, bool utc)
{
struct ds s;
ds_init(&s);
ds_put_strftime(&s, template, when, utc);
ds_put_strftime_msec(&s, template, when, utc);
return s.string;
}

View File

@@ -61,10 +61,9 @@ int ds_get_line(struct ds *, FILE *);
int ds_get_preprocessed_line(struct ds *, FILE *, int *line_number);
int ds_get_test_line(struct ds *, FILE *);
void ds_put_strftime(struct ds *, const char *template, time_t when, bool utc)
STRFTIME_FORMAT(2);
char *xastrftime(const char *template, time_t when, bool utc)
STRFTIME_FORMAT(1);
void ds_put_strftime_msec(struct ds *, const char *template, long long int when,
bool utc);
char *xastrftime_msec(const char *template, long long int when, bool utc);
char *ds_cstr(struct ds *);
const char *ds_cstr_ro(const struct ds *);

View File

@@ -221,7 +221,7 @@ table_print_table_line__(struct ds *line)
static char *
table_format_timestamp__(void)
{
return xastrftime("%Y-%m-%d %H:%M:%S", time_wall(), true);
return xastrftime_msec("%Y-%m-%d %H:%M:%S.###", time_wall_msec(), true);
}
static void

View File

@@ -494,3 +494,49 @@ timeval_dummy_register(void)
unixctl_command_register("time/warp", "MSECS", 1, 1,
timeval_warp_cb, NULL);
}
/* strftime() with an extension for high-resolution timestamps. Any '#'s in
* 'format' will be replaced by subseconds, e.g. use "%S.###" to obtain results
* like "01.123". */
size_t
strftime_msec(char *s, size_t max, const char *format,
const struct tm_msec *tm)
{
size_t n;
n = strftime(s, max, format, &tm->tm);
if (n) {
char decimals[4];
char *p;
sprintf(decimals, "%03d", tm->msec);
for (p = strchr(s, '#'); p; p = strchr(p, '#')) {
char *d = decimals;
while (*p == '#') {
*p++ = *d ? *d++ : '0';
}
}
}
return n;
}
struct tm_msec *
localtime_msec(long long int now, struct tm_msec *result)
{
time_t now_sec = now / 1000;
localtime_r(&now_sec, &result->tm);
result->msec = now % 1000;
return result;
}
struct tm_msec *
gmtime_msec(long long int now, struct tm_msec *result)
{
time_t now_sec = now / 1000;
gmtime_r(&now_sec, &result->tm);
result->msec = now % 1000;
return result;
}

View File

@@ -40,6 +40,11 @@ BUILD_ASSERT_DECL(TYPE_IS_SIGNED(time_t));
#define TIME_MAX TYPE_MAXIMUM(time_t)
#define TIME_MIN TYPE_MINIMUM(time_t)
struct tm_msec {
struct tm tm;
int msec;
};
time_t time_now(void);
time_t time_wall(void);
long long int time_msec(void);
@@ -53,6 +58,10 @@ int time_poll(struct pollfd *, int n_pollfds, long long int timeout_when,
long long int timespec_to_msec(const struct timespec *);
long long int timeval_to_msec(const struct timeval *);
struct tm_msec *localtime_msec(long long int now, struct tm_msec *result);
struct tm_msec *gmtime_msec(long long int now, struct tm_msec *result);
size_t strftime_msec(char *s, size_t max, const char *format,
const struct tm_msec *);
void xgettimeofday(struct timeval *);
void xclock_gettime(clock_t, struct timespec *);

View File

@@ -583,7 +583,7 @@ static void
vlog_init__(void)
{
static char *program_name_copy;
time_t now;
long long int now;
/* openlog() is allowed to keep the pointer passed in, without making a
* copy. The daemonize code sometimes frees and replaces 'program_name',
@@ -593,10 +593,10 @@ vlog_init__(void)
program_name_copy = program_name ? xstrdup(program_name) : NULL;
openlog(program_name_copy, LOG_NDELAY, LOG_DAEMON);
now = time_wall();
now = time_wall_msec();
if (now < 0) {
char *s = xastrftime("%a, %d %b %Y %H:%M:%S", now, true);
VLOG_ERR("current time is negative: %s (%ld)", s, (long int) now);
char *s = xastrftime_msec("%a, %d %b %Y %H:%M:%S", now, true);
VLOG_ERR("current time is negative: %s (%lld)", s, now);
free(s);
}
@@ -746,12 +746,12 @@ format_log_message(const struct vlog_module *module, enum vlog_level level,
ds_put_cstr(s, vlog_get_module_name(module));
break;
case 'd':
p = fetch_braces(p, "%Y-%m-%d %H:%M:%S", tmp, sizeof tmp);
ds_put_strftime(s, tmp, time_wall(), false);
p = fetch_braces(p, "%Y-%m-%d %H:%M:%S.###", tmp, sizeof tmp);
ds_put_strftime_msec(s, tmp, time_wall_msec(), false);
break;
case 'D':
p = fetch_braces(p, "%Y-%m-%d %H:%M:%S", tmp, sizeof tmp);
ds_put_strftime(s, tmp, time_wall(), true);
p = fetch_braces(p, "%Y-%m-%d %H:%M:%S.###", tmp, sizeof tmp);
ds_put_strftime_msec(s, tmp, time_wall_msec(), true);
break;
case 'm':
/* Format user-supplied log message and trim trailing new-lines. */

View File

@@ -64,7 +64,7 @@ enum vlog_level vlog_get_level_val(const char *name);
#define VLOG_FACILITIES \
VLOG_FACILITY(SYSLOG, "ovs|%05N|%c%T|%p|%m") \
VLOG_FACILITY(CONSOLE, "%D{%Y-%m-%dT%H:%M:%SZ}|%05N|%c%T|%p|%m") \
VLOG_FACILITY(FILE, "%D{%Y-%m-%dT%H:%M:%SZ}|%05N|%c%T|%p|%m")
VLOG_FACILITY(FILE, "%D{%Y-%m-%dT%H:%M:%S.###Z}|%05N|%c%T|%p|%m")
enum vlog_facility {
#define VLOG_FACILITY(NAME, PATTERN) VLF_##NAME,
VLOG_FACILITIES

View File

@@ -519,7 +519,8 @@ do_show_log(int argc, char *argv[])
date = shash_find_data(json_object(json), "_date");
if (date && date->type == JSON_INTEGER) {
time_t t = json_integer(date);
char *s = xastrftime(" %Y-%m-%d %H:%M:%S", t, true);
char *s = xastrftime_msec(" %Y-%m-%d %H:%M:%S",
t * 1000LL, true);
fputs(s, stdout);
free(s);
}

View File

@@ -60,7 +60,8 @@ class Vlog:
if not Vlog.__inited:
return
now = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
dt = datetime.datetime.utcnow();
now = dt.strftime("%Y-%m-%dT%H:%M:%S.%%iZ") % (dt.microsecond/1000)
syslog_message = ("%s|%s|%s|%s"
% (Vlog.__msg_num, self.name, level, message))

View File

@@ -9,7 +9,7 @@ AT_CHECK([$PYTHON $srcdir/test-vlog.py --log-file log_file \
AT_CHECK([diff log_file stderr_log])
AT_CHECK([sed -e 's/.*-.*-.*T..:..:..Z|//' \
AT_CHECK([sed -e 's/.*-.*-.*T..:..:..\....Z|//' \
-e 's/File ".*", line [[0-9]][[0-9]]*,/File <name>, line <number>,/' \
stderr_log], [0], [dnl
0|module_0|EMER|emergency

View File

@@ -158,13 +158,20 @@ The current date and time in ISO 8601 format (YYYY\-MM\-DD HH:MM:SS).
.IP \fB%d{\fIformat\fB}\fR
The current date and time in the specified \fIformat\fR, which takes
the same format as the \fItemplate\fR argument to \fBstrftime\fR(3).
As an extension, any \fB#\fR characters in \fIformat\fR will be
replaced by fractional seconds, e.g. use \fB%H:%M:%S.###\fR for the
time to the nearest millisecond. Sub-second times are only
approximate and currently decimal places after the third will always
be reported as zero.
.
.IP \fB%D\fR
The current UTC date and time in ISO 8601 format (YYYY\-MM\-DD HH:MM:SS).
.
.IP \fB%D{\fIformat\fB}\fR
The current UTC date and time in the specified \fIformat\fR, which takes
the same format as the \fItemplate\fR argument to \fBstrftime\fR(3).
The current UTC date and time in the specified \fIformat\fR, which
takes the same format as the \fItemplate\fR argument to
\fBstrftime\fR(3). Supports the same extension for sub-second
resolution as \fB%d{\fR...\fB}\fR.
.
.IP \fB%m\fR
The message being logged.

View File

@@ -1396,7 +1396,8 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests)
run(retval, "vconn_recv");
if (timestamp) {
char *s = xastrftime("%Y-%m-%d %H:%M:%S: ", time_wall(), true);
char *s = xastrftime_msec("%Y-%m-%d %H:%M:%S.###: ",
time_wall_msec(), true);
fputs(s, stderr);
free(s);
}