Feature: allow changing the identifier for syslog (+tests)

Original "qb_log_ctl" interface had to be extended for passing read-only
strings (new parameter), resulting in new "qb_log_ctl2" function, which
is what qb_log_ctl calls into with the new parameter set to NULL.
This ensures backward compatibility.

A new QB_LOG_CONF_IDENT configuration directive for the mentioned
interface is added with a goal to set new internal identifier
that is, notably, used for syslog sink.  This allows for switching
the identification without a need to reinitialize logging subsystem,
akin to changing target logging facility.

Also a brand new concept of testing syslog sink in particular is
introduced (finally).  During initial trial&error stage, it used
LD_PRELOAD hack but it seems that libtool is sophisticated enough
that no such extra intervention is needed and the desired symbol
resolution Just Works (tm).  However, the technique is highly
non-portable (there is even a warning about that from libtool,
which is partially on purpose as the _syslog_override.so should
rather be explicit it is by no mean a regular library) and hence
the syslog tests have to be enabled with explicit

    ./configure --enable-syslog-tests

rather than possibly break on untested platforms (far too many).
The concept can be extended upon, but initially, just the new
feature is being tested.

Post-review: thanks Chrissie for a suggestion how to deal with
extract-arg-and-forget in a less intrusive way (no defines).
This commit is contained in:
Jan Pokorný 2016-02-11 20:42:35 +01:00
parent 242a07ebc2
commit 642f74de61
No known key found for this signature in database
GPG Key ID: 61BBB23A9E8F8DE2
7 changed files with 194 additions and 9 deletions

View File

@ -434,6 +434,12 @@ AC_ARG_ENABLE([slow-tests],
[ --enable-slow-tests : build and run slow tests. ],
[ default="no" ])
if test x"$with_check" = xyes; then
AC_ARG_ENABLE([syslog-tests],
[ --enable-syslog-tests : build and run syslog tests. ],
[ default="no" ])
fi
AC_ARG_WITH([socket-dir],
[ --with-socket-dir=DIR : socket dir. ],
[ SOCKETDIR="$withval" ],
@ -514,6 +520,12 @@ if test "x${enable_slow_tests}" = xyes ; then
fi
AM_CONDITIONAL(HAVE_SLOW_TESTS, [test "x${enable_slow_tests}" = xyes])
AC_SUBST(HAVE_SLOW_TESTS)
if test "x${enable_syslog_tests}" = xyes ; then
AC_DEFINE([HAVE_SYSLOG_TESTS], 1,[have syslog tests])
AC_MSG_NOTICE([Enabling syslog tests])
fi
AM_CONDITIONAL(HAVE_SYSLOG_TESTS, [test "x${enable_syslog_tests}" = xyes])
AC_SUBST(HAVE_SYSLOG_TESTS)
# --- callsite sections ---
if test "x${GCC}" = xyes; then

View File

@ -420,6 +420,7 @@ enum qb_log_conf {
QB_LOG_CONF_STATE_GET,
QB_LOG_CONF_FILE_SYNC,
QB_LOG_CONF_EXTENDED,
QB_LOG_CONF_IDENT,
};
enum qb_log_filter_type {
@ -504,6 +505,30 @@ void qb_log_callsites_dump(void);
*/
int32_t qb_log_ctl(int32_t target, enum qb_log_conf conf_type, int32_t arg);
typedef union {
int32_t i32;
const char *s;
} qb_log_ctl2_arg_t;
/**
* Extension of main logging control function accepting also strings.
*
* @param arg for QB_LOG_CONF_IDENT, 's' member as new identifier to openlog(),
* for all original qb_log_ctl-compatible configuration directives,
* 'i32' member is assumed (although a preferred way is to use
* that original function directly as it allows for more type safety)
* @see qb_log_ctl
*
* @note You can use <tt>QB_LOG_CTL2_I32</tt> and <tt>QB_LOG_CTL2_S</tt>
* macros for a convenient on-the-fly construction of the object
* to be passed as an <tt>arg</tt> argument.
*/
int32_t qb_log_ctl2(int32_t target, enum qb_log_conf conf_type,
qb_log_ctl2_arg_t arg);
#define QB_LOG_CTL2_I32(a) ((qb_log_ctl2_arg_t) { .i32 = (a) })
#define QB_LOG_CTL2_S(a) ((qb_log_ctl2_arg_t) { .s = (a) })
/**
* This allows you modify the 'tags' and 'targets' callsite fields at runtime.
*/

View File

@ -1060,11 +1060,15 @@ _log_target_disable(struct qb_log_target *t)
}
int32_t
qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg)
qb_log_ctl2(int32_t t, enum qb_log_conf c, qb_log_ctl2_arg_t arg_not4directuse)
{
int32_t rc = 0;
int32_t need_reload = QB_FALSE;
/* extract the constants and do not touch the origin anymore */
const int32_t arg_i32 = arg_not4directuse.i32;
const char * const arg_s = arg_not4directuse.s;
if (!logger_inited) {
return -EINVAL;
}
@ -1074,7 +1078,7 @@ qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg)
}
switch (c) {
case QB_LOG_CONF_ENABLED:
if (arg) {
if (arg_i32) {
rc = _log_target_enable(&conf[t]);
} else {
_log_target_disable(&conf[t]);
@ -1084,33 +1088,39 @@ qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg)
rc = conf[t].state;
break;
case QB_LOG_CONF_FACILITY:
conf[t].facility = arg;
conf[t].facility = arg_i32;
if (t == QB_LOG_SYSLOG) {
need_reload = QB_TRUE;
}
break;
case QB_LOG_CONF_IDENT:
(void)strlcpy(conf[t].name, arg_s, PATH_MAX);
if (t == QB_LOG_SYSLOG) {
need_reload = QB_TRUE;
}
break;
case QB_LOG_CONF_FILE_SYNC:
conf[t].file_sync = arg;
conf[t].file_sync = arg_i32;
break;
case QB_LOG_CONF_PRIORITY_BUMP:
conf[t].priority_bump = arg;
conf[t].priority_bump = arg_i32;
break;
case QB_LOG_CONF_SIZE:
if (t == QB_LOG_BLACKBOX) {
if (arg <= 0) {
if (arg_i32 <= 0) {
return -EINVAL;
}
conf[t].size = arg;
conf[t].size = arg_i32;
need_reload = QB_TRUE;
} else {
return -ENOSYS;
}
break;
case QB_LOG_CONF_THREADED:
conf[t].threaded = arg;
conf[t].threaded = arg_i32;
break;
case QB_LOG_CONF_EXTENDED:
conf[t].extended = arg;
conf[t].extended = arg_i32;
break;
default:
@ -1123,3 +1133,9 @@ qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg)
}
return rc;
}
int32_t
qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg)
{
return qb_log_ctl2(t, c, QB_LOG_CTL2_I32(arg));
}

