tracker-0.16.2/src/libtracker-common/tracker-log.c

No issues found

  1 /*
  2  * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
  3  *
  4  * This library is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2.1 of the License, or (at your option) any later version.
  8  *
  9  * This library is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.          See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with this library; if not, write to the
 16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 17  * Boston, MA  02110-1301, USA.
 18  */
 19 
 20 #include "config.h"
 21 
 22 #include <sys/time.h>
 23 #include <sys/resource.h>
 24 #include <sys/types.h>
 25 #include <fcntl.h>
 26 #include <stdio.h>
 27 #include <stdlib.h>
 28 #include <string.h>
 29 #include <unistd.h>
 30 #include <errno.h>
 31 
 32 #include <glib/gstdio.h>
 33 
 34 #include "tracker-log.h"
 35 #include "tracker-file-utils.h"
 36 
 37 static gboolean  initialized;
 38 static FILE     *fd;
 39 static gint      verbosity;
 40 static guint     log_handler_id;
 41 static gboolean  use_log_files;
 42 
 43 #if GLIB_CHECK_VERSION (2,31,0)
 44 static GMutex    mutex;
 45 #else
 46 static GMutex   *mutex;
 47 #endif
 48 
 49 static inline void
 50 log_output (const gchar    *domain,
 51             GLogLevelFlags  log_level,
 52             const gchar    *message)
 53 {
 54 	time_t        now;
 55 	gchar         time_str[64];
 56 	gchar        *output;
 57 	struct tm    *local_time;
 58 	const gchar  *log_level_str;
 59 	static gsize  size = 0;
 60 
 61 	g_return_if_fail (initialized == TRUE);
 62 	g_return_if_fail (message != NULL && message[0] != '\0');
 63 
 64 	/* Ensure file logging is thread safe */
 65 #if GLIB_CHECK_VERSION (2,31,0)
 66 	g_mutex_lock (&mutex);
 67 #else
 68 	g_mutex_lock (mutex);
 69 #endif
 70 
 71 	/* Check log size, 10MiB limit */
 72 	if (size > (10 << 20) && fd) {
 73 		rewind (fd);
 74 
 75 		if (ftruncate (fileno (fd), 0) != 0) {
 76 			/* FIXME: What should we do if this fails? */
 77 		}
 78 
 79 		size = 0;
 80 	}
 81 
 82 	now = time ((time_t *) NULL);
 83 	local_time = localtime (&now);
 84 	strftime (time_str, 64, "%d %b %Y, %H:%M:%S:", local_time);
 85 
 86 	switch (log_level) {
 87 	case G_LOG_LEVEL_WARNING:
 88 		log_level_str = "-Warning **";
 89 		break;
 90 
 91 	case G_LOG_LEVEL_CRITICAL:
 92 		log_level_str = "-Critical **";
 93 		break;
 94 
 95 	case G_LOG_LEVEL_ERROR:
 96 		log_level_str = "-Error **";
 97 		break;
 98 	case G_LOG_FLAG_RECURSION:
 99 	case G_LOG_FLAG_FATAL:
100 	case G_LOG_LEVEL_MESSAGE:
101 	case G_LOG_LEVEL_INFO:
102 	case G_LOG_LEVEL_DEBUG:
103 	case G_LOG_LEVEL_MASK:
104 	default:
105 		log_level_str = NULL;
106 		break;
107 	}
108 
109 	output = g_strdup_printf ("%s%s %s%s: %s",
110 	                          log_level_str ? "\n" : "",
111 	                          time_str,
112 	                          domain,
113 	                          log_level_str ? log_level_str : "",
114 	                          message);
115 
116 	if (G_UNLIKELY (fd == NULL)) {
117 		FILE *f;
118 
119 		if (log_level == G_LOG_LEVEL_WARNING ||
120 		    log_level == G_LOG_LEVEL_CRITICAL ||
121 		    log_level == G_LOG_LEVEL_ERROR) {
122 			f = stderr;
123 		} else {
124 			f = stdout;
125 		}
126 
127 		g_fprintf (f, "%s\n", output);
128 		fflush (f);
129 	} else {
130 		size += g_fprintf (fd, "%s\n", output);
131 		fflush (fd);
132 	}
133 
134 	g_free (output);
135 
136 #if GLIB_CHECK_VERSION (2,31,0)
137 	g_mutex_unlock (&mutex);
138 #else
139 	g_mutex_unlock (mutex);
140 #endif
141 }
142 
143 static void
144 tracker_log_handler (const gchar    *domain,
145                      GLogLevelFlags  log_level,
146                      const gchar    *message,
147                      gpointer        user_data)
148 {
149 	/* Unless enabled, we don't log to file by default */
150 	if (use_log_files) {
151 		log_output (domain, log_level, message);
152 	}
153 
154 	/* Now show the message through stdout/stderr as usual */
155 	g_log_default_handler (domain, log_level, message, user_data);
156 }
157 
158 static void
159 hide_log_handler (const gchar    *domain,
160                   GLogLevelFlags  log_level,
161                   const gchar    *message,
162                   gpointer        user_data)
163 {
164 	/* do nothing */
165 }
166 
167 gboolean
168 tracker_log_init (gint    this_verbosity,
169                   gchar **used_filename)
170 {
171 	const gchar *env_use_log_files;
172 	const gchar *env_verbosity;
173 	GLogLevelFlags hide_levels = 0;
174 
175 	if (initialized) {
176 		return TRUE;
177 	}
178 
179 	env_use_log_files = g_getenv ("TRACKER_USE_LOG_FILES");
180 	if (env_use_log_files != NULL) {
181 		/* When set we use:
182 		 *   ~/.local/share/Tracker/
183 		 * Otherwise, we either of the following:
184 		 *   ~/.xsession-errors
185 		 *   ~/.cache/gdm/session.log
186 		 *   systemd journal
187 		 * Depending on the system.
188 		 */
189 		use_log_files = TRUE;
190 	}
191 
192 	env_verbosity = g_getenv ("TRACKER_VERBOSITY");
193 	if (env_verbosity != NULL) {
194 		this_verbosity = atoi (env_verbosity);
195 	} else {
196 		gchar *verbosity_string;
197 
198 		/* make sure libtracker-sparql uses the same verbosity setting */
199 
200 		verbosity_string = g_strdup_printf ("%d", this_verbosity);
201 		g_setenv ("TRACKER_VERBOSITY", verbosity_string, FALSE);
202 		g_free (verbosity_string);
203 	}
204 
205 	/* If we have debug enabled, we imply G_MESSAGES_DEBUG or we
206 	 * see nothing, this came in since GLib 2.32.
207 	 */
208 	if (this_verbosity > 2) {
209 		g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
210 	}
211 
212 	if (use_log_files) {
213 		gchar *basename;
214 		gchar *filename;
215 
216 		basename = g_strdup_printf ("%s.log", g_get_application_name ());
217 		filename = g_build_filename (g_get_user_data_dir (),
218 		                             "tracker",
219 		                             basename,
220 		                             NULL);
221 		g_free (basename);
222 
223 		/* Open file */
224 		fd = g_fopen (filename, "a");
225 		if (!fd) {
226 			const gchar *error_string;
227 
228 			error_string = g_strerror (errno);
229 			g_fprintf (stderr,
230 			           "Could not open log:'%s', %s\n",
231 			           filename,
232 			           error_string);
233 			g_fprintf (stderr,
234 			           "All logging will go to stderr\n");
235 
236 			use_log_files = TRUE;
237 		}
238 
239 		if (used_filename) {
240 			*used_filename = filename;
241 		} else {
242 			g_free (filename);
243 		}
244 	} else {
245 		*used_filename = NULL;
246 	}
247 
248 	verbosity = CLAMP (this_verbosity, 0, 3);
249 
250 #if GLIB_CHECK_VERSION (2,31,0)
251 	g_mutex_init (&mutex);
252 #else
253 	mutex = g_mutex_new ();
254 #endif
255 
256 	switch (this_verbosity) {
257 		/* Log level 3: EVERYTHING */
258 	case 3:
259 		break;
260 
261 		/* Log level 2: CRITICAL/ERROR/WARNING/INFO/MESSAGE only */
262 	case 2:
263 		hide_levels = G_LOG_LEVEL_DEBUG;
264 		break;
265 
266 		/* Log level 1: CRITICAL/ERROR/WARNING/INFO only */
267 	case 1:
268 		hide_levels = G_LOG_LEVEL_DEBUG |
269 		              G_LOG_LEVEL_MESSAGE;
270 		break;
271 
272 		/* Log level 0: CRITICAL/ERROR/WARNING only (default) */
273 	default:
274 	case 0:
275 		hide_levels = G_LOG_LEVEL_DEBUG |
276 		              G_LOG_LEVEL_MESSAGE |
277 		              G_LOG_LEVEL_INFO;
278 		break;
279 	}
280 
281 	if (hide_levels) {
282 		/* Hide log levels according to configuration */
283 		log_handler_id = g_log_set_handler (G_LOG_DOMAIN,
284 			                            hide_levels,
285 			                            hide_log_handler,
286 			                            NULL);
287 	}
288 
289 	/* Set log handler function for the rest */
290 	g_log_set_default_handler (tracker_log_handler, NULL);
291 
292 	initialized = TRUE;
293 
294 	/* log binary name and version */
295 	g_message ("Starting %s %s", g_get_application_name (), PACKAGE_VERSION);
296 
297 	return TRUE;
298 }
299 
300 void
301 tracker_log_shutdown (void)
302 {
303 	if (!initialized) {
304 		return;
305 	}
306 
307 	g_message ("Stopping %s %s", g_get_application_name (), PACKAGE_VERSION);
308 
309 	/* Reset default log handler */
310 	g_log_set_default_handler (g_log_default_handler, NULL);
311 
312 	if (log_handler_id) {
313 		g_log_remove_handler (G_LOG_DOMAIN, log_handler_id);
314 		log_handler_id = 0;
315 	}
316 
317 	if (use_log_files && fd != NULL) {
318 		fclose (fd);
319 	}
320 
321 #if GLIB_CHECK_VERSION (2,31,0)
322 	g_mutex_clear (&mutex);
323 #else
324 	g_mutex_free (mutex);
325 #endif
326 
327 	initialized = FALSE;
328 }