1 Return-Path: <bremner@unb.ca>
\r
2 X-Original-To: notmuch@notmuchmail.org
\r
3 Delivered-To: notmuch@notmuchmail.org
\r
4 Received: from localhost (localhost [127.0.0.1])
\r
5 by olra.theworths.org (Postfix) with ESMTP id 0A41040D152
\r
6 for <notmuch@notmuchmail.org>; Sun, 24 Oct 2010 14:02:08 -0700 (PDT)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=-2.6 tagged_above=-999 required=5
\r
12 tests=[BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7] autolearn=ham
\r
13 Received: from olra.theworths.org ([127.0.0.1])
\r
14 by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
\r
15 with ESMTP id Re-v-T3Ks9Tz for <notmuch@notmuchmail.org>;
\r
16 Sun, 24 Oct 2010 14:01:51 -0700 (PDT)
\r
17 Received: from tempo.its.unb.ca (tempo.its.unb.ca [131.202.1.21])
\r
18 by olra.theworths.org (Postfix) with ESMTP id BBEC840D157
\r
19 for <notmuch@notmuchmail.org>; Sun, 24 Oct 2010 14:01:14 -0700 (PDT)
\r
20 Received: from rocinante.cs.unb.ca
\r
21 (fctnnbsc30w-142167176217.pppoe-dynamic.High-Speed.nb.bellaliant.net
\r
22 [142.167.176.217]) (authenticated bits=0)
\r
23 by tempo.its.unb.ca (8.13.8/8.13.8) with ESMTP id o9OL1BEg017810
\r
24 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NO);
\r
25 Sun, 24 Oct 2010 18:01:14 -0300
\r
26 Received: from bremner by rocinante.cs.unb.ca with local (Exim 4.72)
\r
27 (envelope-from <bremner@unb.ca>)
\r
28 id 1PA7gl-0006Ok-Ci; Sun, 24 Oct 2010 18:01:11 -0300
\r
29 From: david@tethera.net
\r
30 To: notmuch@notmuchmail.org
\r
31 Subject: [PATCH 1/4] Initial implementation of low level logging routines.
\r
32 Date: Sun, 24 Oct 2010 18:01:03 -0300
\r
33 Message-Id: <1287954066-24512-2-git-send-email-david@tethera.net>
\r
34 X-Mailer: git-send-email 1.7.1
\r
35 In-Reply-To: <1286803617-17328-1-git-send-email-david@tethera.net>
\r
36 References: <1286803617-17328-1-git-send-email-david@tethera.net>
\r
37 Cc: David Bremner <bremner@unb.ca>
\r
38 X-BeenThere: notmuch@notmuchmail.org
\r
39 X-Mailman-Version: 2.1.13
\r
41 List-Id: "Use and development of the notmuch mail system."
\r
42 <notmuch.notmuchmail.org>
\r
43 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
44 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
45 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
46 List-Post: <mailto:notmuch@notmuchmail.org>
\r
47 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
48 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
49 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
50 X-List-Received-Date: Sun, 24 Oct 2010 21:02:08 -0000
\r
52 From: David Bremner <bremner@unb.ca>
\r
54 notmuch_log_open: open a log file; return an opaque "log descriptor"
\r
56 notmuch_log_words: log words, escaping spaces and newlines, and appending a newline.
\r
58 Log format is space delimited, and line oriented. Escaping log text
\r
59 is currently based on a slightly simplified version of
\r
60 json_quote_chararray in ../json.c. This is probably overkill.
\r
62 notmuch_log_transaction_(start|finish): log a transaction identifier
\r
65 Nested transactions are supported, so that this aligns with
\r
66 notmuch_message_(freeze|thaw). The are not too well tested though,
\r
67 since I don't know when they arise.
\r
69 lib/Makefile.local | 1 +
\r
70 lib/log-private.h | 13 +++
\r
71 lib/log.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++++
\r
72 lib/notmuch.h | 23 ++++
\r
73 notmuch-client.h | 4 +
\r
74 notmuch-config.c | 15 +++
\r
75 6 files changed, 345 insertions(+), 0 deletions(-)
\r
76 create mode 100644 lib/log-private.h
\r
77 create mode 100644 lib/log.c
\r
79 diff --git a/lib/Makefile.local b/lib/Makefile.local
\r
80 index a60ef98..d7e8f41 100644
\r
81 --- a/lib/Makefile.local
\r
82 +++ b/lib/Makefile.local
\r
83 @@ -46,6 +46,7 @@ extra_cflags += -I$(dir) -fPIC
\r
84 libnotmuch_c_srcs = \
\r
85 $(notmuch_compat_srcs) \
\r
88 $(dir)/message-file.c \
\r
91 diff --git a/lib/log-private.h b/lib/log-private.h
\r
92 new file mode 100644
\r
93 index 0000000..1af05dd
\r
95 +++ b/lib/log-private.h
\r
98 +#ifndef NOTMUCH_LOG_PRIVATE_H
\r
99 +#define NOTMUCH_LOG_PRIVATE_H
\r
100 +#include "notmuch.h"
\r
101 +struct _notmuch_log {
\r
106 + notmuch_log_buffering_t buffering;
\r
110 diff --git a/lib/log.c b/lib/log.c
\r
111 new file mode 100644
\r
112 index 0000000..31f1e62
\r
117 +/* notmuch - Not much of an email program, (just index and search)
\r
119 + * Copyright © 2010 David Bremner
\r
121 + * This program is free software: you can redistribute it and/or modify
\r
122 + * it under the terms of the GNU General Public License as published by
\r
123 + * the Free Software Foundation, either version 3 of the License, or
\r
124 + * (at your option) any later version.
\r
126 + * This program is distributed in the hope that it will be useful,
\r
127 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
128 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
129 + * GNU General Public License for more details.
\r
131 + * You should have received a copy of the GNU General Public License
\r
132 + * along with this program. If not, see http://www.gnu.org/licenses/ .
\r
134 + * Author: David Bremner <david@tethera.net>
\r
137 +#include <sys/types.h>
\r
138 +#include <sys/stat.h>
\r
139 +#include <fcntl.h>
\r
140 +#include <unistd.h>
\r
141 +#include <errno.h>
\r
142 +#include <string.h>
\r
143 +#include <talloc.h>
\r
144 +#include <stdarg.h>
\r
146 +#include "log-private.h"
\r
147 +#include "notmuch.h"
\r
150 + * Return a file descriptor to the open log file, or -1 if an error
\r
156 +notmuch_log_open (void *ctx,const char *path, notmuch_log_buffering_t buffering)
\r
159 + notmuch_log_t *log;
\r
161 + log=talloc (ctx, notmuch_log_t);
\r
165 + fd = open (path, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
\r
167 + fprintf (stderr, "Failed to open %s: %s\n",
\r
168 + path, strerror (errno));
\r
172 + log->file_desc = fd;
\r
173 + log->buffer = NULL;
\r
174 + log->txn_id = NULL;
\r
175 + log->txn_depth = 0;
\r
176 + log->buffering = buffering;
\r
180 +static notmuch_status_t
\r
181 +_log_write (int file_desc, const char *buffer, size_t len){
\r
183 + struct flock lock;
\r
185 + lock.l_type = F_WRLCK;
\r
186 + lock.l_whence = SEEK_SET;
\r
187 + lock.l_start = 0;
\r
190 + if (fcntl (file_desc, F_SETLKW, &lock) != 0) {
\r
191 + fprintf (stderr, "Failed to lock %s\n",
\r
192 + strerror (errno));
\r
194 + return NOTMUCH_STATUS_FILE_ERROR;
\r
201 + written = write(file_desc, buffer, len);
\r
202 + if (written < 0 || (written == 0 && errno !=0))
\r
204 + fprintf (stderr, "Failed to write %zd characters: %s\n",
\r
205 + len, strerror (errno));
\r
207 + return NOTMUCH_STATUS_FILE_ERROR;
\r
211 + buffer += written;
\r
215 + if (fdatasync (file_desc) != 0) {
\r
216 + fprintf (stderr, "Failed to sync: %s\n",
\r
217 + strerror (errno));
\r
219 + return NOTMUCH_STATUS_FILE_ERROR;
\r
222 + lock.l_type=F_UNLCK;
\r
224 + if (fcntl (file_desc, F_SETLK, &lock) != 0) {
\r
225 + fprintf (stderr, "Failed to unlock: %s\n",
\r
226 + strerror (errno));
\r
228 + return NOTMUCH_STATUS_FILE_ERROR;
\r
231 + return NOTMUCH_STATUS_SUCCESS;
\r
235 +notmuch_log_sync (notmuch_log_t *log)
\r
237 + if (log->buffer) {
\r
238 + _log_write(log->file_desc, log->buffer, strlen (log->buffer));
\r
239 + talloc_free(log->buffer);
\r
240 + log->buffer=NULL;
\r
246 +/* This function was derived from the print_string_ptr function of
\r
247 + * cJSON (http://cjson.sourceforge.net/) and is used by permission of
\r
248 + * the following license:
\r
250 + * Copyright (c) 2009 Dave Gamble
\r
252 + * Permission is hereby granted, free of charge, to any person obtaining a copy
\r
253 + * of this software and associated documentation files (the "Software"), to deal
\r
254 + * in the Software without restriction, including without limitation the rights
\r
255 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
\r
256 + * copies of the Software, and to permit persons to whom the Software is
\r
257 + * furnished to do so, subject to the following conditions:
\r
259 + * The above copyright notice and this permission notice shall be included in
\r
260 + * all copies or substantial portions of the Software.
\r
262 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
263 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
\r
264 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
\r
265 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
\r
266 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
\r
267 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
\r
272 +_log_escape_chararray(const void *ctx, const char *str, const size_t len)
\r
280 + for (loop = 0, required = 0, ptr = str;
\r
282 + loop++, required++, ptr++) {
\r
283 + if ((unsigned char)(*ptr) <= ' ')
\r
288 + * + 1 for trailing NULL.
\r
290 + out = talloc_array (ctx, char, required + 1);
\r
295 + for (loop = 0; loop < len; loop++) {
\r
296 + if ((unsigned char)(*ptr) > 32 && *ptr != '\"' && *ptr != '\\') {
\r
297 + *ptr2++ = *ptr++;
\r
300 + switch (*ptr++) {
\r
301 + case ' ': *ptr2++ = ' '; break;
\r
302 + case '\\': *ptr2++ = '\\'; break;
\r
303 + case '\b': *ptr2++ = 'b'; break;
\r
304 + case '\f': *ptr2++ = 'f'; break;
\r
305 + case '\n': *ptr2++ = 'n'; break;
\r
306 + case '\r': *ptr2++ = 'r'; break;
\r
307 + case '\t': *ptr2++ = 't'; break;
\r
308 + default: ptr2--; break;
\r
318 +_log_escape_string (void *ctx, const char *str)
\r
320 + return _log_escape_chararray (ctx, str, strlen(str));
\r
324 + * Log a series of strings as a space delimited line. Spaces and
\r
325 + * backslashes will be escaped by adding a backslash in front.
\r
328 +static notmuch_status_t
\r
329 +_log_append_string (notmuch_log_t *log, const char *str)
\r
331 + if (log->buffer == NULL) {
\r
332 + log->buffer = talloc_strdup (log, str);
\r
334 + log->buffer = talloc_strdup_append (log->buffer, str);
\r
337 + if (log->buffer == NULL){
\r
338 + return NOTMUCH_STATUS_OUT_OF_MEMORY;
\r
341 + if (log->buffering == NOTMUCH_LOG_BUFFER_NONE)
\r
342 + notmuch_log_sync(log);
\r
344 + return NOTMUCH_STATUS_SUCCESS;
\r
349 + * Log a null terminated list of strings as a single space delimited log line.
\r
350 + * spaces and newlines are escaped.
\r
354 +notmuch_log_words (notmuch_log_t *log, const char *word, ...)
\r
360 + timestamp = talloc_asprintf (log, "%ld", (long)time(NULL));
\r
361 + _log_append_string(log,timestamp);
\r
362 + talloc_free(timestamp);
\r
364 + va_start (args, word);
\r
366 + for (str = word; str != NULL; str = va_arg (args, const char *)) {
\r
367 + _log_append_string (log, " ");
\r
368 + _log_append_string(log, _log_escape_string (log, str));
\r
373 + _log_append_string(log, "\n");
\r
374 + if (log->buffering <= NOTMUCH_LOG_BUFFER_LINE)
\r
375 + notmuch_log_sync(log);
\r
380 +notmuch_log_start_transaction (notmuch_log_t *log)
\r
382 + /* XXX This should probably be something like a uuid */
\r
383 + if (log->txn_depth == 0) {
\r
384 + log->txn_id = talloc_asprintf (log, "%ld", random());
\r
386 + log->txn_depth++;
\r
388 + notmuch_log_words(log,"TX_START",
\r
389 + talloc_asprintf (log, "%s.%d", log->txn_id, log->txn_depth));
\r
393 +notmuch_log_finish_transaction (notmuch_log_t *log)
\r
395 + notmuch_log_words(log,"TX_END",
\r
396 + talloc_asprintf (log, "%s.%d", log->txn_id, log->txn_depth));
\r
398 + log->txn_depth--;
\r
400 + if (log->txn_depth == 0){
\r
401 + talloc_free (log->txn_id);
\r
402 + log->txn_id = NULL;
\r
405 diff --git a/lib/notmuch.h b/lib/notmuch.h
\r
406 index 505ad19..1da84aa 100644
\r
407 --- a/lib/notmuch.h
\r
408 +++ b/lib/notmuch.h
\r
409 @@ -119,6 +119,7 @@ typedef struct _notmuch_message notmuch_message_t;
\r
410 typedef struct _notmuch_tags notmuch_tags_t;
\r
411 typedef struct _notmuch_directory notmuch_directory_t;
\r
412 typedef struct _notmuch_filenames notmuch_filenames_t;
\r
413 +typedef struct _notmuch_log notmuch_log_t;
\r
415 /* Create a new, empty notmuch database located at 'path'.
\r
417 @@ -1123,6 +1124,28 @@ notmuch_filenames_move_to_next (notmuch_filenames_t *filenames);
\r
419 notmuch_filenames_destroy (notmuch_filenames_t *filenames);
\r
422 +typedef enum _notmuch_log_buffer {
\r
423 + NOTMUCH_LOG_BUFFER_NONE = 0,
\r
424 + NOTMUCH_LOG_BUFFER_LINE = 1,
\r
425 + NOTMUCH_LOG_BUFFER_USER = 2
\r
426 +} notmuch_log_buffering_t;
\r
429 +notmuch_log_open (void *ctx, const char *path, notmuch_log_buffering_t buffering);
\r
433 +notmuch_log_sync (notmuch_log_t *log);
\r
436 +notmuch_log_words (notmuch_log_t *log, const char *word, ...);
\r
438 +notmuch_log_start_transaction (notmuch_log_t *log);
\r
441 +notmuch_log_finish_transaction (notmuch_log_t *log);
\r
446 diff --git a/notmuch-client.h b/notmuch-client.h
\r
447 index 20be43b..0be679d 100644
\r
448 --- a/notmuch-client.h
\r
449 +++ b/notmuch-client.h
\r
450 @@ -191,6 +191,10 @@ notmuch_config_set_new_tags (notmuch_config_t *config,
\r
451 const char *new_tags[],
\r
455 +notmuch_config_get_log_path (notmuch_config_t *config,
\r
456 + const char *name);
\r
459 debugger_is_active (void);
\r
461 diff --git a/notmuch-config.c b/notmuch-config.c
\r
462 index cf30603..c01e8f4 100644
\r
463 --- a/notmuch-config.c
\r
464 +++ b/notmuch-config.c
\r
465 @@ -562,3 +562,18 @@ notmuch_config_set_new_tags (notmuch_config_t *config,
\r
466 config->new_tags = NULL;
\r
470 +notmuch_config_get_log_path (notmuch_config_t *config, const char *name)
\r
472 + char *path, *rpath;
\r
474 + path= g_key_file_get_string (config->key_file,
\r
475 + "log", name, NULL);
\r
476 + if (path != NULL) {
\r
477 + rpath = talloc_strdup (config, path);
\r