From bc73f84e5b3577479811bb6cf5a77b5add235c1a Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Sun, 29 Nov 2009 22:48:49 +0200 Subject: [PATCH] * mu-log: add initial implementation of mu logging --- src/mu-log.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/mu-log.h | 65 +++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 src/mu-log.c create mode 100644 src/mu-log.h diff --git a/src/mu-log.c b/src/mu-log.c new file mode 100644 index 00000000..d55265b3 --- /dev/null +++ b/src/mu-log.c @@ -0,0 +1,195 @@ +/* +** Copyright (C) 2008 Dirk-Jan C. Binnema +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, +** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mu-log.h" + +struct _MuLog { + int _fd; /* log file descriptor */ + int _own; /* close _fd with log_destroy? */ + int _log_id; /* log handler id */ + int _debug; /* add debug-level stuff? */ +}; +typedef struct _MuLog MuLog; + +static void log_write (const char* domain, GLogLevelFlags level, + const gchar *msg); + +static MuLog* MU_LOG = NULL; + +static void +try_close (int fd) +{ + if (close (fd) < 0) + fprintf (stderr, "%s: close() of fd %d failed: %s\n", + __FUNCTION__, fd, strerror(errno)); +} + + +static void +silence (void) +{ + return; +} + +gboolean +mu_log_init_silence (void) +{ + g_return_val_if_fail (!MU_LOG, FALSE); + + MU_LOG = g_new(MuLog, 1); + MU_LOG->_fd = -1; + + MU_LOG->_log_id = + g_log_set_handler (NULL, + G_LOG_LEVEL_DEBUG| + G_LOG_LEVEL_MESSAGE| + G_LOG_LEVEL_INFO, + (GLogFunc)silence, NULL); + return TRUE; +} + + +static void +log_handler (const gchar* log_domain, GLogLevelFlags log_level, + const gchar* msg) +{ + if (log_level == G_LOG_LEVEL_DEBUG && MU_LOG->_debug) + return; + + log_write (log_domain ? log_domain : "mu", log_level, msg); +} + + +gboolean +mu_log_init_with_fd (int fd, gboolean doclose, gboolean debug) +{ + g_return_val_if_fail (!MU_LOG, FALSE); + + MU_LOG = g_new(MuLog, 1); + + MU_LOG->_fd = fd; + MU_LOG->_debug = debug; + MU_LOG->_own = doclose; /* if we now own the fd, close it + * in _destroy */ + + g_log_set_handler ("mu", G_LOG_LEVEL_MASK, + (GLogFunc)log_handler, NULL); + + return TRUE; +} + +gboolean +mu_log_init_with_file (const char* file, gboolean append, gboolean debug) +{ + int fd; + + /* only init once... */ + g_return_val_if_fail (!MU_LOG, FALSE); + + fd = -1; + if (file) { + fd = open (file, + O_WRONLY|O_CREAT|(append ? O_APPEND : O_TRUNC), + 00600); + if (fd < 0) { + fprintf (stderr, "%s: open() of '%s' failed: %s\n", + __FUNCTION__, file, strerror(errno)); + return FALSE; + } + } + + if (!mu_log_init_with_fd (fd, FALSE, debug)) { + try_close (fd); + return FALSE; + } + + return TRUE; +} + + + +void +mu_log_uninit (void) +{ + g_return_if_fail (MU_LOG); + + if (MU_LOG->_own) + try_close (MU_LOG->_fd); + + g_free (MU_LOG); + MU_LOG = NULL; +} + + +static const char* +pfx (GLogLevelFlags level) +{ + switch (level) { + case G_LOG_LEVEL_WARNING: return "WARN"; + case G_LOG_LEVEL_ERROR : return "ERR "; + case G_LOG_LEVEL_DEBUG: return "DBG "; + case G_LOG_LEVEL_CRITICAL : return "CRIT"; + case G_LOG_LEVEL_MESSAGE: return "MSG "; + case G_LOG_LEVEL_INFO : return "INFO"; + default: return "LOG "; + } +} + +static void +log_write (const char* domain, GLogLevelFlags level, + const gchar *msg) +{ + time_t now; + ssize_t len; + + /* log lines will be truncated at 255 chars */ + char buf [255], timebuf [32]; + + /* get the time/date string */ + now = time(NULL); + strftime (timebuf, sizeof(timebuf), "%F %T", localtime(&now)); + + /* now put it all together */ + len = snprintf (buf, sizeof(buf), "%s [%s] [%s] %s\n", timebuf, + pfx(level), domain, msg); + + len = write (MU_LOG->_fd, buf, len); + if (len < 0) + fprintf (stderr, "%s: failed to write to log: %s\n", + __FUNCTION__, strerror(errno)); + + /* for serious errors, log them to stderr as well */ + if (level & G_LOG_LEVEL_ERROR) + g_printerr ("error: %s\n", msg); + else if (level & G_LOG_LEVEL_CRITICAL) + g_printerr ("critical: %s\n", msg); + else if (level & G_LOG_LEVEL_WARNING) + g_printerr ("warning: %s\n", msg); +} diff --git a/src/mu-log.h b/src/mu-log.h new file mode 100644 index 00000000..cca1fb82 --- /dev/null +++ b/src/mu-log.h @@ -0,0 +1,65 @@ +/* +** Copyright (C) 2008, 2009 Dirk-Jan C. Binnema +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, +** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +*/ + +#ifndef __MU_LOG_H__ +#define __MU_LOG_H__ + +#include + +/* mu log is the global logging system */ + +/** + * write logging information to a file descriptor + * + * @param fd an open file descriptor + * @param doclose if true, mu-log will close it upon mu_log_uninit + * @param debug include debug-level info + * + * @return TRUE if initialization succeeds, FALSE otherwise + */ +gboolean mu_log_init_with_fd (int fd, gboolean doclose, gboolean debug); + + +/** + * write logging information to a file descriptor + * + * @param a filename to log to + * @param append append to logfile, instead of overwriting + * @param debug include debug-level information. + * + * @return TRUE if initialization succeeds, FALSE otherwise + */ +gboolean mu_log_init_with_file (const char* file, gboolean append, + gboolean debug); + +/** + * be absolutely silent, except for runtime errors, which will be + * written to stderr. + * + * @return TRUE if initialization succeeds, FALSE otherwise + */ +gboolean mu_log_init_silence (void); + + +/** + * unitialize the logging system, and free all resources + */ +void mu_log_uninit (void); + +#endif /*__MU_LOG_H__*/