-/* Copyright (c) 2008, XenSource Inc.
+/*
+ * Copyright (c) 2008, 2009, XenSource Inc.
* All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <string.h>
+#include <unistd.h>
+#include <errno.h>
#include <stdarg.h>
#include <syslog.h>
-#include <inttypes.h>
-#include <time.h>
#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "blktaplib.h"
#include "tapdisk-log.h"
#include "tapdisk-utils.h"
+#include "tapdisk-logfile.h"
#include "tapdisk-vbd-stats.h"
+#define TLOG_LOGFILE_BUFSZ (16<<10)
+
#define MAX_ENTRY_LEN 512
#define MAX_ERROR_MESSAGES 16
};
struct tlog {
- char *p;
- int size;
- uint64_t cnt;
- char *buf;
+ char *ident;
+ td_logfile_t logfile;
+ int precious;
int level;
- char *file;
- int append;
};
static struct ehandle tapdisk_err;
static struct tlog tapdisk_log;
-void
-open_tlog(char *file, size_t bytes, int level, int append)
+static void
+tlog_logfile_vprint(const char *fmt, va_list ap)
{
- int i;
+ tapdisk_logfile_vprintf(&tapdisk_log.logfile, fmt, ap);
+}
- tapdisk_log.size = ((bytes + 511) & (~511));
+static void
+__attribute__((format(printf, 1, 2)))
+tlog_logfile_print(const char *fmt, ...)
+{
+ va_list ap;
- if (asprintf(&tapdisk_log.file, "%s.%d", file, getpid()) == -1)
- return;
+ va_start(ap, fmt);
+ tlog_logfile_vprint(fmt, ap);
+ va_end(ap);
+}
- if (posix_memalign((void **)&tapdisk_log.buf, 512, tapdisk_log.size)) {
- free(tapdisk_log.file);
- tapdisk_log.buf = NULL;
- return;
+static void
+tlog_logfile_save(void)
+{
+ td_logfile_t *logfile = &tapdisk_log.logfile;
+ const char *ident = tapdisk_log.ident;
+ int err;
+
+ tlog_logfile_print("%s: saving log, %d errors",
+ tapdisk_syslog_ident(ident), tapdisk_err.cnt);
+
+ tapdisk_logfile_flush(logfile);
+
+ err = tapdisk_logfile_rename(logfile,
+ TLOG_DIR, ident, ".log");
+#if 0
+ tlog_syslog("logfile saved to %s: %d\n", logfile->path, err);
+#endif
+}
+
+static void
+tlog_logfile_close(void)
+{
+ td_logfile_t *logfile = &tapdisk_log.logfile;
+ const char *ident = tapdisk_log.ident;
+ int keep, err;
+
+ keep = tapdisk_log.precious || tapdisk_err.cnt;
+
+ tlog_logfile_print("%s: closing log, %d errors",
+ tapdisk_syslog_ident(ident), tapdisk_err.cnt);
+
+ if (keep) {
+ tlog_logfile_save();
+ DPRINTF("logfile kept as %s\n", logfile->path);
+ }
+
+ tapdisk_logfile_close(logfile);
+
+ if (!keep)
+ tapdisk_logfile_unlink(logfile);
+}
+
+static int
+tlog_logfile_open(const char *ident, int level)
+{
+ td_logfile_t *logfile = &tapdisk_log.logfile;
+ int mode, err;
+
+ err = mkdir(TLOG_DIR, 0755);
+ if (err) {
+ err = -errno;
+ if (err != -EEXIST)
+ goto fail;
}
- memset(tapdisk_log.buf, 0, tapdisk_log.size);
+ err = tapdisk_logfile_open(logfile,
+ TLOG_DIR, ident, ".tmp",
+ TLOG_LOGFILE_BUFSZ);
+ if (err)
+ goto fail;
+
+ mode = (level == TLOG_DBG) ? _IOLBF : _IOFBF;
+
+ err = tapdisk_logfile_setvbuf(logfile, mode);
+ if (err)
+ goto fail;
+
+ tlog_logfile_print("%s: log start, level %d",
+ tapdisk_syslog_ident(ident), level);
+
+ return 0;
+
+fail:
+ tlog_logfile_close();
+ return err;
+}
+
+static void
+tlog_logfile_error(int err, const char *func, const char *fmt, va_list ap)
+{
+ td_logfile_t *logfile = &tapdisk_log.logfile;
+ char buf[MAX_ENTRY_LEN+1];
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
- tapdisk_log.p = tapdisk_log.buf;
- tapdisk_log.level = level;
- tapdisk_log.append = append;
+ tlog_logfile_print("ERROR: errno %d at %s: %s", err, func, buf);
+
+ tlog_precious();
+}
+
+static void
+tlog_errors_init(const char *ident, int facility)
+{
+ int i;
for (i = 0; i < MAX_ERROR_MESSAGES; ++i)
td_dispersion_init(&tapdisk_err.errors[i].st);
}
+int
+tlog_open(const char *ident, int facility, int level)
+{
+ int err;
+
+ DPRINTF("tlog starting, level %d\n", level);
+
+ tapdisk_log.level = level;
+ tapdisk_log.ident = strdup(ident);
+
+ if (!tapdisk_log.ident) {
+ err = -errno;
+ goto fail;
+ }
+
+ err = tlog_logfile_open(ident, level);
+ if (err)
+ goto fail;
+
+ tlog_errors_init(ident, facility);
+
+ return 0;
+
+fail:
+ tlog_close();
+ return err;
+}
+
void
-close_tlog(void)
+tlog_close(void)
{
- if (!tapdisk_log.buf)
- return;
+ DPRINTF("tlog closing with %d errors\n", tapdisk_err.cnt);
- if (tapdisk_log.append)
- tlog_flush();
+ tlog_logfile_close();
- free(tapdisk_log.buf);
- free(tapdisk_log.file);
+ free(tapdisk_log.ident);
+ tapdisk_log.ident = NULL;
+}
- memset(&tapdisk_log, 0, sizeof(struct tlog));
+void
+tlog_precious(void)
+{
+ if (!tapdisk_log.precious)
+ tlog_logfile_save();
+
+ tapdisk_log.precious = 1;
+}
+
+void
+__tlog_write(int prio, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (prio <= tapdisk_log.level) {
+ va_start(ap, fmt);
+ tlog_logfile_vprint(fmt, ap);
+ va_end(ap);
+ }
}
static void
__tlog_strtime(tstr, len, &tv);
}
-void
-__tlog_write(int level, const char *func, const char *fmt, ...)
-{
- char *buf;
- va_list ap;
- int ret, len, avail;
- char tstr[64];
-
- if (!tapdisk_log.buf)
- return;
-
- if (level > tapdisk_log.level)
- return;
-
- avail = tapdisk_log.size - (tapdisk_log.p - tapdisk_log.buf);
- if (avail < MAX_ENTRY_LEN) {
- if (tapdisk_log.append)
- tlog_flush();
- tapdisk_log.p = tapdisk_log.buf;
- }
-
- buf = tapdisk_log.p;
- tlog_strtime(tstr, sizeof(tstr));
- len = snprintf(buf, MAX_ENTRY_LEN - 1, "%08"PRIu64":[%s]:%s ",
- tapdisk_log.cnt, tstr, func);
-
- va_start(ap, fmt);
- ret = vsnprintf(buf + len, MAX_ENTRY_LEN - (len + 1), fmt, ap);
- va_end(ap);
-
- len = (ret < MAX_ENTRY_LEN - (len + 1) ?
- len + ret : MAX_ENTRY_LEN - 1);
- buf[len] = '\0';
-
- tapdisk_log.cnt++;
- tapdisk_log.p += len;
-}
-
void
__tlog_error(int err, const char *func, const char *fmt, ...)
{
err = (err > 0 ? err : -err);
+ va_start(ap, fmt);
+ tlog_logfile_error(err, func, fmt, ap);
+ va_end(ap);
+
for (i = 0; i < tapdisk_err.cnt; i++) {
e = &tapdisk_err.errors[i];
if (e->err == err && e->func == func) {
}
void
-tlog_flush_errors(void)
-{
- int i;
- struct error *e;
-
- for (i = 0; i < tapdisk_err.cnt; i++) {
- e = &tapdisk_err.errors[i];
- tlog_write(TLOG_WARN, "TAPDISK ERROR: errno %d at %s "
- "(cnt = %d): %s\n", e->err, e->func, e->cnt,
- e->msg);
- }
-
- if (tapdisk_err.dropped)
- tlog_write(TLOG_WARN, "TAPDISK ERROR: %d other error messages "
- "dropped\n", tapdisk_err.dropped);
-}
-
-void
-tlog_flush(void)
-{
- int fd, flags;
- size_t size, wsize;
-
- if (!tapdisk_log.buf)
- return;
-
- flags = O_CREAT | O_WRONLY | O_DIRECT | O_NONBLOCK;
- if (!tapdisk_log.append)
- flags |= O_TRUNC;
-
- fd = open(tapdisk_log.file, flags, 0644);
- if (fd == -1)
- return;
-
- if (tapdisk_log.append)
- if (lseek64(fd, 0, SEEK_END) == (loff_t)-1)
- goto out;
-
- tlog_flush_errors();
-
- size = tapdisk_log.p - tapdisk_log.buf;
- wsize = ((size + 511) & (~511));
-
- memset(tapdisk_log.buf + size, '\n', wsize - size);
- write(fd, tapdisk_log.buf, wsize);
-
- tapdisk_log.p = tapdisk_log.buf;
-
-out:
- close(fd);
-}
-
-void
-tapdisk_start_logging(const char *ident, const char *facility)
+tapdisk_start_logging(const char *ident, const char *_facility)
{
static char buf[128];
+ int facility, err;
- snprintf(buf, sizeof(buf), "%s[%d]", ident, getpid());
+ facility = tapdisk_syslog_facility(_facility);
- openlog(buf, LOG_CONS|LOG_ODELAY, tapdisk_syslog_facility(facility));
+ snprintf(buf, sizeof(buf), "%s[%d]", ident, getpid());
+ openlog(buf, LOG_CONS|LOG_ODELAY, facility);
- open_tlog("/tmp/tapdisk.log", (64 << 10), TLOG_WARN, 0);
+ err = tlog_open(ident, facility, TLOG_WARN);
+ if (err)
+ EPRINTF("tlog open failure: %d\n", err);
}
void
tapdisk_stop_logging(void)
{
- close_tlog();
+ tlog_close();
closelog();
}
-/* Copyright (c) 2008, XenSource Inc.
+/*
+ * Copyright (c) 2009, XenSource Inc.
* All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_LOG_H_
#define TLOG_INFO 1
#define TLOG_DBG 2
-void open_tlog(char *file, size_t bytes, int level, int append);
-void close_tlog(void);
-void tlog_flush(void);
+#define TLOG_DIR "/var/log/blktap"
+
+int tlog_open(const char *, int, int);
+int tlog_setvbuf(void);
+void tlog_close(void);
+void tlog_precious(void);
void tlog_print_errors(void);
-void __tlog_write(int level, const char *func, const char *fmt, ...)
- __attribute__((format(printf, 3, 4)));
+void __tlog_write(int, const char *, ...)
+ __attribute__((format(printf, 2, 3)));
+
void __tlog_error(int err, const char *func, const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
#define tlog_write(_level, _f, _a...) \
- __tlog_write(_level, __func__, _f, ##_a)
+ __tlog_write(_level, "%s: " _f, __func__, ##_a)
#define tlog_error(_err, _f, _a...) \
__tlog_error(_err, __func__, _f, ##_a)