00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
00053
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)
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
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
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;
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
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