Commit 1ff23335 authored by Adrian Reber's avatar Adrian Reber Committed by Andrei Vagin

Printout early log messages

Up until now any pr_* logging command (except pr_msg) was lost if
logging has not been set up (log_init()).

To make sure not logging messages are lost, vprint_on_level() now writes
all messages (except LOG_MSG) to a temporary buffer which is written
to the logging FD once that is set up.
Improved-by: 's avatarAndrei Vagin <avagin@gmail.com>
Signed-off-by: 's avatarAdrian Reber <areber@redhat.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@gmail.com>
parent e1d68095
......@@ -31,11 +31,21 @@
/* Enable timestamps if verbosity is increased from default */
#define LOG_TIMESTAMP (DEFAULT_LOGLEVEL + 1)
#define LOG_BUF_LEN (8*1024)
#define EARLY_LOG_BUF_LEN 1024
static unsigned int current_loglevel = DEFAULT_LOGLEVEL;
static char buffer[LOG_BUF_LEN];
static char buf_off = 0;
/*
* The early_log_buffer is used to store log messages before
* logging is set up to make sure no logs are lost.
*/
static char early_log_buffer[EARLY_LOG_BUF_LEN];
static unsigned int early_log_buf_off = 0;
/* If this is 0 the logging has not been set up yet. */
static int init_done = 0;
static struct timeval start;
/*
......@@ -155,6 +165,45 @@ static void print_versions(void)
buf.release, buf.version, buf.machine);
}
struct early_log_hdr {
uint16_t level;
uint16_t len;
};
static void flush_early_log_buffer(int fd)
{
unsigned int pos = 0;
int ret;
while (pos < early_log_buf_off) {
/*
* The early_log_buffer contains all messages written
* before logging was set up. We only want to print
* out messages which correspond to the requested
* log_level. Therefore the early_log_buffer also contains
* the log_level and the size. This writes one messages,
* depending on the log_level, to the logging fd. Start
* with reading the log_level.
*/
struct early_log_hdr *hdr = (void *)early_log_buffer + pos;
pos += sizeof(hdr);
if (hdr->level <= current_loglevel) {
size_t size = 0;
while (size < hdr->len) {
ret = write(fd, early_log_buffer + pos + size,
hdr->len - size);
if (ret <= 0)
break;
size += ret;
}
}
pos += hdr->len;
}
if (early_log_buf_off)
pr_warn("The early log isn't empty\n");
early_log_buf_off = 0;
}
int log_init(const char *output)
{
int new_logfd, fd;
......@@ -186,6 +235,14 @@ int log_init(const char *output)
if (fd < 0)
goto err;
init_done = 1;
/*
* Once logging is setup this write out all early log messages.
* Only those messages which have to correct log level are printed.
*/
flush_early_log_buffer(fd);
print_versions();
return 0;
......@@ -258,6 +315,41 @@ unsigned int log_get_loglevel(void)
return current_loglevel;
}
static void early_vprint(const char *format, unsigned int loglevel, va_list params)
{
unsigned int log_size = 0;
struct early_log_hdr *hdr;
if (early_log_buf_off >= EARLY_LOG_BUF_LEN)
return;
/* Save loglevel */
hdr = (void *)early_log_buffer + early_log_buf_off;
hdr->level = loglevel;
/* Skip the log entry size */
early_log_buf_off += sizeof(hdr);
if (loglevel >= LOG_TIMESTAMP) {
/*
* If logging is not yet setup we just write zeros
* instead of a real timestamp. This way we can
* keep the same format as the other messages on
* log levels with timestamps (>=LOG_TIMESTAMP).
*/
log_size = snprintf(early_log_buffer + early_log_buf_off,
sizeof(early_log_buffer) - early_log_buf_off,
"(00.000000) ");
}
log_size += vsnprintf(early_log_buffer + early_log_buf_off + log_size,
sizeof(early_log_buffer) - early_log_buf_off - log_size,
format, params);
/* Save log entry size */
hdr->len = log_size;
early_log_buf_off += log_size;
}
void vprint_on_level(unsigned int loglevel, const char *format, va_list params)
{
int fd, size, ret, off = 0;
......@@ -267,6 +359,14 @@ void vprint_on_level(unsigned int loglevel, const char *format, va_list params)
fd = STDOUT_FILENO;
off = buf_off; /* skip dangling timestamp */
} else {
/*
* If logging has not yet been initialized (init_done == 0)
* make sure all messages are written to the early_log_buffer.
*/
if (!init_done) {
early_vprint(format, loglevel, params);
return;
}
if (loglevel > current_loglevel)
return;
fd = log_get_fd();
......@@ -284,6 +384,7 @@ void vprint_on_level(unsigned int loglevel, const char *format, va_list params)
off += ret;
}
/* This is missing for messages in the early_log_buffer. */
if (loglevel == LOG_ERROR)
log_note_err(buffer + buf_off);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment