gnc-trace.c

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

Generated on Fri Oct 21 15:49:54 2005 for QOF by  doxygen 1.4.5