[PATCH 1/4] Initial implementation of low level logging routines.
david at tethera.net
david at tethera.net
Sun Oct 24 14:01:03 PDT 2010
From: David Bremner <bremner at unb.ca>
notmuch_log_open: open a log file; return an opaque "log descriptor"
notmuch_log_words: log words, escaping spaces and newlines, and appending a newline.
Log format is space delimited, and line oriented. Escaping log text
is currently based on a slightly simplified version of
json_quote_chararray in ../json.c. This is probably overkill.
notmuch_log_transaction_(start|finish): log a transaction identifier
and depth.
Nested transactions are supported, so that this aligns with
notmuch_message_(freeze|thaw). The are not too well tested though,
since I don't know when they arise.
---
lib/Makefile.local | 1 +
lib/log-private.h | 13 +++
lib/log.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/notmuch.h | 23 ++++
notmuch-client.h | 4 +
notmuch-config.c | 15 +++
6 files changed, 345 insertions(+), 0 deletions(-)
create mode 100644 lib/log-private.h
create mode 100644 lib/log.c
diff --git a/lib/Makefile.local b/lib/Makefile.local
index a60ef98..d7e8f41 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -46,6 +46,7 @@ extra_cflags += -I$(dir) -fPIC
libnotmuch_c_srcs = \
$(notmuch_compat_srcs) \
$(dir)/libsha1.c \
+ $(dir)/log.c \
$(dir)/message-file.c \
$(dir)/messages.c \
$(dir)/sha1.c \
diff --git a/lib/log-private.h b/lib/log-private.h
new file mode 100644
index 0000000..1af05dd
--- /dev/null
+++ b/lib/log-private.h
@@ -0,0 +1,13 @@
+
+#ifndef NOTMUCH_LOG_PRIVATE_H
+#define NOTMUCH_LOG_PRIVATE_H
+#include "notmuch.h"
+struct _notmuch_log {
+ int file_desc;
+ char *buffer;
+ char *txn_id;
+ int txn_depth;
+ notmuch_log_buffering_t buffering;
+};
+
+#endif
diff --git a/lib/log.c b/lib/log.c
new file mode 100644
index 0000000..31f1e62
--- /dev/null
+++ b/lib/log.c
@@ -0,0 +1,289 @@
+
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright © 2010 David Bremner
+ *
+ * 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 3 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, see http://www.gnu.org/licenses/ .
+ *
+ * Author: David Bremner <david at tethera.net>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <talloc.h>
+#include <stdarg.h>
+
+#include "log-private.h"
+#include "notmuch.h"
+
+/*
+ * Return a file descriptor to the open log file, or -1 if an error
+ * occurs.
+ *
+ */
+
+notmuch_log_t *
+notmuch_log_open (void *ctx,const char *path, notmuch_log_buffering_t buffering)
+{
+ int fd;
+ notmuch_log_t *log;
+
+ log=talloc (ctx, notmuch_log_t);
+ if (log==NULL)
+ return NULL;
+
+ fd = open (path, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (fd < 0) {
+ fprintf (stderr, "Failed to open %s: %s\n",
+ path, strerror (errno));
+ return NULL;
+ }
+
+ log->file_desc = fd;
+ log->buffer = NULL;
+ log->txn_id = NULL;
+ log->txn_depth = 0;
+ log->buffering = buffering;
+ return log;
+}
+
+static notmuch_status_t
+_log_write (int file_desc, const char *buffer, size_t len){
+
+ struct flock lock;
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+
+ if (fcntl (file_desc, F_SETLKW, &lock) != 0) {
+ fprintf (stderr, "Failed to lock %s\n",
+ strerror (errno));
+
+ return NOTMUCH_STATUS_FILE_ERROR;
+ }
+
+ while (len > 0)
+ {
+ int written;
+
+ written = write(file_desc, buffer, len);
+ if (written < 0 || (written == 0 && errno !=0))
+ {
+ fprintf (stderr, "Failed to write %zd characters: %s\n",
+ len, strerror (errno));
+
+ return NOTMUCH_STATUS_FILE_ERROR;
+ }
+
+ len -= written;
+ buffer += written;
+
+ }
+
+ if (fdatasync (file_desc) != 0) {
+ fprintf (stderr, "Failed to sync: %s\n",
+ strerror (errno));
+
+ return NOTMUCH_STATUS_FILE_ERROR;
+ }
+
+ lock.l_type=F_UNLCK;
+
+ if (fcntl (file_desc, F_SETLK, &lock) != 0) {
+ fprintf (stderr, "Failed to unlock: %s\n",
+ strerror (errno));
+
+ return NOTMUCH_STATUS_FILE_ERROR;
+ }
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+void
+notmuch_log_sync (notmuch_log_t *log)
+{
+ if (log->buffer) {
+ _log_write(log->file_desc, log->buffer, strlen (log->buffer));
+ talloc_free(log->buffer);
+ log->buffer=NULL;
+ }
+
+};
+
+
+/* This function was derived from the print_string_ptr function of
+ * cJSON (http://cjson.sourceforge.net/) and is used by permission of
+ * the following license:
+ *
+ * Copyright (c) 2009 Dave Gamble
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+static char *
+_log_escape_chararray(const void *ctx, const char *str, const size_t len)
+{
+ const char *ptr;
+ char *ptr2;
+ char *out;
+ size_t loop;
+ size_t required;
+
+ for (loop = 0, required = 0, ptr = str;
+ loop < len;
+ loop++, required++, ptr++) {
+ if ((unsigned char)(*ptr) <= ' ')
+ required++;
+ }
+
+ /*
+ * + 1 for trailing NULL.
+ */
+ out = talloc_array (ctx, char, required + 1);
+
+ ptr = str;
+ ptr2 = out;
+
+ for (loop = 0; loop < len; loop++) {
+ if ((unsigned char)(*ptr) > 32 && *ptr != '\"' && *ptr != '\\') {
+ *ptr2++ = *ptr++;
+ } else {
+ *ptr2++ = '\\';
+ switch (*ptr++) {
+ case ' ': *ptr2++ = ' '; break;
+ case '\\': *ptr2++ = '\\'; break;
+ case '\b': *ptr2++ = 'b'; break;
+ case '\f': *ptr2++ = 'f'; break;
+ case '\n': *ptr2++ = 'n'; break;
+ case '\r': *ptr2++ = 'r'; break;
+ case '\t': *ptr2++ = 't'; break;
+ default: ptr2--; break;
+ }
+ }
+ }
+ *ptr2++ = '\0';
+
+ return out;
+}
+
+static char*
+_log_escape_string (void *ctx, const char *str)
+{
+ return _log_escape_chararray (ctx, str, strlen(str));
+}
+
+/*
+ * Log a series of strings as a space delimited line. Spaces and
+ * backslashes will be escaped by adding a backslash in front.
+ */
+
+static notmuch_status_t
+_log_append_string (notmuch_log_t *log, const char *str)
+{
+ if (log->buffer == NULL) {
+ log->buffer = talloc_strdup (log, str);
+ } else {
+ log->buffer = talloc_strdup_append (log->buffer, str);
+ }
+
+ if (log->buffer == NULL){
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
+ }
+
+ if (log->buffering == NOTMUCH_LOG_BUFFER_NONE)
+ notmuch_log_sync(log);
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+
+/*
+ * Log a null terminated list of strings as a single space delimited log line.
+ * spaces and newlines are escaped.
+ */
+
+void
+notmuch_log_words (notmuch_log_t *log, const char *word, ...)
+{
+ va_list args;
+ const char *str;
+ char *timestamp;
+
+ timestamp = talloc_asprintf (log, "%ld", (long)time(NULL));
+ _log_append_string(log,timestamp);
+ talloc_free(timestamp);
+
+ va_start (args, word);
+
+ for (str = word; str != NULL; str = va_arg (args, const char *)) {
+ _log_append_string (log, " ");
+ _log_append_string(log, _log_escape_string (log, str));
+ }
+
+ va_end(args);
+
+ _log_append_string(log, "\n");
+ if (log->buffering <= NOTMUCH_LOG_BUFFER_LINE)
+ notmuch_log_sync(log);
+
+};
+
+void
+notmuch_log_start_transaction (notmuch_log_t *log)
+{
+ /* XXX This should probably be something like a uuid */
+ if (log->txn_depth == 0) {
+ log->txn_id = talloc_asprintf (log, "%ld", random());
+ }
+ log->txn_depth++;
+
+ notmuch_log_words(log,"TX_START",
+ talloc_asprintf (log, "%s.%d", log->txn_id, log->txn_depth));
+};
+
+void
+notmuch_log_finish_transaction (notmuch_log_t *log)
+{
+ notmuch_log_words(log,"TX_END",
+ talloc_asprintf (log, "%s.%d", log->txn_id, log->txn_depth));
+
+ log->txn_depth--;
+
+ if (log->txn_depth == 0){
+ talloc_free (log->txn_id);
+ log->txn_id = NULL;
+ }
+};
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 505ad19..1da84aa 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -119,6 +119,7 @@ typedef struct _notmuch_message notmuch_message_t;
typedef struct _notmuch_tags notmuch_tags_t;
typedef struct _notmuch_directory notmuch_directory_t;
typedef struct _notmuch_filenames notmuch_filenames_t;
+typedef struct _notmuch_log notmuch_log_t;
/* Create a new, empty notmuch database located at 'path'.
*
@@ -1123,6 +1124,28 @@ notmuch_filenames_move_to_next (notmuch_filenames_t *filenames);
void
notmuch_filenames_destroy (notmuch_filenames_t *filenames);
+
+typedef enum _notmuch_log_buffer {
+ NOTMUCH_LOG_BUFFER_NONE = 0,
+ NOTMUCH_LOG_BUFFER_LINE = 1,
+ NOTMUCH_LOG_BUFFER_USER = 2
+} notmuch_log_buffering_t;
+
+notmuch_log_t *
+notmuch_log_open (void *ctx, const char *path, notmuch_log_buffering_t buffering);
+
+
+void
+notmuch_log_sync (notmuch_log_t *log);
+
+void
+notmuch_log_words (notmuch_log_t *log, const char *word, ...);
+void
+notmuch_log_start_transaction (notmuch_log_t *log);
+
+void
+notmuch_log_finish_transaction (notmuch_log_t *log);
+
NOTMUCH_END_DECLS
#endif
diff --git a/notmuch-client.h b/notmuch-client.h
index 20be43b..0be679d 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -191,6 +191,10 @@ notmuch_config_set_new_tags (notmuch_config_t *config,
const char *new_tags[],
size_t length);
+const char *
+notmuch_config_get_log_path (notmuch_config_t *config,
+ const char *name);
+
notmuch_bool_t
debugger_is_active (void);
diff --git a/notmuch-config.c b/notmuch-config.c
index cf30603..c01e8f4 100644
--- a/notmuch-config.c
+++ b/notmuch-config.c
@@ -562,3 +562,18 @@ notmuch_config_set_new_tags (notmuch_config_t *config,
config->new_tags = NULL;
}
+const char *
+notmuch_config_get_log_path (notmuch_config_t *config, const char *name)
+{
+ char *path, *rpath;
+
+ path= g_key_file_get_string (config->key_file,
+ "log", name, NULL);
+ if (path != NULL) {
+ rpath = talloc_strdup (config, path);
+ free (path);
+ return rpath;
+ } else {
+ return NULL;
+ }
+}
--
1.7.1
More information about the notmuch
mailing list