qoflog.c

00001 /* **************************************************************************
00002  *            qoflog.c
00003  *
00004  *  Mon Nov 21 14:41:59 2005
00005  *  Author: Rob Clark (rclark@cs.hmc.edu)
00006  *  Copyright (C) 1997-2003 Linas Vepstas <linas@linas.org>
00007  *  Copyright  2005  Neil Williams
00008  *  linux@codehelp.co.uk
00009  *************************************************************************** */
00010 /*
00011  *  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public License
00022  *  along with this program; if not, write to the Free Software
00023  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00024  *  02110-1301,  USA
00025  */
00026  
00027 #include "config.h"
00028 
00029 #include <glib.h>
00030 #ifdef HAVE_UNISTD_H
00031 #include <unistd.h>
00032 #else
00033 #warning unistd required.
00034 #endif
00035 #include <stdarg.h>
00036 #include <string.h>
00037 #include <sys/time.h>
00038 #include "qof.h"
00039 #include "qoflog.h"
00040 
00041 #define QOF_LOG_MAX_CHARS 50
00042 #define QOF_LOG_INDENT_WIDTH 4
00043 #define NUM_CLOCKS 10
00044 
00045 static FILE *fout = NULL;
00046 static gchar* filename = NULL;
00047 static gchar* function_buffer = NULL;
00048 static const int MAX_TRACE_FILENAME = 100;
00049 static GHashTable *log_table = NULL;
00050 static gint qof_log_num_spaces = 0;
00051 
00052 /* uses the enum_as_string macro.
00053 Lookups are done on the string. */
00054 AS_STRING_FUNC(QofLogLevel, LOG_LEVEL_LIST)
00055 
00056 FROM_STRING_FUNC(QofLogLevel, LOG_LEVEL_LIST)
00057 
00058 void
00059 qof_log_add_indent(void)
00060 {
00061         qof_log_num_spaces += QOF_LOG_INDENT_WIDTH;
00062 }
00063 
00064 gint 
00065 qof_log_get_indent(void)
00066 {
00067         return qof_log_num_spaces;
00068 }
00069 
00070 void
00071 qof_log_drop_indent(void)
00072 {
00073         qof_log_num_spaces = (qof_log_num_spaces < QOF_LOG_INDENT_WIDTH) ?
00074                 0 : qof_log_num_spaces - QOF_LOG_INDENT_WIDTH;
00075 }
00076 
00077 static void
00078 fh_printer (const gchar     *log_domain,
00079             GLogLevelFlags  log_level,
00080             const gchar     *message,
00081             gpointer        user_data)
00082 {
00083   FILE *fh = user_data;
00084   fprintf (fh, "%*s%s\n", qof_log_num_spaces, "", message);
00085   fflush(fh);
00086 }
00087 
00088 void 
00089 qof_log_init (void)
00090 {
00091    if(!fout) /* allow qof_log_set_file */
00092    {
00093            fout = fopen ("/tmp/qof.trace", "w");
00094    }
00095 
00096    if(!fout && (filename = (gchar *)g_malloc(MAX_TRACE_FILENAME))) {
00097       snprintf(filename, MAX_TRACE_FILENAME-1, "/tmp/qof.trace.%d", 
00098                getpid());
00099       fout = fopen (filename, "w");
00100       g_free(filename);
00101    }
00102 
00103    if(!fout)
00104       fout = stderr;
00105 
00106    g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, fh_printer, fout);
00107 }
00108 
00109 void
00110 qof_log_set_level(QofLogModule log_module, QofLogLevel level)
00111 {
00112         gchar* level_string;
00113 
00114         if(!log_module || level == 0) { return; }
00115         level_string = g_strdup(QofLogLevelasString(level));
00116         if(!log_table)
00117         {
00118                 log_table = g_hash_table_new(g_str_hash, g_str_equal);
00119         }
00120         g_hash_table_insert(log_table, (gpointer)log_module, level_string);
00121 }
00122 
00123 static void
00124 log_module_foreach(gpointer key, gpointer value, gpointer data)
00125 {
00126         g_hash_table_insert(log_table, key, data);
00127 }
00128 
00129 void
00130 qof_log_set_level_registered(QofLogLevel level)
00131 {
00132         gchar* level_string;
00133 
00134         if(!log_table || level == 0) { return; }
00135         level_string = g_strdup(QofLogLevelasString(level));
00136         g_hash_table_foreach(log_table, log_module_foreach, level_string);
00137 }
00138 
00139 void
00140 qof_log_set_file (FILE *outfile)
00141 {
00142    if(!outfile) { fout = stderr; return; }
00143    fout = outfile;
00144 }
00145 
00146 void
00147 qof_log_init_filename (const gchar* logfilename)
00148 {
00149         if(!logfilename)
00150         {
00151                 fout = stderr;
00152         }
00153         else
00154         {
00155                 filename = g_strdup(logfilename);
00156                 fout = fopen(filename, "w");
00157         }
00158         qof_log_init();
00159 }
00160 
00161 void
00162 qof_log_shutdown (void)
00163 {
00164         if(fout && fout != stderr) { fclose(fout); }
00165         if(filename) { g_free(filename); }
00166         if(function_buffer) { g_free(function_buffer); }
00167         g_hash_table_destroy(log_table);
00168 }
00169 
00170 const char *
00171 qof_log_prettify (const char *name)
00172 {
00173   gchar *p, *buffer;
00174   gint length;
00175 
00176   if (!name) { return ""; }
00177   buffer = g_strndup(name, QOF_LOG_MAX_CHARS - 1);
00178   length = strlen(buffer);
00179   p = g_strstr_len(buffer, length, "(");
00180   if (p)
00181   {
00182     *(p+1) = ')';
00183     *(p+2) = 0x0;
00184   }
00185   else { strcpy (&buffer[QOF_LOG_MAX_CHARS - 4], "...()"); }
00186   function_buffer = g_strdup(buffer);
00187   g_free(buffer);
00188   return function_buffer;
00189 }
00190 
00191 static
00192 struct timeval qof_clock[NUM_CLOCKS] = {
00193    {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 
00194    {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 
00195 };
00196 
00197 static
00198 struct timeval qof_clock_total[NUM_CLOCKS] = {
00199    {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 
00200    {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 
00201 };
00202 
00203 void
00204 qof_start_clock (int clockno, QofLogModule log_module, QofLogLevel log_level,
00205                  const gchar *function_name, const gchar *format, ...)
00206 {
00207   va_list ap;
00208 
00209   if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
00210 #ifdef HAVE_GETTIMEOFDAY
00211   gettimeofday (&qof_clock[clockno], NULL);
00212 #else
00213   time (&(qof_clock[clockno].tv_sec));
00214   qof_clock[clockno].tv_usec = 0;
00215 #endif
00216 
00217   if (!fout) qof_log_init();
00218 
00219   fprintf (fout, "Clock %d Start: %s: ",
00220            clockno, qof_log_prettify (function_name));
00221 
00222   va_start (ap, format);
00223 
00224   vfprintf (fout, format, ap);
00225 
00226   va_end (ap);
00227 
00228   fprintf (fout, "\n");
00229   fflush (fout);
00230 }
00231 
00232 void
00233 qof_report_clock (gint clockno, QofLogModule log_module, QofLogLevel log_level,
00234                   const gchar *function_name, const gchar *format, ...)
00235 {
00236   struct timeval now;
00237   va_list ap;
00238 
00239   if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
00240 #ifdef HAVE_GETTIMEOFDAY
00241   gettimeofday (&now, NULL);
00242 #else
00243   time (&(now.tv_sec));
00244   now.tv_usec = 0;
00245 #endif
00246 
00247   /* need to borrow to make difference */
00248   if (now.tv_usec < qof_clock[clockno].tv_usec)
00249   {
00250     now.tv_sec --;
00251     now.tv_usec += 1000000;
00252   }
00253   now.tv_sec -= qof_clock[clockno].tv_sec;
00254   now.tv_usec -= qof_clock[clockno].tv_usec;
00255 
00256   qof_clock_total[clockno].tv_sec += now.tv_sec;
00257   qof_clock_total[clockno].tv_usec += now.tv_usec;
00258 
00259   if (!fout) qof_log_init();
00260 
00261   fprintf (fout, "Clock %d Elapsed: %ld.%06lds %s: ",
00262            clockno, (long int) now.tv_sec, (long int) now.tv_usec, 
00263                qof_log_prettify (function_name));
00264 
00265   va_start (ap, format);
00266 
00267   vfprintf (fout, format, ap);
00268 
00269   va_end (ap);
00270 
00271   fprintf (fout, "\n");
00272   fflush (fout);
00273 }
00274 
00275 void
00276 qof_report_clock_total (gint clockno,
00277                         QofLogModule log_module, QofLogLevel log_level,
00278                         const gchar *function_name, const gchar *format, ...)
00279 {
00280   va_list ap;
00281 
00282   if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
00283 
00284   /* need to normalize usec */
00285   while (qof_clock_total[clockno].tv_usec >= 1000000)
00286   {
00287     qof_clock_total[clockno].tv_sec ++;
00288     qof_clock_total[clockno].tv_usec -= 1000000;
00289   }
00290 
00291   if (!fout) qof_log_init();
00292 
00293   fprintf (fout, "Clock %d Total Elapsed: %ld.%06lds  %s: ",
00294            clockno,
00295            (long int) qof_clock_total[clockno].tv_sec,
00296            (long int) qof_clock_total[clockno].tv_usec,
00297            qof_log_prettify (function_name));
00298 
00299   va_start (ap, format);
00300 
00301   vfprintf (fout, format, ap);
00302 
00303   va_end (ap);
00304 
00305   fprintf (fout, "\n");
00306   fflush (fout);
00307 }
00308 
00309 gboolean
00310 qof_log_check(QofLogModule log_module, QofLogLevel log_level)
00311 {
00312         gchar* log_string;
00313         QofLogLevel maximum; /* Any positive log_level less than this will be logged. */
00314 
00315         log_string = NULL;
00316         if (log_level > QOF_LOG_TRACE) log_level = QOF_LOG_TRACE;
00317         if(!log_table || log_module == NULL || log_level < 0) { return FALSE; }
00318         log_string = (gchar*)g_hash_table_lookup(log_table, log_module);
00319         /* if log_module not found, do not log. */
00320         if(!log_string) { return FALSE; }
00321         maximum = QofLogLevelfromString(log_string);
00322         if(log_level <= maximum) { return TRUE; }
00323         return FALSE;
00324 }
00325 
00326 void qof_log_set_default(QofLogLevel log_level)
00327 {
00328         qof_log_set_level(QOF_MOD_BACKEND, log_level);
00329         qof_log_set_level(QOF_MOD_CLASS,   log_level);
00330         qof_log_set_level(QOF_MOD_ENGINE,  log_level);
00331         qof_log_set_level(QOF_MOD_OBJECT,  log_level);
00332         qof_log_set_level(QOF_MOD_KVP,     log_level);
00333         qof_log_set_level(QOF_MOD_MERGE,   log_level);
00334         qof_log_set_level(QOF_MOD_QUERY,   log_level);
00335         qof_log_set_level(QOF_MOD_SESSION, log_level);
00336         qof_log_set_level(QOF_MOD_CHOICE,  log_level);
00337         qof_log_set_level(QOF_MOD_UTIL,    log_level);
00338 }
00339 
00340 struct hash_s
00341 {
00342         QofLogCB cb;
00343         gpointer data;
00344 };
00345 
00346 static void hash_cb (gpointer key, gpointer value, gpointer data)
00347 {
00348         struct hash_s *iter;
00349 
00350         iter = (struct hash_s*)data;
00351         if(!iter) { return; }
00352         (iter->cb)(key, value, iter->data);
00353 }
00354 
00355 void qof_log_module_foreach(QofLogCB cb, gpointer data)
00356 {
00357         struct hash_s iter;
00358 
00359         if(!cb) { return; }
00360         iter.cb = cb;
00361         iter.data = data;
00362         g_hash_table_foreach(log_table, hash_cb, (gpointer)&iter);
00363 }
00364 
00365 gint qof_log_module_count(void)
00366 {
00367         if(!log_table) { return 0; }
00368         return g_hash_table_size(log_table);
00369 }
00370 
00371 /* ************************ END OF FILE **************************** */

Generated on Fri May 12 17:57:20 2006 for QOF by  doxygen 1.4.4