/* GKrellM | Copyright (C) 1999-2009 Bill Wilson | | Author: Stefan Gehn stefan+gkrellm@srcbox.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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. | | GKrellM 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, see http://www.gnu.org/licenses/ | | | Additional permission under GNU GPL version 3 section 7 | | If you modify this program, or any covered work, by linking or | combining it with the OpenSSL project's OpenSSL library (or a | modified version of that library), containing parts covered by | the terms of the OpenSSL or SSLeay licenses, you are granted | additional permission to convey the resulting work. | Corresponding Source for a non-source form of such a combination | shall include the source code for the parts of OpenSSL used as well | as that of the covered work. */ /* Wanted logic: - g_print for user-visible messages, --version and --help fall into this category. g_print usage should be kept at a minimum because gkrellm is a gui-app, while gkrellmd is a daemon. Neither of them is suited for terminal-interaction. - gkrellm_debug(DEBUG_FOO, "msg"); for all debug messages. - g_warning("msg") for all failed function calls etc. Output should go to: - g_print : gui-window or stdout where applicable - gkrellm_debug : gui-window or logfile if set - gkrellm_warning: gui-window or logfile if set */ #include "log.h" #include "log-private.h" #include // Include gkrellm headers to access _GK struct inside gkrellm_debug() #if defined(GKRELLM_SERVER) #include "../server/gkrellmd.h" #include "../server/gkrellmd-private.h" #else #include "../src/gkrellm.h" #include "../src/gkrellm-private.h" #endif typedef struct _GkrellmLogFacility { GkrellmLogFunc log; GkrellmLogCleanupFunc cleanup; } GkrellmLogFacility; static GPtrArray *s_log_facility_ptr_array = NULL; // ---------------------------------------------------------------------------- // Logging into a logfile /** * Handle to a logfile. * Set by gkrellm_log_set_filename() and used by gkrellm_log_to_file() **/ static FILE *s_gkrellm_logfile = NULL; static gboolean gkrellm_log_file_cleanup() { if (s_gkrellm_logfile) fclose(s_gkrellm_logfile); s_gkrellm_logfile = NULL; return TRUE; } static void gkrellm_log_file_log(GLogLevelFlags log_level, const gchar *message) { time_t raw_time; char *local_time_str; if (!s_gkrellm_logfile) return; // Prepend log message with current date/time time(&raw_time); local_time_str = ctime(&raw_time); local_time_str[24] = ' '; // overwrite newline with space fputs(local_time_str, s_gkrellm_logfile); fputs(message, s_gkrellm_logfile); fflush(s_gkrellm_logfile); } void gkrellm_log_set_filename(const gchar* filename) { // Remove from logging chain if we already had been registered before // This also cleans up an open logfile. gkrellm_log_unregister(gkrellm_log_file_log); if (filename && filename[0] != '\0') { // Open the file to log into s_gkrellm_logfile = g_fopen(filename, "at"); // Add our callbacks to logging chain if (s_gkrellm_logfile) { gkrellm_log_register(gkrellm_log_file_log, NULL, gkrellm_log_file_cleanup); } } } // ---------------------------------------------------------------------------- //! Logs onto stdout/stderr static void gkrellm_log_to_terminal(GLogLevelFlags log_level, const gchar *message) { // warning, error or critical go to stderr if (log_level & G_LOG_LEVEL_WARNING || log_level & G_LOG_LEVEL_CRITICAL || log_level & G_LOG_LEVEL_ERROR) { fputs(message, stderr); return; } #if defined(WIN32) // debug on windows gets special treatment if (log_level & G_LOG_LEVEL_DEBUG) OutputDebugStringA(message); #endif // Everything also ends up on stdout // (may be invisible on most desktop-systems, especially on windows!) fputs(message, stdout); } // ---------------------------------------------------------------------------- //! Handler that receives all the log-messages first static void gkrellm_log_handler(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { gchar *localized_message; gint i; GkrellmLogFacility *f; localized_message = g_locale_from_utf8(message, -1, NULL, NULL, NULL); if (localized_message == NULL) { for (i = 0; i < s_log_facility_ptr_array->len; i++) { f = (g_ptr_array_index(s_log_facility_ptr_array, i)); f->log(log_level, message); } } else { for (i = 0; i < s_log_facility_ptr_array->len; i++) { f = (g_ptr_array_index(s_log_facility_ptr_array, i)); f->log(log_level, localized_message); } g_free(localized_message); } } // ---------------------------------------------------------------------------- // Non-Static functions that can be used in gkrellm void gkrellm_log_init() { if (s_log_facility_ptr_array) return; // already initialized s_log_facility_ptr_array = g_ptr_array_new(); g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, gkrellm_log_handler, NULL); gkrellm_log_register(gkrellm_log_to_terminal, NULL, NULL); } void gkrellm_log_cleanup() { gint i; GkrellmLogFacility *f; if (!s_log_facility_ptr_array) return; // gkrellm_log_init() not called yet // Call cleanup on all log-facilities and free our internal struct for (i = 0; i < s_log_facility_ptr_array->len; i++) { f = (g_ptr_array_index(s_log_facility_ptr_array, i)); if (f->cleanup != NULL) f->cleanup(); g_free(f); } g_ptr_array_free(s_log_facility_ptr_array, TRUE); s_log_facility_ptr_array = NULL; } gboolean gkrellm_log_register( GkrellmLogFunc log, GkrellmLogInitFunc init, GkrellmLogCleanupFunc cleanup) { GkrellmLogFacility *f; gint i; if (!s_log_facility_ptr_array) return FALSE; // gkrellm_log_init() not called yet // Check if log callback is already regisrered for (i = 0; i < s_log_facility_ptr_array->len; i++) { f = (g_ptr_array_index(s_log_facility_ptr_array, i)); if (f->log == log) return TRUE; } if (init != NULL && init() == FALSE) return FALSE; // remember logging function and cleanup function in a struct f = g_new0(GkrellmLogFacility, 1); f->log = log; f->cleanup = cleanup; // add struct to list of log facilities g_ptr_array_add(s_log_facility_ptr_array, (gpointer)f); return TRUE; } gboolean gkrellm_log_unregister(GkrellmLogFunc log) { gint i; GkrellmLogFacility *f; if (!s_log_facility_ptr_array) return FALSE; // gkrellm_log_init() not called yet for (i = 0; i < s_log_facility_ptr_array->len; i++) { f = (g_ptr_array_index(s_log_facility_ptr_array, i)); if (f->log == log) { if (f->cleanup != NULL) f->cleanup(); g_ptr_array_remove_index(s_log_facility_ptr_array, i); g_free(f); return TRUE; } } return FALSE; } // ---------------------------------------------------------------------------- // Public functions that can be used in gkrellm and plugins void gkrellm_debug(guint debug_level, const gchar *format, ...) { if (_GK.debug_level & debug_level) { va_list varargs; va_start(varargs, format); g_logv(NULL, G_LOG_LEVEL_DEBUG, format, varargs); va_end(varargs); } } void gkrellm_debugv(guint debug_level, const gchar *format, va_list arg) { if (_GK.debug_level & debug_level) { g_logv(NULL, G_LOG_LEVEL_DEBUG, format, arg); } }