Changeset ec36247


Ignore:
Timestamp:
Aug 5, 2017, 11:21:53 PM (7 years ago)
Author:
Jason Gross <jasongross9@gmail.com>
Branches:
master
Children:
77beb3c
Parents:
e47e1b0
git-author:
Jason Gross <jgross@mit.edu> (09/09/12 20:44:13)
git-committer:
Jason Gross <jasongross9@gmail.com> (08/05/17 23:21:53)
Message:
Defer failed log messages

Previously, when we failed to open a logging file, we errored, and
dropped the log message.  This commit makes it so that, if the reason we
failed was a permissions error, we instead add the log entry to a queue
of messages to be logged eventually, and inform the user that logging
has been suspended.  The user must run :flush-logs to resume logging.

If :flush-log has an fopen that fails with EPERM or EACCES, we re-defer
messages and inform the user.

On shutdown, BarnOwl will attempt to log all messages currently in the
queue one last time.
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • commands.c

    r41677d2 rec36247  
    487487              "\n"
    488488              "SEE ALSO: aaway, zaway"),
     489
     490  OWLCMD_VOID("flush-logs", owl_command_flushlogs, OWL_CTX_ANY,
     491              "flush the queue of messages waiting to be logged",
     492              "",
     493              "If BarnOwl failed to log a file, this command tells\n"
     494              "BarnOwl to try logging the messages that have since\n"
     495              "come in, and to resume logging normally."),
    489496
    490497  OWLCMD_ARGS("load-subs", owl_command_loadsubs, OWL_CTX_ANY,
     
    14351442{
    14361443  owl_function_unsuball();
     1444}
     1445
     1446void owl_command_flushlogs(void)
     1447{
     1448  owl_log_flush_logs();
    14371449}
    14381450
  • logging.c

    re47e1b0 rec36247  
    1111static GMainLoop *log_loop;
    1212static GThread *logging_thread;
     13bool defer_logs;
     14static GQueue *deferred_entry_queue;
    1315
    1416/* This is now the one function that should be called to log a
     
    164166}
    165167
    166 static void owl_log_write_entry(gpointer data)
    167 {
    168   owl_log_entry *msg = (owl_log_entry*)data;
     168static CALLER_OWN owl_log_entry *owl_log_new_entry(const char *buffer, const char *filename)
     169{
     170  owl_log_entry *log_msg = g_slice_new(owl_log_entry);
     171  log_msg->message = g_strdup(buffer);
     172  log_msg->filename = g_strdup(filename);
     173  return log_msg;
     174}
     175
     176static void owl_log_deferred_enqueue_message(const char *buffer, const char *filename)
     177{
     178  g_queue_push_tail(deferred_entry_queue, owl_log_new_entry(buffer, filename));
     179}
     180
     181/* write out the entry if possible
     182 * return 0 on success, errno on failure to open
     183 */
     184static int owl_log_try_write_entry(owl_log_entry *msg)
     185{
    169186  FILE *file = NULL;
    170187  file = fopen(msg->filename, "a");
    171188  if (!file) {
    172     owl_log_error("Unable to open file for logging (%s)", msg->filename);
    173     return;
     189    return errno;
    174190  }
    175191  fprintf(file, "%s", msg->message);
    176192  fclose(file);
     193  return 0;
    177194}
    178195
     
    187204}
    188205
     206#if GLIB_CHECK_VERSION(2, 32, 0)
     207#else
     208static void owl_log_entry_free_gfunc(gpointer data, gpointer user_data)
     209{
     210  owl_log_entry_free(data);
     211}
     212#endif
     213
     214/* If we are deferring log messages, enqueue this entry for writing.
     215 * Otherwise, try to write this log message, and, if it fails with
     216 * EPERM or EACCES, go into deferred logging mode and queue an admin
     217 * message.  If it fails with anything else, display an error message,
     218 * but do not go into deferred logging mode. */
     219static void owl_log_eventually_write_entry(gpointer data)
     220{
     221  int ret;
     222  owl_log_entry *msg = (owl_log_entry*)data;
     223  if (defer_logs) {
     224    owl_log_deferred_enqueue_message(msg->message, msg->filename);
     225  } else {
     226    ret = owl_log_try_write_entry(msg);
     227    if (ret == EPERM || ret == EACCES) {
     228      defer_logs = true;
     229      owl_log_error("Unable to open file for logging (%s): \n"
     230                    "%s.  \n"
     231                    "Consider renewing your tickets.  Logging has been \n"
     232                    "suspended, and your messages will be saved.  To \n"
     233                    "resume logging, use the command :flush-logs.\n\n",
     234                    msg->filename,
     235                    g_strerror(ret));
     236      owl_log_deferred_enqueue_message(msg->message, msg->filename);
     237    } else if (ret != 0) {
     238      owl_log_error("Unable to open file for logging: %s (file %s)",
     239                    g_strerror(ret),
     240                    msg->filename);
     241    }
     242  }
     243}
     244
     245/* tries to write the deferred log entries */
     246static void owl_log_write_deferred_entries(gpointer data)
     247{
     248  owl_log_entry *entry;
     249
     250  defer_logs = false;
     251  while (!g_queue_is_empty(deferred_entry_queue) && !defer_logs) {
     252    entry = (owl_log_entry*)g_queue_pop_head(deferred_entry_queue);
     253    owl_log_eventually_write_entry(entry);
     254    owl_log_entry_free(entry);
     255  }
     256}
     257
     258void owl_log_flush_logs(void)
     259{
     260  owl_select_post_task(owl_log_write_deferred_entries, NULL, NULL, log_context);
     261}
     262
    189263void owl_log_enqueue_message(const char *buffer, const char *filename)
    190264{
    191   owl_log_entry *log_msg = NULL;
    192   log_msg = g_slice_new(owl_log_entry);
    193   log_msg->message = g_strdup(buffer);
    194   log_msg->filename = g_strdup(filename);
    195   owl_select_post_task(owl_log_write_entry, log_msg,
     265  owl_log_entry *log_msg = owl_log_new_entry(buffer, filename);
     266  owl_select_post_task(owl_log_eventually_write_entry, log_msg,
    196267                       owl_log_entry_free, log_context);
    197268}
     
    435506static gpointer owl_log_thread_func(gpointer data)
    436507{
     508  log_context = g_main_context_new();
    437509  log_loop = g_main_loop_new(log_context, FALSE);
    438510  g_main_loop_run(log_loop);
     
    440512}
    441513
    442 void owl_log_init(void) 
     514void owl_log_init(void)
    443515{
    444516  log_context = g_main_context_new();
     
    460532  }
    461533#endif
    462  
     534
     535  deferred_entry_queue = g_queue_new();
    463536}
    464537
    465538static void owl_log_quit_func(gpointer data)
    466539{
     540  /* flush the deferred logs queue, trying to write the
     541   * entries to the disk one last time */
     542  owl_log_write_deferred_entries(NULL);
     543#if GLIB_CHECK_VERSION(2, 32, 0)
     544  g_queue_free_full(deferred_entry_queue, owl_log_entry_free);
     545#else
     546  g_queue_foreach(deferred_entry_queue, owl_log_entry_free_gfunc, NULL);
     547  g_queue_free(deferred_entry_queue);
     548#endif
     549
    467550  g_main_loop_quit(log_loop);
    468551}
Note: See TracChangeset for help on using the changeset viewer.