Skip to content

Commit

Permalink
vlog: Report timestamps in millisecond resolution in log messages.
Browse files Browse the repository at this point in the history
To make debugging easier.

Signed-off-by: Ben Pfaff <[email protected]>
Signed-off-by: Paul Ingram <[email protected]>
  • Loading branch information
Paul Ingram authored and blp committed Sep 13, 2013
1 parent 63a04c1 commit 2b31d8e
Show file tree
Hide file tree
Showing 13 changed files with 98 additions and 29 deletions.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -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
Expand Down
21 changes: 12 additions & 9 deletions lib/dynamic-string.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down
7 changes: 3 additions & 4 deletions lib/dynamic-string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down
2 changes: 1 addition & 1 deletion lib/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 46 additions & 0 deletions lib/timeval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
9 changes: 9 additions & 0 deletions lib/timeval.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 *);

Expand Down
16 changes: 8 additions & 8 deletions lib/vlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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);
}

Expand Down Expand Up @@ -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. */
Expand Down
2 changes: 1 addition & 1 deletion lib/vlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion ovsdb/ovsdb-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
3 changes: 2 additions & 1 deletion python/ovs/vlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ def __log(self, level, message, **kwargs):
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))

Expand Down
2 changes: 1 addition & 1 deletion tests/vlog.at
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 9 additions & 2 deletions utilities/ovs-appctl.8.in
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 2 additions & 1 deletion utilities/ovs-ofctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down

0 comments on commit 2b31d8e

Please sign in to comment.