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