mirror of
https://gitlab.gnome.org/GNOME/nautilus
synced 2024-09-12 20:41:34 +00:00
Use the write-to-a-pipe trick from the signal handler instead of queueing
2006-11-23 Federico Mena Quintero <federico@novell.com> Use the write-to-a-pipe trick from the signal handler instead of queueing an idle handler from there. * src/nautilus-main.c (setup_debug_log_signals): Set up a pair of pipes for the SIGUSR1 handler; set up a GIOChannel on them. (sigusr1_handler): Write a byte to our pipe instead of queueing an idle handler. (debug_log_io_cb): Replaces dump_debug_log_idle_cb(). Read from the pipe, and dump the debug log. Add a configuration file for the logging mechanism. You create ~/nautilus-debug-log.conf as a GKeyFile. * libnautilus-private/nautilus-debug-log.c (nautilus_debug_log_load_configuration): New function; loads the configuration from a key file like this: [debug log] enable domains = foo; bar; baz max lines = 1000 * libnautilus-private/nautilus-debug-log.c (dump_configuration): New utility function. (nautilus_debug_log_dump): At the end of the log, dump the configuration used for the debug log so that the user can re-create it later. * libnautilus-private/nautilus-debug-log.h: New prototype for nautilus_debug_log_load_configuration(). * src/nautilus-main.c (setup_debug_log): Load the debug log's configuration from ~/nautilus-debug-log.conf (setup_debug_log_domains): Removed. * src/nautilus-main.c (log_override_cb): If the log level of the message is G_LOG_LEVEL_DEBUG, don't log it as a milestone. We'll use this log level for miscellaneous debugging messages from gnome-vfs. Also, don't send G_LOG_LEVEL_DEBUG messages to the default log handler, to avoid a huge ~/.xsession-errors. (setup_debug_log_domains): Enable logging for NAUTILUS_DEBUG_LOG_DOMAIN_GLOG.
This commit is contained in:
parent
8ffdd1423d
commit
3b44116754
44
ChangeLog
44
ChangeLog
|
@ -1,3 +1,47 @@
|
|||
2006-11-23 Federico Mena Quintero <federico@novell.com>
|
||||
|
||||
Use the write-to-a-pipe trick from the signal handler instead of
|
||||
queueing an idle handler from there.
|
||||
|
||||
* src/nautilus-main.c (setup_debug_log_signals): Set up a pair of
|
||||
pipes for the SIGUSR1 handler; set up a GIOChannel on them.
|
||||
(sigusr1_handler): Write a byte to our pipe instead of queueing an
|
||||
idle handler.
|
||||
(debug_log_io_cb): Replaces dump_debug_log_idle_cb(). Read from
|
||||
the pipe, and dump the debug log.
|
||||
|
||||
Add a configuration file for the logging mechanism. You create
|
||||
~/nautilus-debug-log.conf as a GKeyFile.
|
||||
|
||||
* libnautilus-private/nautilus-debug-log.c
|
||||
(nautilus_debug_log_load_configuration): New function; loads the
|
||||
configuration from a key file like this:
|
||||
|
||||
[debug log]
|
||||
enable domains = foo; bar; baz
|
||||
max lines = 1000
|
||||
|
||||
* libnautilus-private/nautilus-debug-log.c (dump_configuration):
|
||||
New utility function.
|
||||
(nautilus_debug_log_dump): At the end of the log, dump the
|
||||
configuration used for the debug log so that the user can
|
||||
re-create it later.
|
||||
|
||||
* libnautilus-private/nautilus-debug-log.h: New prototype for
|
||||
nautilus_debug_log_load_configuration().
|
||||
|
||||
* src/nautilus-main.c (setup_debug_log): Load the debug log's
|
||||
configuration from ~/nautilus-debug-log.conf
|
||||
(setup_debug_log_domains): Removed.
|
||||
|
||||
* src/nautilus-main.c (log_override_cb): If the log level of the
|
||||
message is G_LOG_LEVEL_DEBUG, don't log it as a milestone. We'll
|
||||
use this log level for miscellaneous debugging messages from
|
||||
gnome-vfs. Also, don't send G_LOG_LEVEL_DEBUG messages to the
|
||||
default log handler, to avoid a huge ~/.xsession-errors.
|
||||
(setup_debug_log_domains): Enable logging for
|
||||
NAUTILUS_DEBUG_LOG_DOMAIN_GLOG.
|
||||
|
||||
2006-11-23 Christian Persch <chpe@cvs.gnome.org>
|
||||
|
||||
* src/nautilus-search-bar.c: (nautilus_search_bar_init):
|
||||
|
|
637
libnautilus-private/nautilus-debug-log.c
Normal file
637
libnautilus-private/nautilus-debug-log.c
Normal file
|
@ -0,0 +1,637 @@
|
|||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
|
||||
|
||||
nautilus-debug-log.c: Ring buffer for logging debug messages
|
||||
|
||||
Copyright (C) 2006 Novell, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
Author: Federico Mena-Quintero <federico@novell.com>
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <eel/eel-glib-extensions.h>
|
||||
#include "nautilus-debug-log.h"
|
||||
#include "nautilus-file.h"
|
||||
|
||||
#define DEFAULT_RING_BUFFER_NUM_LINES 30000
|
||||
|
||||
#define KEY_FILE_GROUP "debug log"
|
||||
#define KEY_FILE_DOMAINS_KEY "enable domains"
|
||||
#define KEY_FILE_MAX_LINES_KEY "max lines"
|
||||
|
||||
static GStaticMutex log_mutex = G_STATIC_MUTEX_INIT;
|
||||
|
||||
static GHashTable *domains_hash;
|
||||
static char **ring_buffer;
|
||||
static int ring_buffer_next_index;
|
||||
static int ring_buffer_num_lines;
|
||||
static int ring_buffer_max_lines = DEFAULT_RING_BUFFER_NUM_LINES;
|
||||
|
||||
static void
|
||||
lock (void)
|
||||
{
|
||||
g_static_mutex_lock (&log_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
unlock (void)
|
||||
{
|
||||
g_static_mutex_unlock (&log_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
nautilus_debug_log (gboolean is_milestone, const char *domain, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
nautilus_debug_logv (is_milestone, domain, NULL, format, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_domain_enabled (const char *domain)
|
||||
{
|
||||
/* User actions are always logged */
|
||||
if (strcmp (domain, NAUTILUS_DEBUG_LOG_DOMAIN_USER) == 0)
|
||||
return TRUE;
|
||||
|
||||
if (!domains_hash)
|
||||
return FALSE;
|
||||
|
||||
return (g_hash_table_lookup (domains_hash, domain) != NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_ring (void)
|
||||
{
|
||||
if (ring_buffer)
|
||||
return;
|
||||
|
||||
ring_buffer = g_new0 (char *, ring_buffer_max_lines);
|
||||
ring_buffer_next_index = 0;
|
||||
ring_buffer_num_lines = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
add_to_ring (char *str)
|
||||
{
|
||||
ensure_ring ();
|
||||
|
||||
g_assert (str != NULL);
|
||||
|
||||
if (ring_buffer_num_lines == ring_buffer_max_lines) {
|
||||
/* We have an overlap, and the ring_buffer_next_index points to
|
||||
* the "first" item. Free it to make room for the new item.
|
||||
*/
|
||||
|
||||
g_assert (ring_buffer[ring_buffer_next_index] != NULL);
|
||||
g_free (ring_buffer[ring_buffer_next_index]);
|
||||
} else
|
||||
ring_buffer_num_lines++;
|
||||
|
||||
g_assert (ring_buffer_num_lines <= ring_buffer_max_lines);
|
||||
|
||||
ring_buffer[ring_buffer_next_index] = str;
|
||||
|
||||
ring_buffer_next_index++;
|
||||
if (ring_buffer_next_index == ring_buffer_max_lines) {
|
||||
ring_buffer_next_index = 0;
|
||||
g_assert (ring_buffer_num_lines == ring_buffer_max_lines);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nautilus_debug_logv (gboolean is_milestone, const char *domain, const GList *uris, const char *format, va_list args)
|
||||
{
|
||||
char *str;
|
||||
char *debug_str;
|
||||
struct timeval tv;
|
||||
struct tm tm;
|
||||
|
||||
lock ();
|
||||
|
||||
if (!(is_milestone || is_domain_enabled (domain)))
|
||||
goto out;
|
||||
|
||||
str = g_strdup_vprintf (format, args);
|
||||
gettimeofday (&tv, NULL);
|
||||
|
||||
tm = *localtime (&tv.tv_sec);
|
||||
|
||||
debug_str = g_strdup_printf ("%p %04d/%02d/%02d %02d:%02d:%02d.%04d (%s): %s",
|
||||
g_thread_self (),
|
||||
tm.tm_year + 1900,
|
||||
tm.tm_mon + 1,
|
||||
tm.tm_mday,
|
||||
tm.tm_hour,
|
||||
tm.tm_min,
|
||||
tm.tm_sec,
|
||||
(int) (tv.tv_usec / 100),
|
||||
domain,
|
||||
str);
|
||||
g_free (str);
|
||||
|
||||
if (uris) {
|
||||
int debug_str_len;
|
||||
int uris_len;
|
||||
const GList *l;
|
||||
char *new_str;
|
||||
char *p;
|
||||
|
||||
uris_len = 0;
|
||||
|
||||
for (l = uris; l; l = l->next) {
|
||||
const char *uri;
|
||||
|
||||
uri = l->data;
|
||||
uris_len += strlen (uri) + 2; /* plus 2 for a tab and the newline */
|
||||
}
|
||||
|
||||
debug_str_len = strlen (debug_str);
|
||||
new_str = g_new (char, debug_str_len + 1 + uris_len); /* plus 1 for newline */
|
||||
|
||||
p = g_stpcpy (new_str, debug_str);
|
||||
*p++ = '\n';
|
||||
|
||||
for (l = uris; l; l = l->next) {
|
||||
const char *uri;
|
||||
|
||||
uri = l->data;
|
||||
|
||||
*p++ = '\t';
|
||||
|
||||
p = g_stpcpy (p, uri);
|
||||
|
||||
if (l->next)
|
||||
*p++ = '\n';
|
||||
}
|
||||
|
||||
g_free (debug_str);
|
||||
debug_str = new_str;
|
||||
}
|
||||
|
||||
add_to_ring (debug_str);
|
||||
|
||||
/* FIXME: deal with milestones */
|
||||
|
||||
out:
|
||||
unlock ();
|
||||
}
|
||||
|
||||
void
|
||||
nautilus_debug_log_with_uri_list (gboolean is_milestone, const char *domain, const GList *uris,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
nautilus_debug_logv (is_milestone, domain, uris, format, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
void
|
||||
nautilus_debug_log_with_file_list (gboolean is_milestone, const char *domain, GList *files,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
GList *uris;
|
||||
GList *l;
|
||||
|
||||
uris = NULL;
|
||||
|
||||
for (l = files; l; l = l->next) {
|
||||
NautilusFile *file;
|
||||
char *uri;
|
||||
|
||||
file = NAUTILUS_FILE (l->data);
|
||||
uri = nautilus_file_get_uri (file);
|
||||
|
||||
if (nautilus_file_is_gone (file)) {
|
||||
char *new_uri;
|
||||
|
||||
/* Hack: this will create an invalid URI, but it's for
|
||||
* display purposes only.
|
||||
*/
|
||||
new_uri = g_strconcat (uri ? uri : "", " (gone)", NULL);
|
||||
g_free (uri);
|
||||
uri = new_uri;
|
||||
}
|
||||
uris = g_list_prepend (uris, uri);
|
||||
}
|
||||
|
||||
uris = g_list_reverse (uris);
|
||||
|
||||
va_start (args, format);
|
||||
nautilus_debug_logv (is_milestone, domain, uris, format, args);
|
||||
va_end (args);
|
||||
|
||||
eel_g_list_free_deep (uris);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nautilus_debug_log_load_configuration (const char *filename, GError **error)
|
||||
{
|
||||
GKeyFile *key_file;
|
||||
char **strings;
|
||||
gsize num_strings;
|
||||
int num;
|
||||
GError *my_error;
|
||||
|
||||
g_assert (filename != NULL);
|
||||
g_assert (error == NULL || *error == NULL);
|
||||
|
||||
key_file = g_key_file_new ();
|
||||
|
||||
if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, error)) {
|
||||
g_key_file_free (key_file);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Domains */
|
||||
|
||||
my_error = NULL;
|
||||
strings = g_key_file_get_string_list (key_file, KEY_FILE_GROUP, KEY_FILE_DOMAINS_KEY, &num_strings, &my_error);
|
||||
if (my_error)
|
||||
g_error_free (my_error);
|
||||
else {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_strings; i++)
|
||||
strings[i] = g_strstrip (strings[i]);
|
||||
|
||||
nautilus_debug_log_enable_domains ((const char **) strings, num_strings);
|
||||
g_strfreev (strings);
|
||||
}
|
||||
|
||||
/* Number of lines */
|
||||
|
||||
my_error = NULL;
|
||||
num = g_key_file_get_integer (key_file, KEY_FILE_GROUP, KEY_FILE_MAX_LINES_KEY, &my_error);
|
||||
if (my_error)
|
||||
g_error_free (my_error);
|
||||
else
|
||||
nautilus_debug_log_set_max_lines (num);
|
||||
|
||||
g_key_file_free (key_file);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nautilus_debug_log_enable_domains (const char **domains, int n_domains)
|
||||
{
|
||||
int i;
|
||||
|
||||
g_assert (domains != NULL);
|
||||
g_assert (n_domains >= 0);
|
||||
|
||||
lock ();
|
||||
|
||||
if (!domains_hash)
|
||||
domains_hash = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
for (i = 0; i < n_domains; i++) {
|
||||
g_assert (domains[i] != NULL);
|
||||
|
||||
if (strcmp (domains[i], NAUTILUS_DEBUG_LOG_DOMAIN_USER) == 0)
|
||||
continue; /* user actions are always enabled */
|
||||
|
||||
if (g_hash_table_lookup (domains_hash, domains[i]) == NULL) {
|
||||
char *domain;
|
||||
|
||||
domain = g_strdup (domains[i]);
|
||||
g_hash_table_insert (domains_hash, domain, domain);
|
||||
}
|
||||
}
|
||||
|
||||
unlock ();
|
||||
}
|
||||
|
||||
void
|
||||
nautilus_debug_log_disable_domains (const char **domains, int n_domains)
|
||||
{
|
||||
int i;
|
||||
|
||||
g_assert (domains != NULL);
|
||||
g_assert (n_domains >= 0);
|
||||
|
||||
lock ();
|
||||
|
||||
if (domains_hash) {
|
||||
for (i = 0; i < n_domains; i++) {
|
||||
char *domain;
|
||||
|
||||
g_assert (domains[i] != NULL);
|
||||
|
||||
if (strcmp (domains[i], NAUTILUS_DEBUG_LOG_DOMAIN_USER) == 0)
|
||||
continue; /* user actions are always enabled */
|
||||
|
||||
domain = g_hash_table_lookup (domains_hash, domains[i]);
|
||||
if (domain) {
|
||||
g_hash_table_remove (domains_hash, domain);
|
||||
g_free (domain);
|
||||
}
|
||||
}
|
||||
} /* else, there is nothing to disable */
|
||||
|
||||
unlock ();
|
||||
}
|
||||
|
||||
gboolean
|
||||
nautilus_debug_log_is_domain_enabled (const char *domain)
|
||||
{
|
||||
gboolean retval;
|
||||
|
||||
g_assert (domain != NULL);
|
||||
|
||||
lock ();
|
||||
retval = is_domain_enabled (domain);
|
||||
unlock ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct domains_dump_closure {
|
||||
char **domains;
|
||||
int num_domains;
|
||||
};
|
||||
|
||||
static void
|
||||
domains_foreach_dump_cb (gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
struct domains_dump_closure *closure;
|
||||
char *domain;
|
||||
|
||||
closure = data;
|
||||
domain = key;
|
||||
|
||||
closure->domains[closure->num_domains] = domain;
|
||||
closure->num_domains++;
|
||||
}
|
||||
|
||||
static GKeyFile *
|
||||
make_key_file_from_configuration (void)
|
||||
{
|
||||
GKeyFile *key_file;
|
||||
struct domains_dump_closure closure;
|
||||
int num_domains;
|
||||
|
||||
key_file = g_key_file_new ();
|
||||
|
||||
/* domains */
|
||||
|
||||
if (domains_hash) {
|
||||
num_domains = g_hash_table_size (domains_hash);
|
||||
|
||||
closure.domains = g_new (char *, num_domains);
|
||||
closure.num_domains = 0;
|
||||
|
||||
g_hash_table_foreach (domains_hash, domains_foreach_dump_cb, &closure);
|
||||
g_assert (num_domains == closure.num_domains);
|
||||
|
||||
g_key_file_set_string_list (key_file, KEY_FILE_GROUP, KEY_FILE_DOMAINS_KEY,
|
||||
(const gchar * const *) closure.domains, closure.num_domains);
|
||||
g_free (closure.domains);
|
||||
}
|
||||
|
||||
/* max lines */
|
||||
|
||||
g_key_file_set_integer (key_file, KEY_FILE_GROUP, KEY_FILE_MAX_LINES_KEY, ring_buffer_max_lines);
|
||||
|
||||
return key_file;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dump_configuration (const char *filename, FILE *file, GError **error)
|
||||
{
|
||||
GKeyFile *key_file;
|
||||
char *data;
|
||||
gsize length;
|
||||
gboolean success;
|
||||
|
||||
success = FALSE;
|
||||
|
||||
key_file = make_key_file_from_configuration ();
|
||||
|
||||
data = g_key_file_to_data (key_file, &length, error);
|
||||
if (!data)
|
||||
goto out;
|
||||
|
||||
if (fputs (data, file) == EOF) {
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR,
|
||||
g_file_error_from_errno (saved_errno),
|
||||
"error when writing to log file %s", filename);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
out:
|
||||
g_key_file_free (key_file);
|
||||
return success;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nautilus_debug_log_dump (const char *filename, GError **error)
|
||||
{
|
||||
FILE *file;
|
||||
gboolean success;
|
||||
int start_index;
|
||||
int i;
|
||||
|
||||
g_assert (error == NULL || *error == NULL);
|
||||
|
||||
lock ();
|
||||
|
||||
success = FALSE;
|
||||
|
||||
file = fopen (filename, "w");
|
||||
if (!file) {
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR,
|
||||
g_file_error_from_errno (saved_errno),
|
||||
"could not open log file %s", filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ring_buffer_num_lines == ring_buffer_max_lines)
|
||||
start_index = ring_buffer_next_index;
|
||||
else
|
||||
start_index = 0;
|
||||
|
||||
for (i = 0; i < ring_buffer_num_lines; i++) {
|
||||
int idx;
|
||||
|
||||
idx = (start_index + i) % ring_buffer_max_lines;
|
||||
|
||||
if (fputs (ring_buffer[idx], file) == EOF
|
||||
|| fputc ('\n', file) == EOF) {
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR,
|
||||
g_file_error_from_errno (saved_errno),
|
||||
"error when writing to log file %s", filename);
|
||||
|
||||
goto do_close;
|
||||
}
|
||||
}
|
||||
|
||||
if (fputs ("\n\n"
|
||||
"This configuration for the debug log can be re-created\n"
|
||||
"by putting the following in ~/nautilus-debug-log.conf\n"
|
||||
"(use ';' to separate domain names):\n\n",
|
||||
file) == EOF) {
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR,
|
||||
g_file_error_from_errno (saved_errno),
|
||||
"error when writing to log file %s", filename);
|
||||
|
||||
goto do_close;
|
||||
}
|
||||
|
||||
if (!dump_configuration (filename, file, error))
|
||||
goto do_close;
|
||||
|
||||
success = TRUE;
|
||||
|
||||
do_close:
|
||||
|
||||
if (fclose (file) != 0) {
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
|
||||
if (error && *error) {
|
||||
g_error_free (*error);
|
||||
*error = NULL;
|
||||
}
|
||||
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR,
|
||||
g_file_error_from_errno (saved_errno),
|
||||
"error when closing log file %s", filename);
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
unlock ();
|
||||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
nautilus_debug_log_set_max_lines (int num_lines)
|
||||
{
|
||||
char **new_buffer;
|
||||
int lines_to_copy;
|
||||
|
||||
g_assert (num_lines > 0);
|
||||
|
||||
lock ();
|
||||
|
||||
if (num_lines == ring_buffer_max_lines)
|
||||
goto out;
|
||||
|
||||
new_buffer = g_new0 (char *, num_lines);
|
||||
|
||||
lines_to_copy = MIN (num_lines, ring_buffer_num_lines);
|
||||
|
||||
if (ring_buffer) {
|
||||
int start_index;
|
||||
int i;
|
||||
|
||||
if (ring_buffer_num_lines == ring_buffer_max_lines)
|
||||
start_index = (ring_buffer_next_index + ring_buffer_max_lines - lines_to_copy) % ring_buffer_max_lines;
|
||||
else
|
||||
start_index = ring_buffer_num_lines - lines_to_copy;
|
||||
|
||||
g_assert (start_index >= 0 && start_index < ring_buffer_max_lines);
|
||||
|
||||
for (i = 0; i < lines_to_copy; i++) {
|
||||
int idx;
|
||||
|
||||
idx = (start_index + i) % ring_buffer_max_lines;
|
||||
|
||||
new_buffer[i] = ring_buffer[idx];
|
||||
ring_buffer[idx] = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ring_buffer_max_lines; i++)
|
||||
g_free (ring_buffer[i]);
|
||||
|
||||
g_free (ring_buffer);
|
||||
}
|
||||
|
||||
ring_buffer = new_buffer;
|
||||
ring_buffer_next_index = lines_to_copy;
|
||||
ring_buffer_num_lines = lines_to_copy;
|
||||
ring_buffer_max_lines = num_lines;
|
||||
|
||||
out:
|
||||
|
||||
unlock ();
|
||||
}
|
||||
|
||||
int
|
||||
nautilus_debug_log_get_max_lines (void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
lock ();
|
||||
retval = ring_buffer_max_lines;
|
||||
unlock ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
nautilus_debug_log_clear (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
lock ();
|
||||
|
||||
if (!ring_buffer)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < ring_buffer_max_lines; i++) {
|
||||
g_free (ring_buffer[i]);
|
||||
ring_buffer[i] = NULL;
|
||||
}
|
||||
|
||||
ring_buffer_next_index = 0;
|
||||
ring_buffer_num_lines = 0;
|
||||
|
||||
out:
|
||||
unlock ();
|
||||
}
|
58
libnautilus-private/nautilus-debug-log.h
Normal file
58
libnautilus-private/nautilus-debug-log.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
|
||||
|
||||
nautilus-debug-log.h: Ring buffer for logging debug messages
|
||||
|
||||
Copyright (C) 2006 Novell, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
Author: Federico Mena-Quintero <federico@novell.com>
|
||||
*/
|
||||
|
||||
#ifndef NAUTILUS_DEBUG_LOG_H
|
||||
#define NAUTILUS_DEBUG_LOG_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define NAUTILUS_DEBUG_LOG_DOMAIN_USER "USER" /* always enabled */
|
||||
#define NAUTILUS_DEBUG_LOG_DOMAIN_ASYNC "async" /* when asynchronous notifications come in */
|
||||
#define NAUTILUS_DEBUG_LOG_DOMAIN_GLOG "GLog" /* used for GLog messages; don't use it yourself */
|
||||
|
||||
void nautilus_debug_log (gboolean is_milestone, const char *domain, const char *format, ...);
|
||||
|
||||
void nautilus_debug_log_with_uri_list (gboolean is_milestone, const char *domain, const GList *uris,
|
||||
const char *format, ...);
|
||||
void nautilus_debug_log_with_file_list (gboolean is_milestone, const char *domain, GList *files,
|
||||
const char *format, ...);
|
||||
|
||||
void nautilus_debug_logv (gboolean is_milestone, const char *domain, const GList *uris, const char *format, va_list args);
|
||||
|
||||
gboolean nautilus_debug_log_load_configuration (const char *filename, GError **error);
|
||||
|
||||
void nautilus_debug_log_enable_domains (const char **domains, int n_domains);
|
||||
void nautilus_debug_log_disable_domains (const char **domains, int n_domains);
|
||||
|
||||
gboolean nautilus_debug_log_is_domain_enabled (const char *domain);
|
||||
|
||||
gboolean nautilus_debug_log_dump (const char *filename, GError **error);
|
||||
|
||||
void nautilus_debug_log_set_max_lines (int num_lines);
|
||||
int nautilus_debug_log_get_max_lines (void);
|
||||
|
||||
/* For testing only */
|
||||
void nautilus_debug_log_clear (void);
|
||||
|
||||
#endif /* NAUTILUS_DEBUG_LOG_H */
|
|
@ -210,9 +210,16 @@ dump_debug_log (void)
|
|||
g_free (filename);
|
||||
}
|
||||
|
||||
static int debug_log_pipes[2];
|
||||
|
||||
static gboolean
|
||||
dump_debug_log_idle_cb (gpointer data)
|
||||
debug_log_io_cb (GIOChannel *io, GIOCondition condition, gpointer data)
|
||||
{
|
||||
char a;
|
||||
|
||||
while (read (debug_log_pipes[0], &a, 1) != 1)
|
||||
;
|
||||
|
||||
nautilus_debug_log (TRUE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
|
||||
"user requested dump of debug log");
|
||||
|
||||
|
@ -230,7 +237,8 @@ static struct sigaction old_bus_sa;
|
|||
static void
|
||||
sigusr1_handler (int sig)
|
||||
{
|
||||
g_idle_add (dump_debug_log_idle_cb, NULL);
|
||||
while (write (debug_log_pipes[1], "a", 1) != 1)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -280,6 +288,13 @@ static void
|
|||
setup_debug_log_signals (void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
GIOChannel *io;
|
||||
|
||||
if (pipe (debug_log_pipes) == -1)
|
||||
g_error ("Could not create pipe() for debug log");
|
||||
|
||||
io = g_io_channel_unix_new (debug_log_pipes[0]);
|
||||
g_io_add_watch (io, G_IO_IN, debug_log_io_cb, NULL);
|
||||
|
||||
sa.sa_handler = sigusr1_handler;
|
||||
sigemptyset (&sa.sa_mask);
|
||||
|
@ -297,16 +312,6 @@ setup_debug_log_signals (void)
|
|||
sigaction(SIGBUS, &sa, &old_bus_sa);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_debug_log_domains (void)
|
||||
{
|
||||
const char *domains[] = {
|
||||
NAUTILUS_DEBUG_LOG_DOMAIN_ASYNC
|
||||
};
|
||||
|
||||
nautilus_debug_log_enable_domains (domains, G_N_ELEMENTS (domains));
|
||||
}
|
||||
|
||||
static GLogFunc default_log_handler;
|
||||
|
||||
static void
|
||||
|
@ -315,9 +320,16 @@ log_override_cb (const gchar *log_domain,
|
|||
const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
nautilus_debug_log (TRUE, NAUTILUS_DEBUG_LOG_DOMAIN_GLOG, "%s", message);
|
||||
gboolean is_debug;
|
||||
gboolean is_milestone;
|
||||
|
||||
(* default_log_handler) (log_domain, log_level, message, user_data);
|
||||
is_debug = ((log_level & G_LOG_LEVEL_DEBUG) != 0);
|
||||
is_milestone = !is_debug;
|
||||
|
||||
nautilus_debug_log (is_milestone, NAUTILUS_DEBUG_LOG_DOMAIN_GLOG, "%s", message);
|
||||
|
||||
if (!is_debug)
|
||||
(* default_log_handler) (log_domain, log_level, message, user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -329,7 +341,12 @@ setup_debug_log_glog (void)
|
|||
static void
|
||||
setup_debug_log (void)
|
||||
{
|
||||
setup_debug_log_domains ();
|
||||
char *config_filename;
|
||||
|
||||
config_filename = g_build_filename (g_get_home_dir (), "nautilus-debug-log.conf", NULL);
|
||||
nautilus_debug_log_load_configuration (config_filename, NULL); /* NULL GError */
|
||||
g_free (config_filename);
|
||||
|
||||
setup_debug_log_signals ();
|
||||
setup_debug_log_glog ();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue