Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
examples/simplelog.c | 25 +++++++++++++++++------
include/qb/qblog.h | 24 +++++++++++++++++++++++
lib/log.c | 42 +++++++++++++++++++++++++++++++++++++++-
tests/check_log.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 133 insertions(+), 9 deletions(-)
diff --git a/examples/simplelog.c b/examples/simplelog.c
index 593dd5c..c0607c2 100644
--- a/examples/simplelog.c
+++ b/examples/simplelog.c
@@ -29,6 +29,8 @@
#define MY_TAG_TWO (1 << 1)
#define MY_TAG_THREE (1 << 2)
+static int32_t _log_priority = LOG_WARNING;
+
static void func_one(void)
{
FILE* fd;
@@ -115,12 +117,23 @@ trace_logger(int32_t t,
fprintf(stderr, "%s\n", output_buffer);
}
+static void
+m_filter(struct qb_log_callsite *cs)
+{
+ if ((cs->priority >= LOG_ALERT &&
+ cs->priority <= _log_priority) &&
+ strcmp(cs->filename, __FILE__) == 0) {
+ qb_bit_set(cs->targets, QB_LOG_STDERR);
+ } else {
+ qb_bit_clear(cs->targets, QB_LOG_STDERR);
+ }
+}
+
int32_t main(int32_t argc, char *argv[])
{
const char *options = "vhtebdf:";
int32_t opt;
int32_t tracer;
- int32_t priority = LOG_WARNING;
int32_t do_stderr = QB_FALSE;
int32_t do_dump_blackbox = QB_FALSE;
char *logfile = NULL;
@@ -144,7 +157,7 @@ int32_t main(int32_t argc, char *argv[])
logfile = optarg;
break;
case 'v':
- priority++;
+ _log_priority++;
break;
case 'h':
default:
@@ -168,10 +181,8 @@ int32_t main(int32_t argc, char *argv[])
tracer = qb_log_custom_open(trace_logger, NULL, NULL, NULL);
if (do_stderr) {
- qb_log_filter_ctl2(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
- QB_LOG_FILTER_FILE, __FILE__,
- LOG_ALERT, QB_MIN(LOG_DEBUG, priority));
- qb_log_format_set(QB_LOG_STDERR, "%4g: %f:%l [%p] %b");
+ qb_log_filter_fn_set(m_filter);
+ qb_log_format_set(QB_LOG_STDERR, "[%p] %4g: %f:%l %b");
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
qb_log_ctl(tracer, QB_LOG_CONF_ENABLED, QB_TRUE);
@@ -190,7 +201,7 @@ int32_t main(int32_t argc, char *argv[])
if (logfile) {
log_fd = qb_log_file_open(logfile);
qb_log_filter_ctl(log_fd, QB_LOG_FILTER_ADD,
- QB_LOG_FILTER_FILE, __FILE__, priority);
+ QB_LOG_FILTER_FILE, __FILE__, _log_priority);
qb_log_format_set(log_fd, "[%N] %t %n() [%p] %b");
qb_log_ctl(log_fd, QB_LOG_CONF_THREADED, do_threaded);
qb_log_ctl(log_fd, QB_LOG_CONF_ENABLED, QB_TRUE);
diff --git a/include/qb/qblog.h b/include/qb/qblog.h
index f1a6305..3d7bf82 100644
--- a/include/qb/qblog.h
+++ b/include/qb/qblog.h
@@ -237,6 +237,8 @@ struct qb_log_callsite {
uint32_t tags;
} __attribute__((aligned(8)));
+typedef void (*qb_log_filter_fn)(struct qb_log_callsite * cs);
+
/* will be assigned by ld linker magic */
#ifdef QB_HAVE_ATTRIBUTE_SECTION
extern struct qb_log_callsite __start___verbose[];
@@ -462,6 +464,28 @@ int32_t qb_log_filter_ctl2(int32_t value, enum qb_log_filter_conf c,
enum qb_log_filter_type type, const char * text,
uint8_t high_priority, uint8_t low_priority);
+
+/**
+ * Instead of using the qb_log_filter_ctl() functions you
+ * can apply the filters manually by defining a callback
+ * and setting the targets field using qb_bit_set() and
+ * qb_bit_clear() like the following below.
+ * @code
+ * static void
+ * m_filter(struct qb_log_callsite *cs)
+ * {
+ * if ((cs->priority >= LOG_ALERT &&
+ * cs->priority <= LOG_DEBUG) &&
+ * strcmp(cs->filename, "my_c_file.c") == 0) {
+ * qb_bit_set(cs->targets, QB_LOG_SYSLOG);
+ * } else {
+ * qb_bit_clear(cs->targets, QB_LOG_SYSLOG);
+ * }
+ * }
+ * @endcode
+ */
+int32_t qb_log_filter_fn_set(qb_log_filter_fn fn);
+
/**
* Set the callback to map the 'tags' bit map to a string.
*/
diff --git a/lib/log.c b/lib/log.c
index 867334f..0785b21 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -43,6 +43,7 @@ static uint32_t conf_active_max = 0;
static int32_t in_logger = QB_FALSE;
static int32_t logger_inited = QB_FALSE;
static pthread_rwlock_t _listlock;
+static qb_log_filter_fn _custom_filter_fn = NULL;
static QB_LIST_DECLARE(tags_head);
static QB_LIST_DECLARE(callsite_sections);
@@ -268,7 +269,7 @@ qb_log_from_external_source_va(const char *function,
flt = qb_list_entry(f_item, struct qb_log_filter, list);
_log_filter_apply_to_cs(cs, t->pos, flt->conf, flt->type,
flt->text, flt->high_priority,
- flt->low_priority);
+ flt->low_priority);
}
}
if (tags == 0) {
@@ -276,11 +277,14 @@ qb_log_from_external_source_va(const char *function,
flt = qb_list_entry(f_item, struct qb_log_filter, list);
_log_filter_apply_to_cs(cs, flt->new_value, flt->conf, flt->type,
flt->text, flt->high_priority,
- flt->low_priority);
+ flt->low_priority);
}
} else {
cs->tags = tags;
}
+ if (_custom_filter_fn) {
+ _custom_filter_fn(cs);
+ }
pthread_rwlock_unlock(&_listlock);
}
qb_log_real_va_(cs, ap);
@@ -306,6 +310,7 @@ qb_log_callsites_register(struct qb_log_callsite *_start,
struct qb_log_callsite *_stop)
{
struct callsite_section *sect;
+ struct qb_log_callsite *cs;
struct qb_log_target *t;
struct qb_log_filter *flt;
int32_t pos;
@@ -354,6 +359,14 @@ qb_log_callsites_register(struct qb_log_callsite *_start,
flt->high_priority, flt->low_priority);
}
pthread_rwlock_unlock(&_listlock);
+ if (_custom_filter_fn) {
+ for (cs = sect->start; cs < sect->stop; cs++) {
+ if (cs->lineno == 0) {
+ break;
+ }
+ _custom_filter_fn(cs);
+ }
+ }
return 0;
}
@@ -588,6 +601,31 @@ qb_log_filter_ctl2(int32_t t, enum qb_log_filter_conf c,
}
int32_t
+qb_log_filter_fn_set(qb_log_filter_fn fn)
+{
+ struct callsite_section *sect;
+ struct qb_log_callsite *cs;
+
+ if (!logger_inited) {
+ return -EINVAL;
+ }
+ _custom_filter_fn = fn;
+ if (_custom_filter_fn == NULL) {
+ return 0;
+ }
+
+ qb_list_for_each_entry(sect, &callsite_sections, list) {
+ for (cs = sect->start; cs < sect->stop; cs++) {
+ if (cs->lineno == 0) {
+ break;
+ }
+ _custom_filter_fn(cs);
+ }
+ }
+ return 0;
+}
+
+int32_t
qb_log_filter_ctl(int32_t t, enum qb_log_filter_conf c,
enum qb_log_filter_type type,
const char *text, uint8_t priority)
diff --git a/tests/check_log.c b/tests/check_log.c
index 19f84f1..318de9a 100644
--- a/tests/check_log.c
+++ b/tests/check_log.c
@@ -186,6 +186,53 @@ static void log_it_please(void)
qb_leave();
}
+
+static int32_t _cust_t = -1;
+static void
+m_filter(struct qb_log_callsite *cs)
+{
+ if ((cs->priority >= LOG_ALERT &&
+ cs->priority <= LOG_INFO) ||
+ cs->tags > 0) {
+ qb_bit_set(cs->targets, _cust_t);
+ } else {
+ qb_bit_clear(cs->targets, _cust_t);
+ }
+}
+
+
+START_TEST(test_log_filter_fn)
+{
+ int32_t rc;
+
+ qb_log_init("test", LOG_USER, LOG_EMERG);
+ qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
+
+ _cust_t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
+ _ck_assert_int(_cust_t, >, QB_LOG_BLACKBOX);
+ rc = qb_log_ctl(_cust_t, QB_LOG_CONF_ENABLED, QB_TRUE);
+ ck_assert_int_eq(rc, 0);
+
+ /*
+ * test the custom filter function.
+ * make sure qb_log, and qb_log_from_external_source are filtered.
+ */
+ qb_log_filter_fn_set(m_filter);
+ num_msgs = 0;
+
+ qb_log(LOG_NOTICE, "qb_log_filter_fn_set good");
+ qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
+ __LINE__, 0, "qb_log_filter_fn_set good");
+ qb_log(LOG_TRACE, "qb_log_filter_fn_set bad");
+ qb_log_from_external_source(__func__, __FILE__, "%s", LOG_DEBUG,
+ __LINE__, 44, "qb_log_filter_fn_set woot");
+ qb_log_from_external_source(__func__, __FILE__, "%s", LOG_DEBUG,
+ __LINE__, 0, "qb_log_filter_fn_set bad");
+
+ ck_assert_int_eq(num_msgs, 3);
+}
+END_TEST
+
START_TEST(test_log_basic)
{
int32_t t;
@@ -533,6 +580,10 @@ static Suite *log_suite(void)
tcase_add_test(tc, test_log_long_msg);
suite_add_tcase(s, tc);
+ tc = tcase_create("filter_ft");
+ tcase_add_test(tc, test_log_filter_fn);
+ suite_add_tcase(s, tc);
+
return s;
}
--
1.7.7.6