mirror of
https://salsa.debian.org/ha-team/libqb
synced 2026-01-07 02:26:49 +00:00
Looks like these are not accepted with splint checker. Also fix some other minor type -- print format specifier discrepancies. Signed-off-by: Jan Pokorný <jpokorny@redhat.com>
915 lines
26 KiB
C
915 lines
26 KiB
C
/*
|
|
* Copyright (c) 2011-2015 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_common.h"
|
|
|
|
#include <qb/qbdefs.h>
|
|
#include <qb/qbutil.h>
|
|
#include <qb/qblog.h>
|
|
|
|
#include "_syslog_override.h"
|
|
|
|
extern size_t qb_vsnprintf_serialize(char *serialize, size_t max_len, const char *fmt, va_list ap);
|
|
extern size_t qb_vsnprintf_deserialize(char *string, size_t strlen, const char *buf);
|
|
|
|
|
|
static void
|
|
format_this(char *out, const char *fmt, ...)
|
|
{
|
|
char buf[QB_LOG_MAX_LEN];
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
qb_vsnprintf_serialize(buf, QB_LOG_MAX_LEN, fmt, ap);
|
|
qb_vsnprintf_deserialize(out, QB_LOG_MAX_LEN, buf);
|
|
va_end(ap);
|
|
}
|
|
|
|
static void
|
|
format_this_up_to(char *out, size_t max_len, const char *fmt, ...)
|
|
{
|
|
char buf[QB_LOG_MAX_LEN];
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
qb_vsnprintf_serialize(buf, max_len, fmt, ap);
|
|
qb_vsnprintf_deserialize(out, QB_LOG_MAX_LEN, buf);
|
|
va_end(ap);
|
|
}
|
|
|
|
START_TEST(test_va_serialize)
|
|
{
|
|
char buf[QB_LOG_MAX_LEN];
|
|
char cmp_buf[QB_LOG_MAX_LEN];
|
|
|
|
format_this(buf, "one line");
|
|
ck_assert_str_eq(buf, "one line");
|
|
|
|
format_this(buf, "p1:%p, p2:%p", format_this, buf);
|
|
snprintf(cmp_buf, QB_LOG_MAX_LEN, "p1:%p, p2:%p", format_this, buf);
|
|
ck_assert_str_eq(buf, cmp_buf);
|
|
|
|
format_this(buf, "s1:%s, s2:%s", "Yes", "Never");
|
|
ck_assert_str_eq(buf, "s1:Yes, s2:Never");
|
|
|
|
format_this(buf, "s1:%s, s2:%s", "Yes", "Never");
|
|
ck_assert_str_eq(buf, "s1:Yes, s2:Never");
|
|
|
|
format_this(buf, "d1:%d, d2:%5i, d3:%04i", 23, 37, 84);
|
|
ck_assert_str_eq(buf, "d1:23, d2: 37, d3:0084");
|
|
|
|
format_this(buf, "f1:%.5f, f2:%.2f", 23.34109, 23.34109);
|
|
ck_assert_str_eq(buf, "f1:23.34109, f2:23.34");
|
|
|
|
format_this(buf, "%zd", (size_t)13140964);
|
|
ck_assert_str_eq(buf, "13140964");
|
|
format_this(buf, "%jd", (intmax_t)30627823);
|
|
ck_assert_str_eq(buf, "30627823");
|
|
format_this(buf, "%td", buf-cmp_buf);
|
|
snprintf(cmp_buf, QB_LOG_MAX_LEN, "%td", buf-cmp_buf);
|
|
ck_assert_str_eq(buf, cmp_buf);
|
|
|
|
format_this(buf, ":%s:", "Hello, world!");
|
|
ck_assert_str_eq(buf, ":Hello, world!:");
|
|
format_this(buf, ":%15s:", "Hello, world!");
|
|
ck_assert_str_eq(buf, ": Hello, world!:");
|
|
format_this(buf, ":%.10s:", "Hello, world!");
|
|
ck_assert_str_eq(buf, ":Hello, wor:");
|
|
format_this(buf, ":%-10s:", "Hello, world!");
|
|
ck_assert_str_eq(buf, ":Hello, world!:");
|
|
format_this(buf, ":%-15s:", "Hello, world!");
|
|
ck_assert_str_eq(buf, ":Hello, world! :");
|
|
format_this(buf, ":%.15s:", "Hello, world!");
|
|
ck_assert_str_eq(buf, ":Hello, world!:");
|
|
format_this(buf, ":%15.10s:", "Hello, world!");
|
|
ck_assert_str_eq(buf, ": Hello, wor:");
|
|
format_this(buf, ":%-15.10s:", "Hello, world!");
|
|
ck_assert_str_eq(buf, ":Hello, wor :");
|
|
|
|
format_this(buf, ":%*d:", 8, 96);
|
|
ck_assert_str_eq(buf, ": 96:");
|
|
|
|
format_this_up_to(buf, 11, "123456789____");
|
|
ck_assert_str_eq(buf, "123456789_");
|
|
|
|
format_this(buf, "Client %s.%.9s wants to fence (%s) '%s' with device '%s'",
|
|
"bla", "foooooooooooooooooo",
|
|
"action", "target", "hoop");
|
|
|
|
ck_assert_str_eq(buf,
|
|
"Client bla.foooooooo wants to fence (action) 'target' with device 'hoop'");
|
|
|
|
format_this(buf, "Node %s now has process list: %.32x (was %.32x)",
|
|
"18builder", 2, 0);
|
|
ck_assert_str_eq(buf, "Node 18builder now has process list: 00000000000000000000000000000002 (was 00000000000000000000000000000000)");
|
|
|
|
|
|
}
|
|
END_TEST
|
|
|
|
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(LOG_INFO, "not init'd");
|
|
|
|
qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
|
|
__LINE__, 0, "also not init'd");
|
|
|
|
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, 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
|
|
|
|
static char test_buf[QB_LOG_MAX_LEN];
|
|
static uint8_t test_priority;
|
|
static int32_t num_msgs;
|
|
|
|
/*
|
|
* to test that we get what we expect.
|
|
*/
|
|
static void
|
|
_test_logger(int32_t t,
|
|
struct qb_log_callsite *cs,
|
|
time_t timestamp, const char *msg)
|
|
{
|
|
test_buf[0] = '\0';
|
|
qb_log_target_format(t, cs, timestamp, msg, test_buf);
|
|
test_priority = cs->priority;
|
|
|
|
num_msgs++;
|
|
}
|
|
|
|
static void log_also(void)
|
|
{
|
|
qb_log(LOG_INFO, "yes please");
|
|
}
|
|
|
|
static void log_and_this_too(void)
|
|
{
|
|
qb_log(LOG_INFO, "this too please");
|
|
}
|
|
|
|
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);
|
|
errno = EEXIST;
|
|
qb_perror(LOG_WARNING, "bogus error");
|
|
errno = 0;
|
|
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();
|
|
}
|
|
|
|
|
|
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;
|
|
int32_t rc;
|
|
|
|
qb_log_init("test", LOG_USER, LOG_EMERG);
|
|
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
|
|
|
t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
|
|
rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FORMAT, "Angus", LOG_WARNING);
|
|
ck_assert_int_eq(rc, 0);
|
|
qb_log_format_set(t, "%b");
|
|
rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
|
|
ck_assert_int_eq(rc, 0);
|
|
|
|
/* captures last log */
|
|
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 file regex
|
|
*/
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
|
|
QB_LOG_FILTER_FORMAT, "*", LOG_TRACE);
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FILE_REGEX, "^fakefile*", LOG_DEBUG);
|
|
|
|
num_msgs = 0;
|
|
qb_log_from_external_source(__func__, "fakefile_logging", "%s bla", LOG_INFO,
|
|
56, 0, "filename/lineno");
|
|
qb_log_from_external_source(__func__, "do_not_log_fakefile_logging", "%s bla", LOG_INFO,
|
|
56, 0, "filename/lineno");
|
|
ck_assert_int_eq(num_msgs, 1);
|
|
|
|
/*
|
|
* test filtering by format regex
|
|
*/
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
|
|
QB_LOG_FILTER_FORMAT, "*", LOG_TRACE);
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FORMAT_REGEX, "^one", LOG_WARNING);
|
|
|
|
num_msgs = 0;
|
|
qb_log(LOG_INFO, "one two three");
|
|
qb_log(LOG_ERR, "testing one two three");
|
|
qb_log(LOG_WARNING, "one two three");
|
|
qb_log(LOG_ERR, "one two three");
|
|
qb_log(LOG_EMERG, "one two three");
|
|
ck_assert_int_eq(num_msgs, 3);
|
|
|
|
/*
|
|
* test filtering by function and regex
|
|
*/
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
|
|
QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FUNCTION_REGEX, "^log_.*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, 3);
|
|
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_REMOVE,
|
|
QB_LOG_FILTER_FUNCTION_REGEX, "log_it_please", LOG_WARNING);
|
|
|
|
/*
|
|
* test filtering by function
|
|
*/
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
|
|
QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
|
qb_log_filter_ctl(t, 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, 3);
|
|
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_REMOVE,
|
|
QB_LOG_FILTER_FUNCTION, "log_it_please", LOG_WARNING);
|
|
qb_log_filter_ctl(t, 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);
|
|
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
|
|
QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FUNCTION,
|
|
"log_also,log_and_this_too",
|
|
LOG_DEBUG);
|
|
num_msgs = 0;
|
|
log_also();
|
|
log_and_this_too();
|
|
ck_assert_int_eq(num_msgs, 2);
|
|
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
|
|
QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FILE, "fakefile.c,"__FILE__",otherfakefile", LOG_DEBUG);
|
|
/*
|
|
* make sure we can pass in a null filename or function name.
|
|
*/
|
|
qb_log_from_external_source(__func__, NULL, "%s", LOG_INFO,
|
|
__LINE__, 0, "null filename");
|
|
qb_log_from_external_source(NULL, __FILE__, "%s", LOG_INFO,
|
|
__LINE__, 0, "null function");
|
|
|
|
/* check same file/lineno logs with different formats work
|
|
*/
|
|
num_msgs = 0;
|
|
qb_log_from_external_source(__func__, __FILE__, "%s bla", LOG_INFO,
|
|
56, 0, "filename/lineno");
|
|
ck_assert_int_eq(num_msgs, 1);
|
|
ck_assert_str_eq(test_buf, "filename/lineno bla");
|
|
|
|
num_msgs = 0;
|
|
qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
|
|
56, 0, "same filename/lineno");
|
|
ck_assert_int_eq(num_msgs, 1);
|
|
ck_assert_str_eq(test_buf, "same filename/lineno");
|
|
|
|
/* check filtering works on same file/lineno but different
|
|
* log level.
|
|
*/
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
|
|
QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FILE, __FILE__, LOG_INFO);
|
|
|
|
num_msgs = 0;
|
|
qb_log_from_external_source(__func__, __FILE__,
|
|
"same filename/lineno, this level %d",
|
|
LOG_INFO, 56, 0, LOG_INFO);
|
|
ck_assert_int_eq(num_msgs, 1);
|
|
ck_assert_str_eq(test_buf, "same filename/lineno, this level 6");
|
|
|
|
num_msgs = 0;
|
|
qb_log_from_external_source(__func__, __FILE__,
|
|
"same filename/lineno, this level %d",
|
|
LOG_DEBUG, 56, 0, LOG_DEBUG);
|
|
ck_assert_int_eq(num_msgs, 0);
|
|
}
|
|
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)
|
|
{
|
|
int32_t t;
|
|
/* following size/length related equation holds in the context of use:
|
|
strlen(cmp_str) = strlen(host_str) + X; X ~ 20 < sizeof(host_str) */
|
|
char host_str[256];
|
|
char cmp_str[2 * sizeof(host_str)];
|
|
|
|
qb_log_init("test", LOG_USER, LOG_DEBUG);
|
|
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
|
|
|
t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
|
|
qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
|
|
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
|
|
qb_log_format_set(t, "%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(t, "%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");
|
|
|
|
qb_log_format_set(t, "%-15f %b");
|
|
qb_log(LOG_WARNING, "Andrew");
|
|
ck_assert_str_eq(test_buf, " check_log.c Andrew");
|
|
|
|
qb_log_tags_stringify_fn_set(NULL);
|
|
|
|
gethostname(host_str, sizeof(host_str));
|
|
host_str[sizeof(host_str) - 1] = '\0';
|
|
|
|
qb_log_format_set(t, "%P %H %N %b");
|
|
qb_log(LOG_INFO, "Angus");
|
|
snprintf(cmp_str, sizeof(cmp_str), "%d %s test Angus", getpid(),
|
|
host_str);
|
|
ck_assert_str_eq(test_buf, cmp_str);
|
|
|
|
qb_log_format_set(t, "%3N %H %P %b");
|
|
qb_log(LOG_INFO, "Angus");
|
|
snprintf(cmp_str, sizeof(cmp_str), "tes %s %d Angus", host_str,
|
|
getpid());
|
|
ck_assert_str_eq(test_buf, cmp_str);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_log_enable)
|
|
{
|
|
int32_t t;
|
|
int32_t state;
|
|
|
|
qb_log_init("test", LOG_USER, LOG_DEBUG);
|
|
state = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_STATE_GET, 0);
|
|
ck_assert_int_eq(state, QB_LOG_STATE_ENABLED);
|
|
state = qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0);
|
|
ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
|
|
state = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0);
|
|
ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
|
|
|
|
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
|
state = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_STATE_GET, 0);
|
|
ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
|
|
|
|
t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
|
|
qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
|
|
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
|
|
qb_log_format_set(t, "%b");
|
|
|
|
qb_log(LOG_DEBUG, "Hello");
|
|
ck_assert_str_eq(test_buf, "Hello");
|
|
|
|
num_msgs = 0;
|
|
qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_FALSE);
|
|
qb_log(LOG_DEBUG, "Goodbye");
|
|
ck_assert_int_eq(num_msgs, 0);
|
|
qb_log_ctl(t, 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
|
|
|
|
#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)
|
|
{
|
|
int lpc;
|
|
int rc;
|
|
int i, max = 1000;
|
|
char *buffer = calloc(1, max);
|
|
|
|
qb_log_init("test", LOG_USER, LOG_DEBUG);
|
|
rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
|
ck_assert_int_eq(rc, 0);
|
|
rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024);
|
|
ck_assert_int_eq(rc, 0);
|
|
rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
|
|
ck_assert_int_eq(rc, 0);
|
|
rc = qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
|
ck_assert_int_eq(rc, 0);
|
|
|
|
for (lpc = 500; lpc < max; lpc++) {
|
|
lpc++;
|
|
for(i = 0; i < max; i++) {
|
|
buffer[i] = 'a' + (i % 10);
|
|
}
|
|
buffer[lpc%600] = 0;
|
|
qb_log(LOG_INFO, "Message %d %d - %s", lpc, lpc%600, buffer);
|
|
}
|
|
|
|
qb_log_blackbox_write_to_file("blackbox.dump");
|
|
qb_log_blackbox_print_from_file("blackbox.dump");
|
|
unlink("blackbox.dump");
|
|
qb_log_fini();
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_threaded_logging)
|
|
{
|
|
int32_t t;
|
|
int32_t rc;
|
|
|
|
qb_log_init("test", LOG_USER, LOG_EMERG);
|
|
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
|
|
|
t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
|
|
rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FILE, "*", LOG_INFO);
|
|
ck_assert_int_eq(rc, 0);
|
|
qb_log_format_set(t, "%b");
|
|
rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
|
|
ck_assert_int_eq(rc, 0);
|
|
rc = qb_log_ctl(t, QB_LOG_CONF_THREADED, QB_TRUE);
|
|
ck_assert_int_eq(rc, 0);
|
|
qb_log_thread_start();
|
|
|
|
memset(test_buf, 0, sizeof(test_buf));
|
|
test_priority = 0;
|
|
num_msgs = 0;
|
|
|
|
qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
|
|
qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
|
|
qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
|
|
qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
|
|
qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
|
|
qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
|
|
qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
|
|
qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
|
|
qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
|
|
qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
|
|
|
|
qb_log_fini();
|
|
|
|
ck_assert_int_eq(num_msgs, 10);
|
|
}
|
|
END_TEST
|
|
|
|
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
|
|
START_TEST(test_threaded_logging_bad_sched_params)
|
|
{
|
|
int32_t t;
|
|
int32_t rc;
|
|
|
|
qb_log_init("test", LOG_USER, LOG_EMERG);
|
|
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
|
|
|
t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
|
|
rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FILE, "*", LOG_INFO);
|
|
ck_assert_int_eq(rc, 0);
|
|
qb_log_format_set(t, "%b");
|
|
rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
|
|
ck_assert_int_eq(rc, 0);
|
|
rc = qb_log_ctl(t, QB_LOG_CONF_THREADED, QB_TRUE);
|
|
ck_assert_int_eq(rc, 0);
|
|
|
|
#if defined(SCHED_RR)
|
|
#define QB_SCHED SCHED_RR
|
|
#elif defined(SCHED_FIFO)
|
|
#define QB_SCHED SCHED_FIFO
|
|
#else
|
|
#define QB_SCHED (-1)
|
|
#endif
|
|
rc = qb_log_thread_priority_set(QB_SCHED, -1);
|
|
ck_assert_int_eq(rc, 0);
|
|
|
|
rc = qb_log_thread_start();
|
|
ck_assert_int_ne(rc, 0);
|
|
qb_log_fini();
|
|
}
|
|
END_TEST
|
|
#endif
|
|
|
|
START_TEST(test_extended_information)
|
|
{
|
|
int32_t t;
|
|
int32_t rc;
|
|
int extended;
|
|
|
|
qb_log_init("test", LOG_USER, LOG_DEBUG);
|
|
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
|
|
|
t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
|
|
_ck_assert_int(t, >, QB_LOG_STDOUT);
|
|
qb_log_format_set(t, "%b");
|
|
rc = qb_log_filter_fn_set(NULL);
|
|
ck_assert_int_eq(rc, 0);
|
|
rc = qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL, QB_LOG_FILTER_FILE,
|
|
"*", LOG_TRACE);
|
|
ck_assert_int_eq(rc, 0);
|
|
rc = qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL, QB_LOG_FILTER_FORMAT,
|
|
"*", LOG_TRACE);
|
|
ck_assert_int_eq(rc, 0);
|
|
rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FORMAT,
|
|
"*", LOG_TRACE);
|
|
ck_assert_int_eq(rc, 0);
|
|
rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
|
|
ck_assert_int_eq(rc, 0);
|
|
|
|
for (extended = QB_FALSE; extended <= QB_TRUE; ++extended) {
|
|
rc = qb_log_ctl(t, QB_LOG_CONF_EXTENDED, extended);
|
|
ck_assert_int_eq(rc, 0);
|
|
|
|
num_msgs = 0;
|
|
|
|
memset(test_buf, 0, sizeof(test_buf));
|
|
qb_log(LOG_ERR, "message with no extended information");
|
|
ck_assert_str_eq(test_buf, "message with no extended information");
|
|
|
|
memset(test_buf, 0, sizeof(test_buf));
|
|
qb_log(LOG_ERR, "message with empty extended information "QB_XS);
|
|
ck_assert_str_eq(test_buf, "message with empty extended information ");
|
|
|
|
memset(test_buf, 0, sizeof(test_buf));
|
|
qb_log(LOG_ERR, QB_XS" message with only extended information");
|
|
ck_assert_str_eq(test_buf, extended?
|
|
"| message with only extended information" : "");
|
|
|
|
memset(test_buf, 0, sizeof(test_buf));
|
|
qb_log(LOG_ERR, "message with extended information "QB_XS" (namely this)");
|
|
ck_assert_str_eq(test_buf, extended?
|
|
"message with extended information | (namely this)"
|
|
: "message with extended information ");
|
|
|
|
ck_assert_int_eq(num_msgs, (extended? 4 : 3));
|
|
}
|
|
qb_log_fini();
|
|
}
|
|
END_TEST
|
|
|
|
static const char *tagtest_stringify_tag(uint32_t tag)
|
|
{
|
|
static char buf[32];
|
|
sprintf(buf, "%5" PRIu32, tag);
|
|
return buf;
|
|
}
|
|
|
|
START_TEST(test_zero_tags)
|
|
{
|
|
int32_t rc;
|
|
int32_t t;
|
|
|
|
qb_log_init("test", LOG_USER, LOG_EMERG);
|
|
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
|
|
|
t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
|
|
rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FILE, "*", LOG_INFO);
|
|
ck_assert_int_eq(rc, 0);
|
|
|
|
qb_log_format_set(t, "[%g] %b");
|
|
qb_log_tags_stringify_fn_set(tagtest_stringify_tag);
|
|
rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
|
|
ck_assert_int_eq(rc, 0);
|
|
|
|
qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
|
|
QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
|
|
|
qb_log_from_external_source("function", "filename", "%s: %d", LOG_DEBUG, 356, 2, "testlog", 2);
|
|
ck_assert_str_eq(test_buf, "[ 2] testlog: 2");
|
|
|
|
qb_log_from_external_source("function", "filename", "%s: %d", LOG_DEBUG, 356, 0, "testlog", 0);
|
|
ck_assert_str_eq(test_buf, "[ 2] testlog: 0");
|
|
|
|
qb_log_fini();
|
|
|
|
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_syslog)
|
|
{
|
|
qb_log_init("flip", LOG_USER, LOG_INFO);
|
|
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
|
|
|
|
qb_log(LOG_ERR, "first as flip");
|
|
ck_assert_int_eq(_syslog_opened, 1);
|
|
ck_assert_str_eq(_syslog_ident, "flip");
|
|
|
|
qb_log_ctl2(QB_LOG_SYSLOG, QB_LOG_CONF_IDENT, QB_LOG_CTL2_S("flop"));
|
|
qb_log(LOG_ERR, "second as flop");
|
|
ck_assert_str_eq(_syslog_ident, "flop");
|
|
|
|
qb_log_fini();
|
|
}
|
|
END_TEST
|
|
|
|
static Suite *
|
|
log_suite(void)
|
|
{
|
|
TCase *tc;
|
|
Suite *s = suite_create("logging");
|
|
|
|
add_tcase(s, tc, test_va_serialize);
|
|
add_tcase(s, tc, test_log_stupid_inputs);
|
|
add_tcase(s, tc, test_log_basic);
|
|
add_tcase(s, tc, test_log_format);
|
|
add_tcase(s, tc, test_log_enable);
|
|
add_tcase(s, tc, test_log_threads, 360);
|
|
add_tcase(s, tc, test_log_long_msg);
|
|
add_tcase(s, tc, test_log_filter_fn);
|
|
add_tcase(s, tc, test_threaded_logging);
|
|
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
|
|
add_tcase(s, tc, test_threaded_logging_bad_sched_params);
|
|
#endif
|
|
add_tcase(s, tc, test_extended_information);
|
|
add_tcase(s, tc, test_zero_tags);
|
|
add_tcase(s, tc, test_syslog);
|
|
|
|
return s;
|
|
}
|
|
|
|
int32_t
|
|
main(void)
|
|
{
|
|
int32_t number_failed;
|
|
|
|
Suite *s = log_suite();
|
|
SRunner *sr = srunner_create(s);
|
|
|
|
srunner_run_all(sr, CK_VERBOSE);
|
|
number_failed = srunner_ntests_failed(sr);
|
|
srunner_free(sr);
|
|
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|