summaryrefslogtreecommitdiff
path: root/chardev
diff options
context:
space:
mode:
authorVladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>2026-02-01 20:36:31 +0300
committerMarc-André Lureau <marcandre.lureau@redhat.com>2026-02-13 10:00:02 +0100
commitb108dcbebc05b65ca2db2d506f2e93204fb2424a (patch)
tree3bdc439c8f623998c5045349bf68c82038837774 /chardev
parent2eed5472ec424d217786af97e6212e68e49c5d0b (diff)
downloadqemu-b108dcbebc05b65ca2db2d506f2e93204fb2424a.tar.gz
qemu-b108dcbebc05b65ca2db2d506f2e93204fb2424a.zip
chardev: add logtimestamp option
Add an option to inject timestamps into serial log file. That simplifies debugging a lot, when you can simply compare QEMU logs with guest console logs. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Acked-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-ID: <20260201173633.413934-4-vsementsov@yandex-team.ru>
Diffstat (limited to 'chardev')
-rw-r--r--chardev/char.c63
1 files changed, 58 insertions, 5 deletions
diff --git a/chardev/char.c b/chardev/char.c
index 4b285baf02..48b326d57b 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -82,12 +82,8 @@ void qemu_chr_be_event(Chardev *s, QEMUChrEvent event)
CHARDEV_GET_CLASS(s)->chr_be_event(s, event);
}
-static void qemu_chr_write_log(Chardev *s, const uint8_t *buf, size_t len)
+static void do_write_log(Chardev *s, const uint8_t *buf, size_t len)
{
- if (s->logfd < 0) {
- return;
- }
-
if (qemu_write_full(s->logfd, buf, len) < len) {
/*
* qemu_write_full() is defined with G_GNUC_WARN_UNUSED_RESULT,
@@ -96,6 +92,55 @@ static void qemu_chr_write_log(Chardev *s, const uint8_t *buf, size_t len)
}
}
+static void do_write_log_timestamps(Chardev *s, const uint8_t *buf, size_t len)
+{
+ g_autofree char *timestr = NULL;
+
+ while (len) {
+ size_t i;
+
+ if (s->log_line_start) {
+ if (!timestr) {
+ timestr = real_time_iso8601();
+ }
+ do_write_log(s, (const uint8_t *)timestr, strlen(timestr));
+ do_write_log(s, (const uint8_t *)" ", 1);
+ s->log_line_start = false;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] == '\n') {
+ break;
+ }
+ }
+
+ if (i == len) {
+ /* not found \n */
+ do_write_log(s, buf, len);
+ return;
+ }
+
+ i += 1;
+ do_write_log(s, buf, i);
+ buf += i;
+ len -= i;
+ s->log_line_start = true;
+ }
+}
+
+static void qemu_chr_write_log(Chardev *s, const uint8_t *buf, size_t len)
+{
+ if (s->logfd < 0) {
+ return;
+ }
+
+ if (s->logtimestamp) {
+ do_write_log_timestamps(s, buf, len);
+ } else {
+ do_write_log(s, buf, len);
+ }
+}
+
static int qemu_chr_write_buffer(Chardev *s,
const uint8_t *buf, int len,
int *offset, bool write_all)
@@ -248,6 +293,7 @@ static bool qemu_char_open(Chardev *chr, ChardevBackend *backend, Error **errp)
} else {
flags |= O_TRUNC;
}
+ chr->logtimestamp = common->has_logtimestamp && common->logtimestamp;
chr->logfd = qemu_create(common->logfile, flags, 0666, errp);
if (chr->logfd < 0) {
return false;
@@ -267,6 +313,7 @@ static void char_init(Object *obj)
chr->handover_yank_instance = false;
chr->logfd = -1;
+ chr->log_line_start = true;
qemu_mutex_init(&chr->chr_write_lock);
/*
@@ -505,6 +552,9 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
backend->logfile = g_strdup(logfile);
backend->has_logappend = true;
backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
+
+ backend->has_logtimestamp = true;
+ backend->logtimestamp = qemu_opt_get_bool(opts, "logtimestamp", false);
}
static const ChardevClass *char_get_class(const char *driver, Error **errp)
@@ -957,6 +1007,9 @@ QemuOptsList qemu_chardev_opts = {
.name = "logappend",
.type = QEMU_OPT_BOOL,
},{
+ .name = "logtimestamp",
+ .type = QEMU_OPT_BOOL,
+ },{
.name = "mouse",
.type = QEMU_OPT_BOOL,
},{