From eca62df908b5bb5ff8382d314bce31c6f64ca6f5 Mon Sep 17 00:00:00 2001 From: sr Date: Fri, 24 Aug 2012 21:02:36 +0200 Subject: ... --- src/server/memlog.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/server/memlog.c (limited to 'src/server/memlog.c') diff --git a/src/server/memlog.c b/src/server/memlog.c new file mode 100644 index 0000000..9809e64 --- /dev/null +++ b/src/server/memlog.c @@ -0,0 +1,114 @@ +/* + * This file is part of the Distributed Network Block Device 3 + * + * Copyright(c) 2011-2012 Simon Rettberg + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX(a,b) (a > b ? a : b) + +static pthread_spinlock_t logLock; + +#define LINE_LEN 500 +#define LINE_COUNT 50 + +typedef struct +{ + uint16_t len; + char text[LINE_LEN]; +} LogLine; + +// This will be used as a ring buffer +static volatile LogLine *logBuffer = NULL; +// bufferPos counts up, use modulo LINE_COUNT to get array index +static volatile int bufferPos = 0; + +void initmemlog() +{ + // Use main spinlock to make sure we really init only once + if (logBuffer) return; + pthread_spin_init(&logLock, PTHREAD_PROCESS_PRIVATE); + logBuffer = (LogLine *)calloc(LINE_COUNT, sizeof(LogLine)); +} + +void memlogf(const char *fmt, ...) +{ + if (!logBuffer) return; // Not initialized yet + va_list ap; + int ret; + time_t rawtime; + struct tm * timeinfo; + time(&rawtime); + timeinfo = localtime(&rawtime); + pthread_spin_lock(&logLock); + LogLine * const line = (LogLine *)&(logBuffer[bufferPos % LINE_COUNT]); + const size_t offset = strftime(line->text, LINE_LEN, "[%d.%m. %H:%M:%S] ", timeinfo); + if (offset == 0) *line->text = '\0'; + va_start(ap, fmt); + ret = vsnprintf(line->text + offset, LINE_LEN - offset, fmt, ap); + va_end(ap); + char *end = line->text + strlen(line->text); + while (end > line->text && *--end == '\n') *end = '\0'; // remove trailing \n + // glibc 2.0 would return -1 if the buffer was too small + // glibc 2.1 would return the number of bytes required if the buffer was too small + // so to be safe either way, let strlen do the job + line->len = strlen(line->text); + if (ret > 0 || line->len > 0) ++bufferPos; + pthread_spin_unlock(&logLock); + puts(line->text); +} + +char * fetchlog(int maxlines) +{ + if (!logBuffer) return NULL; + if (maxlines <= 0 || maxlines > LINE_COUNT) maxlines = LINE_COUNT; + const int start = MAX(0, bufferPos - maxlines); + int len = 1, i; + //printf("Outputting log from %d to %d\n", start, bufferPos); + pthread_spin_lock(&logLock); + // Determine required buffer space for all log lines + for (i = start; i < bufferPos; ++i) { + if (logBuffer[i % LINE_COUNT].len > 0) { + len += logBuffer[i % LINE_COUNT].len + 1; + } + } + //printf("Have to allocate %d bytes\n", len); + // Allocate buffer. If this is a bottleneck because of malloc, consider passing a buffer to the function that the caller allocates on the stack + char *retval = (char *)calloc(len, sizeof(char)); + if (retval == NULL) goto endFunction; + // Concatenate all log lines, delimit using '\n' + char *pos = retval; + for (i = start; i < bufferPos; ++i) { + LogLine * const line = (LogLine *)&(logBuffer[i % LINE_COUNT]); + if (line->len > 0) { + memcpy(pos, (char *)line->text, line->len); + pos += line->len; + *pos++ = '\n'; + } + } + *pos = '\0'; +endFunction: + pthread_spin_unlock(&logLock); + return retval; +} -- cgit v1.2.3-55-g7522