View File

@ -147,6 +147,13 @@ ipc_test_LDADD = $(top_builddir)/lib/libqb.la @CHECK_LIBS@
log_test_SOURCES = check_log.c $(top_builddir)/include/qb/qblog.h
log_test_CFLAGS = @CHECK_CFLAGS@ -I$(top_srcdir)/include
log_test_LDADD = $(top_builddir)/lib/libqb.la @CHECK_LIBS@
if HAVE_SYSLOG_TESTS
log_test_LDADD += _syslog_override.la
lib_LTLIBRARIES = _syslog_override.la
_syslog_override_la_SOURCES = _syslog_override.c
_syslog_override_la_LDFLAGS = -module
endif
util_test_SOURCES = check_util.c $(top_builddir)/include/qb/qbutil.h
util_test_CFLAGS = @CHECK_CFLAGS@ -I$(top_srcdir)/include

62
tests/_syslog_override.c Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2016 Red Hat, Inc.
*
* All rights reserved.
*
* Author: Jan Pokorny <jpokorny@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 "_syslog_override.h"
#include <limits.h>
#include <string.h>
int _syslog_opened = 0;
int _syslog_option = 0;
int _syslog_facility = 0;
char _syslog_ident[PATH_MAX] = "";
void openlog(const char *ident, int option, int facility);
void
openlog(const char *ident, int option, int facility)
{
_syslog_opened = 1;
_syslog_option = option;
_syslog_facility = facility;
strncpy(_syslog_ident, ident, sizeof(_syslog_ident));
}
void syslog(int priority, const char *format, ...);
void
syslog(int priority, const char *format, ...)
{
_syslog_opened = 1;
}
void closelog(void);
void
closelog(void)
{
_syslog_opened = 0;
_syslog_option = -1;
_syslog_facility = -1;
_syslog_ident[0] = '\0';
}

34
tests/_syslog_override.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2016 Red Hat, Inc.
*
* All rights reserved.
*
* Author: Jan Pokorny <jpokorny@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/>.
*/
#ifndef QB_SYSLOG_OVERRIDE_H_DEFINED
#define QB_SYSLOG_OVERRIDE_H_DEFINED
#include <limits.h>
extern int _syslog_opened;
extern int _syslog_option;
extern int _syslog_facility;
extern char _syslog_ident[PATH_MAX];
#endif

View File

@ -29,6 +29,10 @@
#include <qb/qbutil.h>
#include <qb/qblog.h>
#ifdef HAVE_SYSLOG_TESTS
#include "_syslog_override.h"
#endif
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);
@ -765,6 +769,25 @@ START_TEST(test_extended_information)
}
END_TEST
#ifdef HAVE_SYSLOG_TESTS
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
#endif
static Suite *
log_suite(void)
{
@ -812,6 +835,12 @@ log_suite(void)
tcase_add_test(tc, test_extended_information);
suite_add_tcase(s, tc);
#ifdef HAVE_SYSLOG_TESTS
tc = tcase_create("syslog");
tcase_add_test(tc, test_syslog);
suite_add_tcase(s, tc);
#endif
return s;
}