summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/nslog/nslog.h45
-rw-r--r--src/core.c100
-rw-r--r--test/basic.c22
3 files changed, 96 insertions, 71 deletions
diff --git a/include/nslog/nslog.h b/include/nslog/nslog.h
index fff31a7..ffa87bd 100644
--- a/include/nslog/nslog.h
+++ b/include/nslog/nslog.h
@@ -15,6 +15,8 @@
#ifndef NSLOG_NSLOG_H_
#define NSLOG_NSLOG_H_
+#include <stdarg.h>
+
typedef enum {
NSLOG_LEVEL_DEEPDEBUG = 0,
NSLOG_LEVEL_DEBUG = 1,
@@ -45,16 +47,15 @@ typedef struct nslog_category_s {
struct nslog_category_s *next;
} nslog_category_t;
-typedef struct nslog_entry_s {
+typedef struct nslog_entry_context_s {
nslog_category_t *category;
nslog_level level;
const char *filename;
const char *funcname;
int lineno;
- char message[0]; /* NUL terminated */
-} nslog_entry_t;
+} nslog_entry_context_t;
-#define NSLOG_DECLARE_CATEGORY(catname) \
+#define NSLOG_DECLARE_CATEGORY(catname) \
extern nslog_category_t __nslog_category_##catname
#define NSLOG_DEFINE_CATEGORY(catname, description) \
@@ -75,31 +76,31 @@ typedef struct nslog_entry_s {
NULL, \
}
-#define NSLOG(catname, level, logmsg, args...) \
- if (NSLOG_LEVEL_##level >= NSLOG_COMPILED_MIN_LEVEL) { \
- nslog__log(&__nslog_category_##catname, \
- NSLOG_LEVEL_##level, \
- __FILE__, \
- __LINE__, \
- __PRETTY_FUNCTION__, \
- logmsg, \
- ##args); \
- }
-
-void nslog__log(nslog_category_t *category,
- nslog_level level,
- const char *filename,
- int lineno,
- const char *funcname,
+#define NSLOG(catname, level, logmsg, args...) \
+ do { \
+ if (NSLOG_LEVEL_##level >= NSLOG_COMPILED_MIN_LEVEL) { \
+ nslog_entry_context_t ctx = { \
+ &__nslog_category_##catname, \
+ NSLOG_LEVEL_##level, \
+ __FILE__, \
+ __PRETTY_FUNCTION__, \
+ __LINE__, \
+ }; \
+ nslog__log(&ctx, logmsg, ##args); \
+ } \
+ } while(0)
+
+void nslog__log(nslog_entry_context_t *ctx,
const char *pattern,
- ...) __attribute__ ((format (printf, 6, 7)));
+ ...) __attribute__ ((format (printf, 2, 3)));
typedef enum {
NSLOG_NO_ERROR = 0,
NSLOG_NO_MEMORY = 1,
} nslog_error;
-typedef void (*nslog_callback)(void *context, nslog_entry_t *msg);
+typedef void (*nslog_callback)(void *context, nslog_entry_context_t *ctx,
+ const char *fmt, va_list args);
nslog_error nslog_set_render_callback(nslog_callback cb, void *context);
diff --git a/src/core.c b/src/core.c
index 0665195..ee5f2bc 100644
--- a/src/core.c
+++ b/src/core.c
@@ -20,12 +20,14 @@
#include <stdlib.h>
#include <string.h>
+
static bool nslog__corked = true;
static struct nslog_cork_chain {
struct nslog_cork_chain *next;
- nslog_entry_t *entry;
-} *nslog__cork_chain = NULL;
+ nslog_entry_context_t context;
+ char message[0]; /* NUL terminated */
+} *nslog__cork_chain = NULL, *nslog__cork_chain_last = NULL;
static nslog_callback nslog__cb = NULL;
static void *nslog__cb_ctx = NULL;
@@ -70,58 +72,56 @@ static void nslog__normalise_category(nslog_category_t *cat)
}
}
-static void nslog__deliver(nslog_entry_t *entry)
+static void nslog__log_corked(nslog_entry_context_t *ctx,
+ int measured_len,
+ const char *fmt,
+ va_list args)
+{
+ /* If corked, we need to store a copy */
+ struct nslog_cork_chain *newcork = malloc(sizeof(*newcork) + measured_len + 1);
+ if (newcork == NULL) {
+ /* Wow, something went wrong */
+ return;
+ }
+ newcork->context = *ctx;
+ vsprintf(newcork->message, fmt, args);
+ if (nslog__cork_chain == NULL) {
+ nslog__cork_chain = nslog__cork_chain_last = newcork;
+ } else {
+ nslog__cork_chain_last->next = newcork;
+ nslog__cork_chain_last = newcork;
+ }
+}
+
+static void nslog__log_uncorked(nslog_entry_context_t *ctx,
+ const char *fmt,
+ va_list args)
{
/* TODO: Add filtering here */
if (nslog__cb != NULL) {
- if (entry->category->name == NULL) {
- nslog__normalise_category(entry->category);
+ if (ctx->category->name == NULL) {
+ nslog__normalise_category(ctx->category);
}
- (*nslog__cb)(nslog__cb_ctx, entry);
+ (*nslog__cb)(nslog__cb_ctx, ctx, fmt, args);
}
}
-void nslog__log(nslog_category_t *category,
- nslog_level level,
- const char *filename,
- int lineno,
- const char *funcname,
+void nslog__log(nslog_entry_context_t *ctx,
const char *pattern,
...)
{
va_list ap;
va_start(ap, pattern);
- va_list ap2;
- va_copy(ap2, ap);
- int slen = vsnprintf(NULL, 0, pattern, ap);
- va_end(ap);
- nslog_entry_t *entry = malloc(sizeof(nslog_entry_t) + slen + 1);
- if (entry == NULL) {
- /* We're at ENOMEM! log entry is lost */
- va_end(ap2);
- return;
- }
- entry->category = category;
- entry->level = level;
- entry->filename = filename;
- entry->funcname = funcname;
- entry->lineno = lineno;
- vsprintf(entry->message, pattern, ap2);
- va_end(ap2);
if (nslog__corked) {
- struct nslog_cork_chain *chained = malloc(sizeof(struct nslog_cork_chain));
- if (chained == NULL) {
- /* ENOMEM during corked operation! wow */
- free(entry);
- return;
- }
- chained->next = nslog__cork_chain;
- chained->entry = entry;
- nslog__cork_chain = chained;
+ va_list ap2;
+ va_copy(ap2, ap);
+ int slen = vsnprintf(NULL, 0, pattern, ap);
+ va_end(ap);
+ nslog__log_corked(ctx, slen, pattern, ap2);
+ va_end(ap2);
} else {
- /* Not corked */
- nslog__deliver(entry);
- free(entry);
+ nslog__log_uncorked(ctx, pattern, ap);
+ va_end(ap);
}
}
@@ -133,14 +133,30 @@ nslog_error nslog_set_render_callback(nslog_callback cb, void *context)
return NSLOG_NO_ERROR;
}
+
+static void __nslog__deliver_corked_entry(nslog_entry_context_t *ctx,
+ const char *fmt,
+ ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ if (nslog__cb != NULL) {
+ (*nslog__cb)(nslog__cb_ctx, ctx, fmt, args);
+ }
+ va_end(args);
+}
+
nslog_error nslog_uncork()
{
if (nslog__corked) {
while (nslog__cork_chain != NULL) {
struct nslog_cork_chain *ent = nslog__cork_chain;
nslog__cork_chain = ent->next;
- nslog__deliver(ent->entry);
- free(ent->entry);
+ if (ent->context.category->name == NULL) {
+ nslog__normalise_category(ent->context.category);
+ }
+ __nslog__deliver_corked_entry(&ent->context,
+ "%s", ent->message);
free(ent);
}
nslog__corked = false;
diff --git a/test/basic.c b/test/basic.c
index fd40633..7626dd8 100644
--- a/test/basic.c
+++ b/test/basic.c
@@ -13,21 +13,29 @@
NSLOG_DEFINE_CATEGORY(test, "Test category");
-static void test_render_function(void *ctx, nslog_entry_t *log)
+static void test_render_function(
+ void *_ctx, nslog_entry_context_t *ctx,
+ const char *fmt, va_list args)
{
(void)ctx;
- fprintf(stderr, "%s %s:%d [%s] %s() %s\n",
- nslog_level_name(log->level),
- log->filename, log->lineno,
- log->category->name,
- log->funcname,
- log->message);
+ fprintf(stderr, "%s %s:%d [%s] %s() ",
+ nslog_level_name(ctx->level),
+ ctx->filename, ctx->lineno,
+ ctx->category->name,
+ ctx->funcname);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
}
int main(int argc, char **argv)
{
nslog_set_render_callback(test_render_function, NULL);
+ NSLOG(test, INFO, "Pre-uncorking");
+ fprintf(stderr, "About to nslog_uncork()\n");
nslog_uncork();
+ fprintf(stderr, "Uncorked now\n");
NSLOG(test, WARN, "argc=%d", argc);
+ for (int i = 0; i < argc; ++i)
+ NSLOG(test, WARN, "argv[%d] = %s", i, argv[i]);
return 0;
}