1
0
Fork 0

log: Introduced stderr log handler

This handler redirects stderr output to a pipe and gathers logs from the
read end.

The handler is called from main loop, therefore, if a function prints logs
to stderr they will be put to log file only after function returns.
This commit is contained in:
Dmitry Podgorny 2015-06-22 11:30:23 +00:00
parent 2d3537515d
commit e831410669
4 changed files with 114 additions and 0 deletions

103
src/log.c
View File

@ -34,6 +34,7 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -61,6 +62,16 @@ static GHashTable *logs;
static GHashTable *groupchat_logs;
static GDateTime *session_started;
enum {
STDERR_BUFSIZE = 4000,
STDERR_RETRY_NR = 5,
};
static int stderr_inited;
static log_level_t stderr_level;
static int stderr_pipe[2];
static char *stderr_buf;
static GString *stderr_msg;
struct dated_chat_log {
gchar *filename;
GDateTime *date;
@ -690,3 +701,95 @@ _log_string_from_level(log_level_t level)
return "LOG";
}
}
void
log_stderr_handler(void)
{
GString * const s = stderr_msg;
char * const buf = stderr_buf;
ssize_t size;
int retry = 0;
int i;
if (!stderr_inited)
return;
do {
size = read(stderr_pipe[0], buf, STDERR_BUFSIZE);
if (size == -1 && errno == EINTR && retry++ < STDERR_RETRY_NR)
continue;
if (size <= 0 || retry++ >= STDERR_RETRY_NR)
break;
for (i = 0; i < size; ++i) {
if (buf[i] == '\n') {
log_msg(stderr_level, "stderr", s->str);
g_string_assign(s, "");
} else
g_string_append_c(s, buf[i]);
}
} while (1);
if (s->len > 0 && s->str[0] != '\0') {
log_msg(stderr_level, "stderr", s->str);
g_string_assign(s, "");
}
}
void
log_stderr_init(log_level_t level)
{
int rc;
int flags;
rc = pipe(stderr_pipe);
if (rc != 0)
goto err;
flags = fcntl(stderr_pipe[0], F_GETFL);
rc = fcntl(stderr_pipe[0], F_SETFL, flags | O_NONBLOCK);
if (rc != 0)
goto err_close;
close(STDERR_FILENO);
rc = dup2(stderr_pipe[1], STDERR_FILENO);
if (rc < 0)
goto err_close;
stderr_buf = malloc(STDERR_BUFSIZE);
stderr_msg = g_string_sized_new(STDERR_BUFSIZE);
stderr_level = level;
stderr_inited = 1;
if (stderr_buf == NULL || stderr_msg == NULL) {
errno = ENOMEM;
goto err_free;
}
return;
err_free:
if (stderr_msg != NULL)
g_string_free(stderr_msg, TRUE);
free(stderr_buf);
err_close:
close(stderr_pipe[0]);
close(stderr_pipe[1]);
err:
stderr_inited = 0;
log_error("Unable to init stderr log handler: %s", strerror(errno));
}
void
log_stderr_close(void)
{
if (!stderr_inited)
return;
/* handle remaining logs before close */
log_stderr_handler();
stderr_inited = 0;
free(stderr_buf);
g_string_free(stderr_msg, TRUE);
close(stderr_pipe[0]);
close(stderr_pipe[1]);
}

View File

@ -63,6 +63,10 @@ void log_msg(log_level_t level, const char * const area,
const char * const msg);
log_level_t log_level_from_string(char *log_level);
void log_stderr_init(log_level_t level);
void log_stderr_close(void);
void log_stderr_handler(void);
void chat_log_init(void);
void chat_log_msg_out(const char * const barejid, const char * const msg);

View File

@ -89,6 +89,7 @@ prof_run(const int disable_tls, char *log_level, char *account_name)
char *line = NULL;
while(cont) {
log_stderr_handler();
_check_autoaway();
line = ui_readline();
@ -225,6 +226,7 @@ _init(const int disable_tls, char *log_level)
log_level_t prof_log_level = log_level_from_string(log_level);
prefs_load();
log_init(prof_log_level);
log_stderr_init(PROF_LEVEL_ERROR);
if (strcmp(PACKAGE_STATUS, "development") == 0) {
#ifdef HAVE_GIT_VERSION
log_info("Starting Profanity (%sdev.%s.%s)...", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION);
@ -283,6 +285,7 @@ _shutdown(void)
theme_close();
accounts_close();
cmd_uninit();
log_stderr_close();
log_close();
prefs_close();
}

View File

@ -49,6 +49,10 @@ log_level_t log_level_from_string(char *log_level)
return (log_level_t)mock();
}
void log_stderr_init(log_level_t level) {}
void log_stderr_close(void) {}
void log_stderr_handler(void) {}
void chat_log_init(void) {}
void chat_log_msg_out(const char * const barejid, const char * const msg) {}