1 /* **************************************************************************
2 * qoflog.c
3 *
4 * Mon Nov 21 14:41:59 2005
5 * Author: Rob Clark (rclark@cs.hmc.edu)
6 * Copyright (C) 1997-2003 Linas Vepstas <linas@linas.org>
7 * Copyright 2005-2008 Neil Williams
8 * linux@codehelp.co.uk
9 *************************************************************************** */
10 /*
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * 02110-1301, USA
25 */
26
27 #include "config.h"
28
29 #include <glib.h>
30 #include <unistd.h>
31 #include "qof.h"
32
33 #define QOF_LOG_MAX_CHARS 50
34 #define QOF_LOG_INDENT_WIDTH 4
35
36 static FILE *fout = NULL;
37 static gchar *filename = NULL;
38 static gchar *function_buffer = NULL;
39 static const gint MAX_TRACE_FILENAME = 100;
40 static GHashTable *log_table = NULL;
41 static gint qof_log_num_spaces = 0;
42
43 /* uses the enum_as_string macro.
44 Lookups are done on the string. */
AS_STRING_FUNC(QofLogLevel,LOG_LEVEL_LIST)45 AS_STRING_FUNC (QofLogLevel, LOG_LEVEL_LIST)
46 FROM_STRING_FUNC (QofLogLevel, LOG_LEVEL_LIST)
47
48 void qof_log_add_indent (void)
49 {
50 qof_log_num_spaces += QOF_LOG_INDENT_WIDTH;
51 }
52
53 gint
qof_log_get_indent(void)54 qof_log_get_indent (void)
55 {
56 return qof_log_num_spaces;
57 }
58
59 void
qof_log_drop_indent(void)60 qof_log_drop_indent (void)
61 {
62 qof_log_num_spaces = (qof_log_num_spaces < QOF_LOG_INDENT_WIDTH) ?
63 0 : qof_log_num_spaces - QOF_LOG_INDENT_WIDTH;
64 }
65
66 static void
fh_printer(const gchar * log_domain,GLogLevelFlags log_level,const gchar * message,gpointer user_data)67 fh_printer (const gchar * log_domain __attribute__ ((unused)),
68 GLogLevelFlags log_level __attribute__ ((unused)),
69 const gchar * message, gpointer user_data)
70 {
71 FILE *fh = user_data;
72 fprintf (fh, "%*s%s\n", qof_log_num_spaces, "", message);
73 fflush (fh);
74 }
75
76 void
qof_log_init(void)77 qof_log_init (void)
78 {
79 if (!fout) /* allow qof_log_set_file */
80 {
81 fout = fopen ("/tmp/qof.trace", "w");
82 }
83
84 if (!fout && (filename = (gchar *) g_malloc (MAX_TRACE_FILENAME)))
85 {
86 snprintf (filename, MAX_TRACE_FILENAME - 1, "/tmp/qof.trace.%d",
87 getpid ());
88 fout = fopen (filename, "w");
89 g_free (filename);
90 }
91
92 if (!fout)
93 fout = stderr;
94
95 g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, fh_printer, fout);
96 }
97
98 void
qof_log_set_level(QofLogModule log_module,QofLogLevel level)99 qof_log_set_level (QofLogModule log_module, QofLogLevel level)
100 {
101 gchar *level_string;
102
103 if (!log_module || level == 0)
104 {
105 return;
106 }
107 level_string = g_strdup (QofLogLevelasString (level));
108 if (!log_table)
109 {
110 log_table = g_hash_table_new (g_str_hash, g_str_equal);
111 }
112 g_hash_table_insert (log_table, (gpointer) log_module, level_string);
113 }
114
115 static void
log_module_foreach(gpointer key,gpointer value,gpointer data)116 log_module_foreach (gpointer key,
117 gpointer value __attribute__ ((unused)), gpointer data)
118 {
119 g_hash_table_insert (log_table, key, data);
120 }
121
122 void
qof_log_set_level_registered(QofLogLevel level)123 qof_log_set_level_registered (QofLogLevel level)
124 {
125 gchar *level_string;
126
127 if (!log_table || level == 0)
128 {
129 return;
130 }
131 level_string = g_strdup (QofLogLevelasString (level));
132 g_hash_table_foreach (log_table, log_module_foreach, level_string);
133 }
134
135 void
qof_log_set_file(FILE * outfile)136 qof_log_set_file (FILE * outfile)
137 {
138 if (!outfile)
139 {
140 fout = stderr;
141 return;
142 }
143 fout = outfile;
144 }
145
146 void
qof_log_init_filename(const gchar * logfilename)147 qof_log_init_filename (const gchar * logfilename)
148 {
149 if (!logfilename)
150 {
151 fout = stderr;
152 }
153 else
154 {
155 filename = g_strdup (logfilename);
156 fout = fopen (filename, "w");
157 }
158 qof_log_init ();
159 }
160
161 void
qof_log_shutdown(void)162 qof_log_shutdown (void)
163 {
164 if (fout && fout != stderr)
165 {
166 fclose (fout);
167 }
168 if (filename)
169 {
170 g_free (filename);
171 }
172 if (function_buffer)
173 {
174 g_free (function_buffer);
175 }
176 g_hash_table_destroy (log_table);
177 }
178
179 const gchar *
qof_log_prettify(const gchar * name)180 qof_log_prettify (const gchar *name)
181 {
182 gchar *p, *buffer;
183 gint length;
184
185 if (!name)
186 {
187 return "";
188 }
189 buffer = g_strndup (name, QOF_LOG_MAX_CHARS - 1);
190 length = strlen (buffer);
191 p = g_strstr_len (buffer, length, "(");
192 if (p)
193 {
194 *(p + 1) = ')';
195 *(p + 2) = 0x0;
196 }
197 else
198 {
199 strcpy (&buffer[QOF_LOG_MAX_CHARS - 4], "...()");
200 }
201 function_buffer = g_strdup (buffer);
202 g_free (buffer);
203 return function_buffer;
204 }
205
206 gboolean
qof_log_check(QofLogModule log_module,QofLogLevel log_level)207 qof_log_check (QofLogModule log_module, QofLogLevel log_level)
208 {
209 gchar *log_string;
210 /* Any positive log_level less than this will be logged. */
211 QofLogLevel maximum;
212
213 log_string = NULL;
214 if (log_level > QOF_LOG_TRACE)
215 log_level = QOF_LOG_TRACE;
216 if (!log_table || log_module == NULL)
217 {
218 return FALSE;
219 }
220 log_string = (gchar *) g_hash_table_lookup (log_table, log_module);
221 /* if log_module not found, do not log. */
222 if (!log_string)
223 {
224 return FALSE;
225 }
226 maximum = QofLogLevelfromString (log_string);
227 if (log_level <= maximum)
228 {
229 return TRUE;
230 }
231 return FALSE;
232 }
233
234 void
qof_log_set_default(QofLogLevel log_level)235 qof_log_set_default (QofLogLevel log_level)
236 {
237 qof_log_set_level (QOF_MOD_BACKEND, log_level);
238 qof_log_set_level (QOF_MOD_CLASS, log_level);
239 qof_log_set_level (QOF_MOD_ENGINE, log_level);
240 qof_log_set_level (QOF_MOD_OBJECT, log_level);
241 qof_log_set_level (QOF_MOD_KVP, log_level);
242 qof_log_set_level (QOF_MOD_MERGE, log_level);
243 qof_log_set_level (QOF_MOD_QUERY, log_level);
244 qof_log_set_level (QOF_MOD_SESSION, log_level);
245 qof_log_set_level (QOF_MOD_CHOICE, log_level);
246 qof_log_set_level (QOF_MOD_UTIL, log_level);
247 qof_log_set_level (QOF_MOD_TIME, log_level);
248 qof_log_set_level (QOF_MOD_DATE, log_level);
249 qof_log_set_level (QOF_MOD_UNDO, log_level);
250 qof_log_set_level (QOF_MOD_ERROR, log_level);
251 qof_log_set_level (QOF_MOD_QSF, log_level);
252 qof_log_set_level (QOF_MOD_SQLITE, log_level);
253 qof_log_set_level (QOF_MOD_GDA, log_level);
254 }
255
256 struct hash_s
257 {
258 QofLogCB cb;
259 gpointer data;
260 };
261
262 static void
hash_cb(gpointer key,gpointer value,gpointer data)263 hash_cb (gpointer key, gpointer value, gpointer data)
264 {
265 struct hash_s *qiter;
266
267 qiter = (struct hash_s *) data;
268 if (!qiter)
269 {
270 return;
271 }
272 (qiter->cb) (key, value, qiter->data);
273 }
274
275 void
qof_log_module_foreach(QofLogCB cb,gpointer data)276 qof_log_module_foreach (QofLogCB cb, gpointer data)
277 {
278 struct hash_s qiter;
279
280 if (!cb)
281 {
282 return;
283 }
284 qiter.cb = cb;
285 qiter.data = data;
286 g_hash_table_foreach (log_table, hash_cb, (gpointer) &qiter);
287 }
288
289 gint
qof_log_module_count(void)290 qof_log_module_count (void)
291 {
292 if (!log_table)
293 {
294 return 0;
295 }
296 return g_hash_table_size (log_table);
297 }
298
299 /* ************************ END OF FILE **************************** */
300