summaryrefslogtreecommitdiffstats
path: root/src/server/memlog.c
diff options
context:
space:
mode:
authorsr2012-08-24 21:02:36 +0200
committersr2012-08-24 21:02:36 +0200
commiteca62df908b5bb5ff8382d314bce31c6f64ca6f5 (patch)
treedbd5f49c8574049b2e15c3488313586353035a27 /src/server/memlog.c
parent[*] Cleanup, comments, more error checks (diff)
downloaddnbd3-eca62df908b5bb5ff8382d314bce31c6f64ca6f5.tar.gz
dnbd3-eca62df908b5bb5ff8382d314bce31c6f64ca6f5.tar.xz
dnbd3-eca62df908b5bb5ff8382d314bce31c6f64ca6f5.zip
...
Diffstat (limited to 'src/server/memlog.c')
-rw-r--r--src/server/memlog.c114
1 files changed, 114 insertions, 0 deletions
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 <stdarg.h>
+#include <pthread.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#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;
+}