Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/include/qb/qblog.h b/include/qb/qblog.h
index d30da3f..132bb54 100644
--- a/include/qb/qblog.h
+++ b/include/qb/qblog.h
@@ -1,470 +1,472 @@
/*
* Copyright (C) 2010 Red Hat, Inc.
*
* All rights reserved.
*
* Author: Angus Salkeld <asalkeld@redhat.com>
*
* libqb is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* libqb is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libqb. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QB_LOG_H_DEFINED
#define QB_LOG_H_DEFINED
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <syslog.h>
#include <qb/qbconfig.h>
#ifdef S_SPLINT_S
#undef QB_HAVE_ATTRIBUTE_SECTION
#endif /* S_SPLINT_S */
/**
* @file qblog.h
* The logging API provides four main parts (basics, filtering, threading & blackbox).
*
* The idea behind this logging system is not to be prescriptive but to provide a
* set of tools to help the developer achieve what they want quickly and easily.
*
* @par Basic logging API.
* Call qb_log() to generate a log message. Then to write the message
* somewhere meaningful call qb_log_ctl() to configure the targets.
*
* Simplist possible use:
* @code
* main() {
* qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
* // ...
* qb_log(LOG_WARNING, "watch out");
* // ...
* qb_log_fini();
* }
* @endcode
*
* @par Configuring log targets.
* A log target can by syslog, stderr, the blackbox or a text file.
* By default only syslog is enabled.
*
* To enable a target do the following
* @code
* qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
* @endcode
*
* syslog, stderr and the blackbox are static (they don't need
* to be created, just enabled or disabled. However you can open multiple
* logfiles (32 - QB_LOG_BLACKBOX). To do this use the following code.
* @code
* mytarget = qb_log_file_open("/var/log/mylogfile");
* qb_log_ctl(mytarget, QB_LOG_CONF_ENABLED, QB_TRUE);
* @endcode
*
* Once your targets are enabled/opened you can configure them as follows:
* Configure the size of blackbox
* @code
* qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024*10);
* @endcode
*
* Make logging to file threaded:
* @code
* qb_log_ctl(mytarget, QB_LOG_CONF_THREADED, QB_TRUE);
* @endcode
*
* To workaround your syslog daemon filtering all messages > LOG_INFO
* @code
* qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP,
* LOG_INFO - LOG_DEBUG);
* @endcode
*
* @par Filtering messages.
* To have more power over what log messages go to which target you can apply
* filters to the targets. What happens is the desired callsites have the
* correct bit set. Then when the log message is generated it gets sent to the
* targets based on which bit is set in the callsite's "target" bitmap.
* Messages can be filtered based on the:
* -# filename + priority
* -# function name + priority
* -# format string + priority
*
* So to make all logs from evil_fnunction() go to stderr do the following:
* @code
* qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
* QB_LOG_FILTER_FUNCTION, "evil_fnunction", LOG_TRACE);
* @endcode
*
* So to make all logs from totem* (with a priority <= LOG_INFO) go to stderr do the following:
* @code
* qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
* QB_LOG_FILTER_FILE, "totem", LOG_INFO);
* @endcode
*
* So to make all logs with the substring "ringbuffer" go to stderr do the following:
* @code
* qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
* QB_LOG_FILTER_FORMAT, "ringbuffer", LOG_TRACE);
* @endcode
*
* @par Threaded logging.
* To achieve non-blocking logging you can use threaded logging. So any
* calls to write() or syslog() will not hold up your program.
*
* Threaded logging use:
* @code
* main() {
* qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
* qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_THREADED, QB_TRUE);
* // ...
* daemonize();
* // call this after you fork()
* qb_log_thread_start();
* // ...
* qb_log(LOG_WARNING, "watch out");
* // ...
* qb_log_fini();
* }
* @endcode
*
* @par A blackbox for in-field diagnosis.
* This stores log messages in a ringbuffer so they can be written to
* file if the program crashes (you will need to catch SIGSEGV). These
* can then be easily printed out later.
*
* @note the blackbox is not enabled by default.
*
* Blackbox usage:
* @code
*
* static void sigsegv_handler(int sig)
* {
* (void)signal (SIGSEGV, SIG_DFL);
* qb_log_blackbox_write_to_file("simple-log.fdata");
* qb_log_fini();
* raise(SIGSEGV);
* }
*
* main() {
*
* signal(SIGSEGV, sigsegv_handler);
*
* qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
* qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
* QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
* qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024*10);
* qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
* // ...
* qb_log(LOG_WARNING, "watch out");
* // ...
* qb_log_fini();
* }
* @endcode
*
* @par Tagging messages.
* You can tag messages using the second argument to qb_logt() or
* by using qb_log_filter_ctl().
* This can be used to add feature or sub-system information to the logs.
*
* @code
* const char* my_tags_stringify(uint32_t tags) {
* if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT) {
* return "libqb";
* } else if (tags == 3) {
* return "three";
* } else {
* return "MAIN";
* }
* }
* main() {
* // ...
* qb_log_tags_stringify_fn_set(my_tags_stringify);
* qb_log_format_set(QB_LOG_STDERR, "[%5g] %p %b");
* // ...
* qb_logt(LOG_INFO, 3, "hello");
* qb_logt(LOG_INFO, 0, "hello");
* }
* @endcode
* The code above will produce:
* @code
* [libqb] some message
* [three] info hello
* [MAIN ] info hello
* @endcode
*/
#undef LOG_TRACE
#define LOG_TRACE (LOG_DEBUG + 1)
typedef const char *(*qb_log_tags_stringify_fn)(uint32_t tags);
/**
* An instance of this structure is created in a special
* ELF section at every dynamic debug callsite. At runtime,
* the special section is treated as an array of these.
*/
struct qb_log_callsite {
const char *function;
const char *filename;
const char *format;
uint8_t priority;
uint32_t lineno;
uint32_t targets;
uint32_t tags;
} __attribute__((aligned(8)));
/* will be assigned by ld linker magic */
#ifdef QB_HAVE_ATTRIBUTE_SECTION
extern struct qb_log_callsite __start___verbose[];
extern struct qb_log_callsite __stop___verbose[];
#define QB_LOG_INIT_DATA(name) \
void name(void); \
void name(void) { assert(__start___verbose != __stop___verbose); } \
void __attribute__ ((constructor)) name(void);
#else
#define QB_LOG_INIT_DATA(name)
#endif
/**
* Internal function: use qb_log() or qb_logt()
*/
void qb_log_real_(struct qb_log_callsite *cs, ...);
-#define QB_LOG_TAG_EXTERNAL_BIT 30
-#define QB_LOG_TAG_EXTERNAL (1 << QB_LOG_TAG_EXTERNAL_BIT)
#define QB_LOG_TAG_LIBQB_MSG_BIT 31
#define QB_LOG_TAG_LIBQB_MSG (1 << QB_LOG_TAG_LIBQB_MSG_BIT)
/**
* This function is to import logs from other code (like libraries)
* that provide a callback with their logs.
*
* @note the performance of this will not impress you, as
* the filtering is done on each log message, not
* before hand. So try doing basic pre-filtering.
*
* @param function originating function name
* @param filename originating filename
* @param format format string
* @param priority this takes syslog priorities.
* @param lineno file line number
* @param tags This MUST have QB_LOG_EXTERNAL_TAG or'ed in
* so that it gets free'ed.
* @param msg the log message text
*/
void qb_log_from_external_source(const char *function,
const char *filename,
const char *format,
uint8_t priority,
uint32_t lineno,
uint32_t tags,
const char *msg);
/**
* This is the function to generate a log message if you want to
* manually add tags.
*
* @param priority this takes syslog priorities.
* @param tags this is a uint32_t that you can use with
* qb_log_tags_stringify_fn_set() to "tag" a log message
* with a feature or sub-system then you can use "%g"
* in the format specifer to print it out.
* @param fmt usual printf style format specifiers
* @param args usual printf style args
*/
#ifdef QB_HAVE_ATTRIBUTE_SECTION
#define qb_logt(priority, tags, fmt, args...) do { \
static struct qb_log_callsite descriptor \
__attribute__((section("__verbose"), aligned(8))) = \
{ __func__, __FILE__, fmt, priority, __LINE__, 0, tags }; \
qb_log_real_(&descriptor, ##args); \
} while(0)
#else
#define qb_logt(priority, tags, fmt, args...) do { \
char _log_buf_[256]; \
snprintf(_log_buf_, 256, fmt, ##args); \
qb_log_from_external_source( __func__, __FILE__, fmt, priority, __LINE__, tags, _log_buf_); \
} while(0)
#endif /* QB_HAVE_ATTRIBUTE_SECTION */
/**
* This is the main function to generate a log message.
*
* @param priority this takes syslog priorities.
* @param fmt usual printf style format specifiers
* @param args usual printf style args
*/
#define qb_log(priority, fmt, args...) qb_logt(priority, 0, fmt, ##args)
/**
* This is similar to perror except it goes into the logging system.
*
* @param priority this takes syslog priorities.
* @param fmt usual printf style format specifiers
* @param args usual printf style args
*/
#ifndef S_SPLINT_S
#define qb_perror(priority, fmt, args...) do { \
const char *err = strerror(errno); \
qb_logt(priority, 0, fmt ": %s (%d)", ##args, err, errno); \
} while(0)
#else
#define qb_perror
#endif
+
+#define qb_enter() qb_log(LOG_TRACE, "entering %s()", __func__)
+#define qb_leave() qb_log(LOG_TRACE, "leaving %s()", __func__)
+
#define QB_LOG_SYSLOG 0
#define QB_LOG_STDERR 1
#define QB_LOG_BLACKBOX 2
enum qb_log_conf {
QB_LOG_CONF_ENABLED,
QB_LOG_CONF_FACILITY,
QB_LOG_CONF_DEBUG,
QB_LOG_CONF_SIZE,
QB_LOG_CONF_THREADED,
QB_LOG_CONF_PRIORITY_BUMP,
};
enum qb_log_filter_type {
QB_LOG_FILTER_FILE,
QB_LOG_FILTER_FUNCTION,
QB_LOG_FILTER_FORMAT,
};
enum qb_log_filter_conf {
QB_LOG_FILTER_ADD,
QB_LOG_FILTER_REMOVE,
QB_LOG_FILTER_CLEAR_ALL,
QB_LOG_TAG_SET,
QB_LOG_TAG_CLEAR,
QB_LOG_TAG_CLEAR_ALL,
};
/**
* Init the logging system.
*
* @param name will be passed into openlog()
* @param facility default for all new targets.
* @param priority a basic filter with this priority will be added.
*/
void qb_log_init(const char *name,
int32_t facility,
uint8_t priority);
/**
* Logging system finalization function.
*
* It releases any shared memory.
* Stops the logging thread if running.
* Flushes the last message to their destinations.
*/
void qb_log_fini(void);
/**
* If you are using dynamically loadable modules via dlopen() and
* you load them after qb_log_init() then after you load the module
* you will need to do the following to get the filters to work
* in that module.
* @code
* _start = dlsym (dl_handle, "__start___verbose");
* _stop = dlsym (dl_handle, "__stop___verbose");
* qb_log_callsites_register(_start, _stop);
* @endcode
*/
void qb_log_callsites_register(struct qb_log_callsite *_start, struct qb_log_callsite *_stop);
/**
* Dump the callsite info to stdout.
*/
void qb_log_callsites_dump(void);
/**
* Main logging control function.
*
* @param t QB_LOG_SYSLOG, QB_LOG_STDERR or result from qb_log_file_open()
* @param c what to configure
* @param arg the new value
* @see qb_log_conf
* @retval -errno on error
* @retval 0 on success
*/
int32_t qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg);
/**
* This allows you modify the 'tags' and 'targets' callsite fields at runtime.
*/
int32_t qb_log_filter_ctl(int32_t value, enum qb_log_filter_conf c,
enum qb_log_filter_type type, const char * text,
uint8_t priority);
/**
* Set the callback to map the 'tags' bit map to a string.
*/
void qb_log_tags_stringify_fn_set(qb_log_tags_stringify_fn fn);
/**
* Set the format specifiers.
*
* %n FUNCTION NAME
* %f FILENAME
* %l FILELINE
* %p PRIORITY
* %t TIMESTAMP
* %b BUFFER
* %g TAGS
*
* any number between % and character specify field length to pad or chop
*/
void qb_log_format_set(int32_t t, const char* format);
/**
* Open a log file.
*
* @retval -errno on error
* @retval 3 to 31 (to be passed into other qb_log_* functions)
*/
int32_t qb_log_file_open(const char *filename);
/**
* Close a log file and release is resources.
*/
void qb_log_file_close(int32_t t);
/**
* Start the logging pthread.
*/
void qb_log_thread_start(void);
/**
* Write the blackbox to file.
*/
ssize_t qb_log_blackbox_write_to_file(const char *filename);
/**
* Read the blackbox for file and print it out.
*/
void qb_log_blackbox_print_from_file(const char* filename);
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif /* __cplusplus */
/* *INDENT-ON* */
#endif /* QB_LOG_H_DEFINED */
diff --git a/tests/check_log.c b/tests/check_log.c
index 1665636..470f655 100644
--- a/tests/check_log.c
+++ b/tests/check_log.c
@@ -1,422 +1,424 @@
/*
* Copyright (c) 2011 Red Hat, Inc.
*
* All rights reserved.
*
* Author: Angus Salkeld <asalkeld@redhat.com>
*
* This file is part of libqb.
*
* libqb is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* libqb is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libqb. If not, see <http://www.gnu.org/licenses/>.
*/
#include "os_base.h"
#include <pthread.h>
#include <check.h>
#include <qb/qbdefs.h>
#include <qb/qbutil.h>
#include <qb/qblog.h>
START_TEST(test_log_stupid_inputs)
{
int32_t rc;
/* shouldn't crash with out an init() */
qb_log_fini();
/* not init'ed */
rc = qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "bla", LOG_TRACE);
ck_assert_int_eq(rc, -EINVAL);
rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 2000);
ck_assert_int_eq(rc, -EINVAL);
qb_log_init("test", LOG_USER, LOG_DEBUG);
/* non-opened log file */
rc = qb_log_filter_ctl(21, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "bla", LOG_TRACE);
ck_assert_int_eq(rc, -EBADF);
rc = qb_log_ctl(21, QB_LOG_CONF_PRIORITY_BUMP, -1);
ck_assert_int_eq(rc, -EBADF);
/* target < 0 or >= 32 */
rc = qb_log_filter_ctl(41, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "bla", LOG_TRACE);
ck_assert_int_eq(rc, -EBADF);
rc = qb_log_ctl(-1, QB_LOG_CONF_PRIORITY_BUMP, -1);
ck_assert_int_eq(rc, -EBADF);
/* crap values to filter_ctl() */
rc = qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "bla", 45);
ck_assert_int_eq(rc, -EINVAL);
rc = qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, NULL, LOG_INFO);
ck_assert_int_eq(rc, -EINVAL);
rc = qb_log_filter_ctl(QB_LOG_SYSLOG, 56,
QB_LOG_FILTER_FILE, "boja", LOG_INFO);
ck_assert_int_eq(rc, -EINVAL);
/* crap values to ctl() */
rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, -2000);
ck_assert_int_eq(rc, -EINVAL);
rc = qb_log_ctl(QB_LOG_BLACKBOX, 67, 2000);
ck_assert_int_eq(rc, -EINVAL);
rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_SIZE, 2000);
ck_assert_int_eq(rc, -ENOSYS);
}
END_TEST
#define TEST_BUF_SIZE 1024
static char test_buf[TEST_BUF_SIZE];
static int32_t test_priority;
static int32_t num_msgs;
/*
* to test that we get what we expect.
*/
void syslog(int priority, const char *format, ...)
{
va_list ap;
va_start(ap, format);
vsnprintf(test_buf, TEST_BUF_SIZE, format, ap);
va_end(ap);
test_priority = priority;
num_msgs++;
}
static void log_it_please(void)
{
+ qb_enter();
qb_log(LOG_TRACE, "A:%d B:%d C:%d", 1, 2, 3);
qb_log(LOG_DEBUG, "A:%d B:%d C:%d", 1, 2, 3);
qb_log(LOG_INFO, "A:%d B:%d C:%d", 1, 2, 3);
qb_log(LOG_NOTICE, "A:%d B:%d C:%d", 1, 2, 3);
qb_log(LOG_WARNING, "A:%d B:%d C:%d", 1, 2, 3);
qb_log(LOG_ERR, "A:%d B:%d C:%d", 1, 2, 3);
+ qb_leave();
}
START_TEST(test_log_basic)
{
qb_log_init("test", LOG_USER, LOG_EMERG);
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_CLEAR_ALL,
QB_LOG_FILTER_FILE, "*", LOG_EMERG);
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FORMAT, "Angus", LOG_WARNING);
qb_log_format_set(QB_LOG_SYSLOG, "%b");
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
memset(test_buf, 0, sizeof(test_buf));
test_priority = 0;
num_msgs = 0;
/*
* test filtering by format
*/
qb_log(LOG_INFO, "Hello Angus, how are you?");
qb_log(LOG_WARNING, "Hello Steven, how are you?");
qb_log(LOG_ERR, "Hello Andrew, how are you?");
qb_log(LOG_ERR, "Hello Angus, how are you?");
qb_log(LOG_EMERG, "Hello Anna, how are you?");
ck_assert_int_eq(test_priority, LOG_ERR);
ck_assert_int_eq(num_msgs, 1);
ck_assert_str_eq(test_buf, "Hello Angus, how are you?");
/*
* test filtering by function
*/
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_CLEAR_ALL,
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FUNCTION, "log_it_please", LOG_WARNING);
num_msgs = 0;
qb_log(LOG_ERR, "try if you: log_it_please()");
log_it_please();
ck_assert_int_eq(num_msgs, 2);
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_REMOVE,
QB_LOG_FILTER_FUNCTION, "log_it_please", LOG_WARNING);
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FUNCTION, __func__, LOG_DEBUG);
num_msgs = 0;
log_it_please();
ck_assert_int_eq(num_msgs, 0);
qb_log(LOG_DEBUG, "try if you: log_it_please()");
ck_assert_int_eq(num_msgs, 1);
}
END_TEST
static const char *_test_tags_stringify(uint32_t tags)
{
if (tags == 1) {
return "ONE";
} else if (tags == 8) {
return "ATE";
} else {
return "ANY";
}
}
START_TEST(test_log_format)
{
qb_log_init("test", LOG_USER, LOG_DEBUG);
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
qb_log_format_set(QB_LOG_SYSLOG, "%p %f %b");
qb_log(LOG_DEBUG, "Angus");
ck_assert_str_eq(test_buf, "debug check_log.c Angus");
qb_log(LOG_INFO, "Angus");
ck_assert_str_eq(test_buf, "info check_log.c Angus");
qb_log(LOG_NOTICE, "Angus");
ck_assert_str_eq(test_buf, "notice check_log.c Angus");
qb_log(LOG_WARNING, "Angus");
ck_assert_str_eq(test_buf, "warning check_log.c Angus");
qb_log(LOG_ERR, "Angus");
ck_assert_str_eq(test_buf, "error check_log.c Angus");
qb_log(LOG_CRIT, "Angus");
ck_assert_str_eq(test_buf, "crit check_log.c Angus");
qb_log(LOG_ALERT, "Angus");
ck_assert_str_eq(test_buf, "alert check_log.c Angus");
qb_log(LOG_EMERG, "Angus");
ck_assert_str_eq(test_buf, "emerg check_log.c Angus");
qb_log_tags_stringify_fn_set(_test_tags_stringify);
qb_log_format_set(QB_LOG_SYSLOG, "%g %b");
qb_logt(LOG_INFO, 0, "Angus");
ck_assert_str_eq(test_buf, "ANY Angus");
qb_logt(LOG_INFO, 1, "Angus");
ck_assert_str_eq(test_buf, "ONE Angus");
qb_logt(LOG_INFO, 5, "Angus");
ck_assert_str_eq(test_buf, "ANY Angus");
qb_logt(LOG_INFO, 8, "Angus");
ck_assert_str_eq(test_buf, "ATE Angus");
}
END_TEST
START_TEST(test_log_enable)
{
qb_log_init("test", LOG_USER, LOG_DEBUG);
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
qb_log_format_set(QB_LOG_SYSLOG, "%b");
/* enabled by default */
qb_log(LOG_DEBUG, "Hello");
ck_assert_str_eq(test_buf, "Hello");
num_msgs = 0;
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
qb_log(LOG_DEBUG, "Goodbye");
ck_assert_int_eq(num_msgs, 0);
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
qb_log(LOG_DEBUG, "Hello again");
ck_assert_int_eq(num_msgs, 1);
ck_assert_str_eq(test_buf, "Hello again");
}
END_TEST
START_TEST(test_log_bump)
{
qb_log_init("test", LOG_USER, LOG_DEBUG);
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
qb_log_format_set(QB_LOG_SYSLOG, "%b");
qb_log(LOG_DEBUG, "Hello");
ck_assert_int_eq(test_priority, LOG_DEBUG);
qb_log(LOG_INFO, "Hello");
ck_assert_int_eq(test_priority, LOG_INFO);
qb_log(LOG_CRIT, "Hello");
ck_assert_int_eq(test_priority, LOG_CRIT);
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP, -1);
qb_log(LOG_DEBUG, "Hello");
ck_assert_int_eq(test_priority, LOG_INFO);
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP, -2);
qb_log(LOG_DEBUG, "Hello");
ck_assert_int_eq(test_priority, LOG_NOTICE);
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP, 0);
qb_log(LOG_DEBUG, "Hello");
ck_assert_int_eq(test_priority, LOG_DEBUG);
}
END_TEST
#define ITERATIONS 100000
static void *thr_send_logs_2(void *ctx)
{
int32_t i;
printf("%s\n", __func__);
for (i = 0; i < ITERATIONS; i++) {
qb_log(LOG_INFO, "bla bla");
qb_log(LOG_INFO, "blue blue");
qb_log(LOG_INFO, "bra bra");
qb_log(LOG_INFO, "bro bro");
qb_log(LOG_INFO, "brown brown");
qb_log(LOG_INFO, "booo booo");
qb_log(LOG_INFO, "bogus bogus");
qb_log(LOG_INFO, "bungu bungu");
}
return (NULL);
}
static void *thr_send_logs_1(void *ctx)
{
int32_t i;
printf("%s\n", __func__);
for (i = 0; i < ITERATIONS; i++) {
qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
__LINE__, 0, "foo soup");
qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
__LINE__, 0, "fungus soup");
qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
__LINE__, 0, "fruity soup");
qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
__LINE__, 0, "free soup");
qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
__LINE__, 0, "frot soup");
qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
__LINE__, 0, "fresh soup");
qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
__LINE__, 0, "fattening soup");
}
return (NULL);
}
#define THREADS 4
START_TEST(test_log_threads)
{
pthread_t threads[THREADS];
pthread_attr_t thread_attr[THREADS];
int32_t i;
int32_t rc;
int32_t lf;
void *retval;
qb_log_init("test", LOG_USER, LOG_DEBUG);
lf = qb_log_file_open("threads.log");
rc = qb_log_filter_ctl(lf, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE,
__FILE__, LOG_DEBUG);
ck_assert_int_eq(rc, 0);
qb_log_format_set(lf, "[%p] [%l] %b");
rc = qb_log_ctl(lf, QB_LOG_CONF_ENABLED, QB_TRUE);
ck_assert_int_eq(rc, 0);
rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
ck_assert_int_eq(rc, 0);
for (i = 0; i < THREADS/2; i++) {
pthread_attr_init(&thread_attr[i]);
pthread_attr_setdetachstate(&thread_attr[i],
PTHREAD_CREATE_JOINABLE);
pthread_create(&threads[i], &thread_attr[i],
thr_send_logs_1, NULL);
}
for (i = THREADS/2; i < THREADS; i++) {
pthread_attr_init(&thread_attr[i]);
pthread_attr_setdetachstate(&thread_attr[i],
PTHREAD_CREATE_JOINABLE);
pthread_create(&threads[i], &thread_attr[i],
thr_send_logs_2, NULL);
}
for (i = 0; i < THREADS; i++) {
pthread_join(threads[i], &retval);
}
}
END_TEST
START_TEST(test_log_long_msg)
{
qb_log_init("test", LOG_USER, LOG_DEBUG);
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
qb_log_format_set(QB_LOG_SYSLOG, "%b");
qb_log(LOG_ERR, "QMF Agent Initialized: broker=localhost:49000 interval=5 storeFile=.cloudpolicyengine-data-cpe name=cloudpolicyengine.org:cpe:04eabb39-89cf-47dd-9d14-7e77d864be07 QMF Agent Initialized: broker=localhost:49000 interval=5 storeFile=.cloudpolicyengine-data-cpe name=cloudpolicyengine.org:cpe:04eabb39-89cf-47dd-9d14-7e77d864be07 QMF Agent Initialized: broker=localhost:49000 interval=5 storeFile=.cloudpolicyengine-data-cpe name=cloudpolicyengine.org:cpe:04eabb39-89cf-47dd-9d14-7e77d864be07");
}
END_TEST
static Suite *log_suite(void)
{
TCase *tc;
Suite *s = suite_create("logging");
tc = tcase_create("limits");
tcase_add_test(tc, test_log_stupid_inputs);
suite_add_tcase(s, tc);
tc = tcase_create("basic");
tcase_add_test(tc, test_log_basic);
suite_add_tcase(s, tc);
tc = tcase_create("format");
tcase_add_test(tc, test_log_format);
suite_add_tcase(s, tc);
tc = tcase_create("enable");
tcase_add_test(tc, test_log_enable);
suite_add_tcase(s, tc);
tc = tcase_create("bump");
tcase_add_test(tc, test_log_bump);
suite_add_tcase(s, tc);
tc = tcase_create("threads");
tcase_add_test(tc, test_log_threads);
tcase_set_timeout(tc, 30);
suite_add_tcase(s, tc);
tc = tcase_create("long_msg");
tcase_add_test(tc, test_log_long_msg);
suite_add_tcase(s, tc);
return s;
}
static void libqb_log_fn(const char *file_name,
int32_t file_line, int32_t severity, const char *msg)
{
printf("libqb: %s:%d %s\n", file_name, file_line, msg);
}
int32_t main(void)
{
int32_t number_failed;
Suite *s = log_suite();
SRunner *sr = srunner_create(s);
qb_util_set_log_function(libqb_log_fn);
srunner_run_all(sr, CK_VERBOSE);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/tests/simple-log.c b/tests/simple-log.c
index 898a9c1..9dd2910 100644
--- a/tests/simple-log.c
+++ b/tests/simple-log.c
@@ -1,193 +1,198 @@
/*
* Copyright (c) 2011 Red Hat, Inc.
*
* All rights reserved.
*
* Author: Angus Salkeld <asalkeld@redhat.com>
*
* libqb is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* libqb is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libqb. If not, see <http://www.gnu.org/licenses/>.
*/
#include "os_base.h"
#include <signal.h>
#include <syslog.h>
#include <qb/qbdefs.h>
#include <qb/qblog.h>
#define MY_TAG_ONE (1)
#define MY_TAG_TWO (1 << 1)
#define MY_TAG_THREE (1 << 2)
-static void func_one(void) {
+static void func_one(void)
+{
FILE* fd;
+
+ qb_enter();
qb_logt(LOG_DEBUG, MY_TAG_TWO, "arf arf?");
qb_logt(LOG_CRIT, MY_TAG_THREE, "arrrg!");
qb_logt(LOG_ERR, MY_TAG_THREE, "oops, I did it again");
qb_log(LOG_INFO, "are you aware ...");
fd = fopen("/nothing.txt", "r+");
if (fd == NULL) {
qb_perror(LOG_ERR, "can't open(\"/nothing.txt\")");
}
+ qb_leave();
}
-static void func_two(void) {
+static void func_two(void)
+{
+ qb_enter();
qb_logt(LOG_DEBUG, 0, "arf arf?");
qb_logt(LOG_CRIT, MY_TAG_ONE, "arrrg!");
qb_log(LOG_ERR, "oops, I did it again");
qb_logt(LOG_INFO, MY_TAG_THREE, "are you aware ...");
+ qb_leave();
}
static void show_usage(const char *name)
{
printf("usage: \n");
printf("%s <options>\n", name);
printf("\n");
printf(" options:\n");
printf("\n");
printf(" -v verbose\n");
printf(" -t threaded logging\n");
printf(" -e log to stderr\n");
printf(" -b log to blackbox\n");
printf(" -f <filename> log to a file\n");
printf(" -h show this help text\n");
printf("\n");
}
static int32_t do_blackbox = QB_FALSE;
static int32_t do_threaded = QB_FALSE;
static void sigsegv_handler(int sig)
{
(void)signal (SIGSEGV, SIG_DFL);
qb_log_fini();
if (do_blackbox) {
qb_log_blackbox_write_to_file("simple-log.fdata");
}
raise(SIGSEGV);
}
static const char *my_tags_stringify(uint32_t tags)
{
if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT)) {
return "libqb";
} else if (qb_bit_is_set(tags, 0)) {
return "ONE";
} else if (qb_bit_is_set(tags, 1)) {
return "TWO";
} else if (qb_bit_is_set(tags, 2)) {
return "THREE";
} else {
return "MAIN";
}
}
int32_t main(int32_t argc, char *argv[])
{
const char *options = "vhtebdf:";
int32_t opt;
int32_t priority = LOG_WARNING;
int32_t do_stderr = QB_FALSE;
int32_t do_dump_blackbox = QB_FALSE;
char *logfile = NULL;
int32_t log_fd = -1;
while ((opt = getopt(argc, argv, options)) != -1) {
switch (opt) {
case 'd':
do_dump_blackbox = QB_TRUE;
break;
case 't':
do_threaded = QB_TRUE;
break;
case 'e':
do_stderr = QB_TRUE;
break;
case 'b':
do_blackbox = QB_TRUE;
break;
case 'f':
logfile = optarg;
break;
case 'v':
priority++;
break;
case 'h':
default:
show_usage(argv[0]);
exit(0);
break;
}
}
if (do_dump_blackbox) {
qb_log_blackbox_print_from_file("simple-log.fdata");
exit(0);
}
signal(SIGSEGV, sigsegv_handler);
qb_log_init("simple-log", LOG_USER, LOG_INFO);
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_THREADED, do_threaded);
qb_log_tags_stringify_fn_set(my_tags_stringify);
if (do_stderr) {
- qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
- QB_LOG_FILTER_FUNCTION, "func_one", LOG_DEBUG);
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, __FILE__, priority);
qb_log_format_set(QB_LOG_STDERR, "%4g: %f:%l [%p] %b");
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
}
if (do_blackbox) {
qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 4096);
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_THREADED, QB_FALSE);
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
}
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_format_set(log_fd, "%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);
}
if (do_threaded) {
qb_log_thread_start();
}
qb_log(LOG_DEBUG, "hello");
qb_log(LOG_INFO, "this is an info");
qb_log(LOG_NOTICE, "hello - notice?");
func_one();
func_two();
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
qb_log(LOG_WARNING, "no syslog");
qb_log(LOG_ERR, "no syslog");
#if 0
// test blackbox
logfile = NULL;
logfile[5] = 'a';
#endif
if (do_blackbox) {
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
}
qb_log_fini();
return 0;
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Feb 27, 5:03 AM (1 d, 17 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1466192
Default Alt Text
(31 KB)

Event Timeline