log: Remove more dead code from linker callsites (#331)

Thanks for the review
This commit is contained in:
Chrissie Caulfield 2018-11-12 15:55:33 +00:00 committed by GitHub
parent 7556204b27
commit 926e851fbb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 10 additions and 1089 deletions

View File

@ -16,7 +16,6 @@ script: RPMBUILDOPTS_="--nodeps --define '_without_check 1'";
./autogen.sh
&& ./configure
&& make -C lib V=1
&& make -C tests/functional/log_internal VERBOSE=1 check
&& make VERBOSE=1 CPPFLAGS=-Dci_dump_shm_usage distcheck
&& sed "s|RPMBUILDOPTS =|\\0 ${RPMBUILDOPTS_}|" Makefile | make -f- rpm

View File

@ -749,9 +749,6 @@ AC_CONFIG_FILES([Makefile
lib/libqb.pc
tools/Makefile
tests/Makefile
tests/functional/Makefile
tests/functional/log_external/Makefile
tests/functional/log_internal/Makefile
tests/test.conf
examples/Makefile
docs/Makefile
@ -760,9 +757,6 @@ AC_CONFIG_FILES([Makefile
docs/man.dox
lib/qblog_script.la:lib/qblog_script.la.in])
AC_CONFIG_LINKS([lib/qblog_script_noop.ld:lib/qblog_script_noop.ld
tests/functional/GNUmakefile:tests/functional/GNUmakefile])
AC_OUTPUT
AC_MSG_RESULT([])

View File

@ -61,25 +61,11 @@ extern "C" {
* }
* @endcode
*
* @note
* In practice, such a minimalistic approach hardly caters real use cases.
* Following section discusses the customization. Moreover when employing
* the log module is bound to its active use (some log messages are assuredly
* emitted within the target compilation unit), it's quite vital to instrument
* the target side with @c QB_LOG_INIT_DATA() macro placed in the top file
* scope in exactly one source file (preferably the main one) to be mixed into
* the resulting compilation unit. This is a self-defensive measure for when
* the linker-assisted collection of callsite data silently fails, which could
* otherwise go unnoticed, causing troubles down the road, but alas it cannot
* discern misuse of @c QB_LOG_INIT_DATA() macro in no-logging context from
* broken callsite section handling assumptions owing to overboard fancy
* linker -- situation that the self-check aims to detect in the first place.
*
* @par Configuring log targets.
* A log target can be syslog, stderr, the blackbox, stdout, or a text file.
* By default, only syslog is enabled. While this is customary for daemons,
* it is rarely appropriate for ordinary programs, which should promptly
* disable that when other targets (read on) are to be utilized:
* By default, only syslog is enabled. While this is usual for daemons,
* it is rarely appropriate for ordinary programs, which should
* disable it when other targets (see below) are to be used:
* @code
* qb_log_ctl(B_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
* @endcode
@ -262,9 +248,7 @@ extern "C" {
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.
* An instance of this structure is created for each log message
*/
struct qb_log_callsite {
const char *function;
@ -410,8 +394,8 @@ void qb_log_from_external_source_va(const char *function,
* as non-inclusive higher bounds of the respective categories
* (static and all the log targets) and also denote the number
* of (reserved) items in the category. Both are possibly subject
* of change, hence it is only adequate to always refer to them
* via these defined values.
* to change, so you should always refer to them using
* these defined values.
* Similarly, there are QB_LOG_TARGET_{STATIC_,DYNAMIC_,}START
* and QB_LOG_TARGET_{STATIC_,DYNAMIC_,}END values, but these
* are inclusive lower and higher bounds, respectively.
@ -649,11 +633,10 @@ void qb_log_tags_stringify_fn_set(qb_log_tags_stringify_fn fn);
* Any number between % and character specify field length to pad or chop.
*
* @note Some of the fields are immediately evaluated and remembered
* for performance reasons, so when there's an objective for log
* messages to carry PIDs (not in the default setup) and, moreover,
* precisely, this function needs to be reinvoked upon @c fork
* for performance reasons, so whenlog messages carry PIDs (not the default)
* this function needs to be reinvoked following @c fork
* (@c clone) in the respective children. When already linking
* to @c libpthread, @c pthread_atfork callback registration
* with @c libpthread, @c pthread_atfork callback registration
* could be useful.
*/
void qb_log_format_set(int32_t t, const char* format);

View File

@ -25,9 +25,6 @@
#endif /* HAVE_LINK_H */
#include <stdarg.h>
#include <pthread.h>
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif /* HAVE_DLFCN_H */
#include <stdarg.h>
#include <string.h>
@ -48,15 +45,9 @@ 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(dlnames);
static QB_LIST_DECLARE(tags_head);
static QB_LIST_DECLARE(callsite_sections);
struct dlname {
char *dln_name;
struct qb_list_head list;
};
struct callsite_section {
struct qb_log_callsite *start;
struct qb_log_callsite *stop;
@ -814,14 +805,6 @@ qb_log_init(const char *name, int32_t facility, uint8_t priority)
{
int32_t l;
enum qb_log_target_slot i;
/* cannot reuse single qb_log invocation in various contexts
through the variables (when section attribute in use),
hence this indirection */
enum {
preinit_err_none,
preinit_err_target_sec,
preinit_err_target_empty,
} preinit_err = preinit_err_none;
l = pthread_rwlock_init(&_listlock, NULL);
assert(l == 0);
@ -849,25 +832,6 @@ qb_log_init(const char *name, int32_t facility, uint8_t priority)
_log_target_state_set(&conf[QB_LOG_SYSLOG], QB_LOG_STATE_ENABLED);
(void)qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "*", priority);
if (preinit_err == preinit_err_target_sec)
qb_util_log(LOG_NOTICE, "(libqb) log module hasn't observed"
" target chain supplied callsite"
" section, target's and/or libqb's"
" build is at fault, preventing"
" reliable logging (unless qb_log_init"
" invoked in no-custom-logging context"
" unexpectedly, or target chain built"
" purposefully without these sections)");
else if (preinit_err == preinit_err_target_empty) {
qb_util_log(LOG_WARNING, "(libqb) log module has observed"
" target chain supplied section"
" unpopulated, target's and/or libqb's"
" build is at fault, preventing"
" reliable logging (unless qb_log_init"
" invoked in no-custom-logging context"
" unexpectedly)");
}
}
void

View File

@ -31,8 +31,7 @@ make %{?_smp_mflags}
%if 0%{?with_check}
%check
make V=1 check \
&& make -C tests/functional/log_internal V=1 check
make V=1 check
%endif
%install

View File

@ -21,8 +21,6 @@ MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST =
CLEANFILES =
SUBDIRS = functional
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
noinst_PROGRAMS = bmc bmcpt bms rbreader rbwriter \

View File

@ -1,21 +0,0 @@
all check:
# do not trigger automatically, it's for on-demand use
@echo "Use 'make $@' within particular subdirectories"
install: force
# definitely not desired to install anything from this subtree
distclean maintainer-clean:
# following is a nasty hack to keep "make distclean" (and
# ~ "maintainer-clean") succeeding (problem mostly arises from
# shared object files and hence shared compiler-generated makefile
# includes, which are swiped when processing one subdir and then
# missing, as a hard error, for the other)
@$(MAKE) -C log_external $@
@mkdir -p .deps
@touch .deps/log_client.Po .deps/log_interlib.Plo .deps/log_interlib_client.Po
@$(MAKE) -C log_internal $@
@$(MAKE) -f Makefile $@ SUBDIRS=
%: force
@$(MAKE) -f Makefile $@
force: ;
.PHONY: check distclean force install maintainer-clean

View File

@ -1,25 +0,0 @@
# Copyright 2017 Red Hat, Inc.
#
# Authors: 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/>.
MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = GNUmakefile log_test_client.err log_test_interlib_client.err \
log_test_client.sh log_test_interlib_client.sh \
log_test_mock.sh syslog-stdout.py \
log_callsite_bench_gen.py
SUBDIRS = log_external log_internal

View File

@ -1,58 +0,0 @@
# Copyright 2017 Red Hat, Inc.
#
# 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/>.
MAINTAINERCLEANFILES = Makefile.in
CLEANFILES = log_test_client.err.real log_test_interlib_client.err.real \
../log_callsite_bench.c
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_builddir)/include -I$(top_srcdir)/include
noinst_PROGRAMS = log_client log_interlib_client
# cannot use {check,noinst}_LTLIBRARIES because it leads to solely static lib
# (this won't get installed anyway, thanks to GNUmakefile rule)
lib_LTLIBRARIES = liblog_inter.la
log_client_SOURCES = ../log_client.c
# log_client_LDFLAGS/log_client_LDADD to be delivered by the base Makefile.am
liblog_inter_la_SOURCES = ../log_interlib.c
liblog_inter_la_LDFLAGS = -shared
# liblog_inter_la_LIBADD to be delivered by the base Makefile.am
log_interlib_client_SOURCES = ../log_interlib_client.c
# this transitively shares link dependencies with liblog_inter.la itself
log_interlib_client_LDADD = $(builddir)/liblog_inter.la
# actual 'make check' auxiliary definitions
TESTS = ../log_test_client.sh ../log_test_interlib_client.sh
TEST_EXTENSIONS = .sh
log_test.log: $(check_PROGRAMS)
../log_test_client.log: log_client
../log_test_interlib_client.log: log_interlib_client
../log_callsite_bench.c: ../log_callsite_bench_gen.py
if HAVE_PYTHON
$(AM_V_GEN)$(PYTHON) $< >$@
else
@echo 'configure script did not detect python prerequisite'
false
endif
# vim: ft=automake

View File

@ -1,173 +0,0 @@
#!/usr/bin/python
# Copyright 2017 Red Hat, Inc.
#
# 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/>.
# expected to work with both Python 2.6+/3+
from __future__ import print_function
"""Generate callsite-heavy logging client so as to evaluate use of resources"""
from getopt import GetoptError, getopt
from math import ceil, floor, log10
#from pprint import pprint
#from random import shuffle
from sys import argv, exit
def die(*args, **kwargs):
print(*args, **kwargs)
exit(1)
def list_to_c_source(worklist, fnc_prefix, width=0):
ret = []
while worklist:
item = worklist.pop()
if type(item) is list:
head, children = item
if type(children) is list:
for i, ci in enumerate(children):
ret += list_to_c_source([ci], fnc_prefix, width)
if type(ci) is list:
children[i] = ci[0]
if type(children[i]) is list:
children[i] = children[i][0]
else:
head = item
children = []
if type(head) is not list:
head = [head]
ret += ["static void {0}_{1:0{2}}(int doit) {{"
.format(fnc_prefix, head[0], width),
"\tif (!doit) return;"]
ret += ["\tqb_log(LOG_ERR, \"{0:0{1}}\");".format(i, width)
for i in head]
ret += ["\t{0}_{1:0{2}}(doit);".format(fnc_prefix, i, width)
for i in reversed(children)]
ret += ["}"]
return ret
def main(opts, args):
FNC_PREFIX = "fnc"
try:
CALLSITE_COUNT = int(opts["CALLSITE_COUNT"])
if not 0 < CALLSITE_COUNT < 10 ** 6: raise ValueError
except ValueError:
die("callsites count can only be a number x, 0 < x < 1e6")
try:
BRANCHING_FACTOR = int(opts["BRANCHING_FACTOR"])
if not 0 < BRANCHING_FACTOR < 10 ** 3: raise ValueError
except ValueError:
die("branching factor can only be a number x, 0 < x < 1000")
try:
CALLSITES_PER_FNC = int(opts["CALLSITES_PER_FNC"])
if not 0 < CALLSITES_PER_FNC < 10 ** 3: raise ValueError
except ValueError:
die("callsites-per-fnc count can only be a number x, 0 < x < 1000")
try:
ROUND_COUNT = int(opts["ROUND_COUNT"])
if not 0 < ROUND_COUNT < 10 ** 6: raise ValueError
except ValueError:
die("round count can only be a number x, 0 < x < 1e6")
worklist, worklist_len = list(range(0, CALLSITE_COUNT)), CALLSITE_COUNT
#shuffle(worklist)
#pprint(worklist)
first = worklist[0]
while worklist_len > 1:
item = worklist.pop(); worklist_len -= 1
reminder = worklist_len % CALLSITES_PER_FNC
parent = (worklist_len - reminder if reminder
else (worklist_len // CALLSITES_PER_FNC - 1)
// BRANCHING_FACTOR * CALLSITES_PER_FNC)
#print("parent {0} (len={1})".format(parent, worklist_len))
if type(worklist[parent]) is not list:
worklist[parent] = [worklist[parent], []]
if not(reminder):
worklist[parent][1].append(item) # reverses the order!
#worklist[parent][1][:0] = [item]
else:
if type(worklist[parent][0]) is not list:
worklist[parent][0] = [worklist[parent][0]]
#worklist[parent][0].append(item) # reverses the order
worklist[parent][0][1:1] = [item] # parent itself the 1st element
#pprint(worklist)
width = int(floor(log10(CALLSITE_COUNT))) + 1
print('\n'.join([
"/* compile with -lqb OR with -DQB_KILL_ATTRIBUTE_SECTION -l:libqb.so.0 */",
"#include <qb/qblog.h>",
] + list_to_c_source(worklist, FNC_PREFIX, width) + [
"int main(int argc, char *argv[]) {",
"\tqb_log_init(\"log_gen_test\", LOG_DAEMON, LOG_INFO);",
"\tqb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);",
"\tqb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE, \"*\", LOG_ERR);",
"\tqb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);",
"\tfor (int i = 0; i < {0}; i++) {{".format(ROUND_COUNT),
"\t\t{0}_{1:0{2}}(argc);".format(FNC_PREFIX, first, width),
"\t}",
"\tqb_log_fini();",
"\treturn !argc;",
"}"
]
))
if __name__ == '__main__':
# Full trees for CALLSITES_PER_FNC == 1 (can be trivially extrapolated):
# BF = 2 (binary trees)
# --> C = 7 (3 steps), 15 (4 steps), ..., 127 (6 steps), ...
# (see https://en.wikipedia.org/wiki/Binary_tree#Properties_of_binary_trees)
# BF = 3 (ternary trees)
# --> C = 13 (3 steps), 40 (4 steps), ..., 1093 (6 steps), ...
# (see https://en.wikipedia.org/wiki/Ternary_tree#Properties_of_ternary_trees)
# ...
BRANCHING_FACTOR = 3
CALLSITES_PER_FNC = 10
CALLSITE_COUNT = 3640
ROUND_COUNT = 1000
try:
opts, args = getopt(argv[1:],
"hc:b:f:r:",
("help", "callsite-count=", "branching-factor=",
"callsites-per-fnc=", "round-count="))
for o, a in opts:
if o in ("-h", "--help"):
raise GetoptError("__justhelp__")
elif o in ("-c", "--callsite-count"): CALLSITE_COUNT = a
elif o in ("-b", "--branching-factor"): BRANCHING_FACTOR = a
elif o in ("-f", "--callsites-per-fnc"): CALLSITES_PER_FNC = a
elif o in ("-r", "--round-count"): ROUND_COUNT = a
except GetoptError as err:
if err.msg != "__justhelp__":
print(str(err))
print("Usage:\n{0} -h|--help\n"
"{0} [-c X|--callsite-count={CALLSITE_COUNT}]"
" [-b Y|--branching-factor={BRANCHING_FACTOR}]\n"
"{1:{2}} [-f Z|--callsites-per-fnc={CALLSITES_PER_FNC}]"
" [-r R|--round-count={ROUND_COUNT}]"
.format(argv[0], '', len(argv[0]), **locals()))
exit(0 if err.msg == "__justhelp__" else 2)
opts = dict(CALLSITE_COUNT=CALLSITE_COUNT,
BRANCHING_FACTOR=BRANCHING_FACTOR,
CALLSITES_PER_FNC=CALLSITES_PER_FNC,
ROUND_COUNT=ROUND_COUNT)
main(opts, args)

View File

@ -1,93 +0,0 @@
/*
* Copyright (c) 2017 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 "os_base.h"
#include <qb/qblog.h>
#ifndef NSELFCHECK
QB_LOG_INIT_DATA(linker_contra_log);
#endif
static const char *
my_tags_stringify(uint32_t tags)
{
if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT)) {
return "libqb";
} else {
return "MAIN";
}
}
int32_t
main(int32_t argc, char *argv[])
{
int tmpfile_fd;
struct stat tmpfile_stat;
char *tmpfile_buf = strdup("linker-log-XXXXXX");
qb_log_init("linker-contra-log", LOG_USER, LOG_INFO);
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
qb_log_tags_stringify_fn_set(my_tags_stringify);
qb_log_format_set(QB_LOG_STDERR, "[%5g|%p] %f:%l:%b");
#if 0
printf("\n==%s consists of: %d, %d, %d, %s==\n\n", qb_ver_str,
qb_ver.major, qb_ver.minor, qb_ver.micro, qb_ver.rest);
#endif
#if 0
printf("--\n");
qb_log_callsites_dump();
printf("--\n");
#endif
#ifndef NLOG
/* Casual test of "user-space" logging. */
qb_log(LOG_DEBUG, "hello");
#endif
/* And now of "library-space" logging, i.e., let libqb generated
an error message on its own behalf, first to see if it will be
logged at all, second if it will be distinguished properly.
The trigger here is as simple as trying to print non-existing
blackbox file. */
tmpfile_fd = mkstemp(tmpfile_buf);
if (tmpfile_fd == -1) {
qb_perror(LOG_ERR, "creating temporary file");
exit(EXIT_FAILURE);
}
unlink(tmpfile_buf);
close(tmpfile_fd);
#if 0
if (stat(tmpfile_buf, &tmpfile_stat) == -1) {
qb_perror(LOG_ERR, "stat'ing nonexistent temporary file");
exit(EXIT_FAILURE);
}
#endif
qb_log_blackbox_print_from_file(tmpfile_buf);
free(tmpfile_buf);
qb_log_fini();
}

View File

@ -1,40 +0,0 @@
# Copyright 2017 Red Hat, Inc.
#
# 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 ../log.am
# while linking with system-wide version of libqb, we are still pursuing
# local in-tree header file, hence we need to link with dynamic linking
# library (which is a prerequisite for using QB_LOG_INIT_DATA defined
# in qblog.h) explicitly
log_client_LDFLAGS = -lqb @client_dlopen_LIBS@
liblog_inter_la_LIBADD = -lqb @client_dlopen_LIBS@
# extras for log_external: comparable, generated callsite-heavy logging clients
if HAVE_PYTHON
noinst_PROGRAMS += log_callsite_bench_sectionfull log_callsite_bench_sectionless
endif
log_callsite_bench_sectionfull_SOURCES = ../log_callsite_bench.c
log_callsite_bench_sectionfull_LDFLAGS = -lqb
log_callsite_bench_sectionless_SOURCES = ../log_callsite_bench.c
log_callsite_bench_sectionless_LDFLAGS = -l:libqb.so.0
log_callsite_bench_sectionless_CPPFLAGS = -DQB_KILL_ATTRIBUTE_SECTION

View File

@ -1,70 +0,0 @@
/*
* Copyright (c) 2017 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 "os_base.h"
#include <qb/qblog.h>
#ifndef NSELFCHECK
QB_LOG_INIT_DATA(linker_contra_log_lib);
#endif
void foo(void);
void
foo(void)
{
int tmpfile_fd;
struct stat tmpfile_stat;
char *tmpfile_buf = strdup("linker-log-XXXXXX");
#if 0
printf("--\n");
qb_log_callsites_dump();
printf("--\n");
#endif
#ifndef NLIBLOG
/* Casual test of "user-space" logging. */
qb_log(LOG_INFO, "aloha");
#endif
/* And now of "library-space" logging, i.e., let libqb generated
an error message on its own behalf, first to see if it will be
logged at all, second if it will be distinguished properly.
The trigger here is as simple as trying to print non-existing
blackbox file. */
tmpfile_fd = mkstemp(tmpfile_buf);
if (tmpfile_fd == -1) {
qb_perror(LOG_ERR, "creating temporary file");
exit(EXIT_FAILURE);
}
unlink(tmpfile_buf);
close(tmpfile_fd);
#if 0
if (stat(tmpfile_buf, &tmpfile_stat) == -1) {
qb_perror(LOG_ERR, "stat'ing nonexistent temporary file");
exit(EXIT_FAILURE);
}
#endif
qb_log_blackbox_print_from_file(tmpfile_buf);
free(tmpfile_buf);
}

View File

@ -1,68 +0,0 @@
/*
* Copyright (c) 2017 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 "os_base.h"
#include <qb/qblog.h>
#ifndef NSELFCHECK
QB_LOG_INIT_DATA(linker_contra_log_lib_user);
#endif
void foo(void);
static const char *
my_tags_stringify(uint32_t tags)
{
if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT)) {
return "libqb";
} else {
return "MAIN";
}
}
int
main(int argc, char *argv[])
{
qb_log_init("linker-contra-log", LOG_USER, LOG_INFO);
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
qb_log_tags_stringify_fn_set(my_tags_stringify);
qb_log_format_set(QB_LOG_STDERR, "[%5g|%p] %f:%l:%b");
#if 0
printf("--\n");
qb_log_callsites_dump();
printf("--\n");
#endif
#ifndef NLOG
qb_log(LOG_INFO, "BEFORE");
#endif
foo();
#ifndef NLOG
qb_log(LOG_INFO, "AFTER");
#endif
qb_log_fini();
}

View File

@ -1,23 +0,0 @@
# Copyright 2017 Red Hat, Inc.
#
# 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 ../log.am
log_client_LDADD = $(top_builddir)/lib/libqb.la
liblog_inter_la_LIBADD = $(top_builddir)/lib/libqb.la

View File

@ -1,2 +0,0 @@
[MAIN |debug] ../log_client.c:69:hello
[libqb|error] log_blackbox.c:197:qb_log_blackbox_print_from_file:

View File

@ -1,33 +0,0 @@
#!/bin/sh
# Copyright 2017 Red Hat, Inc.
#
# 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/>.
# error msg can differ per locale, errno code per system (Hurd begs to differ)
./log_client 2>&1 >/dev/null \
| sed 's/\(qb_log_blackbox_print_from_file:\).*/\1/' \
>log_test_client.err.real
_pipeline='cat ../log_test_client.err'
case "${CPPFLAGS}" in
*-DNLOG*)
_pipeline="${_pipeline} | \
grep -Ev '^\[MAIN |info] \.\./log_client\.c'";;
esac
eval "${_pipeline}" | diff -u - log_test_client.err.real

View File

@ -1,4 +0,0 @@
[MAIN |info] ../log_interlib_client.c:61:BEFORE
[MAIN |info] ../log_interlib.c:47:aloha
[libqb|error] log_blackbox.c:197:qb_log_blackbox_print_from_file:
[MAIN |info] ../log_interlib_client.c:65:AFTER

View File

@ -1,36 +0,0 @@
#!/bin/sh
# Copyright 2017 Red Hat, Inc.
#
# 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/>.
# error msg can differ per locale, errno code per system (Hurd begs to differ)
./log_interlib_client 2>&1 >/dev/null \
| sed 's/\(qb_log_blackbox_print_from_file:\).*/\1/' \
>log_test_interlib_client.err.real
_pipeline='cat ../log_test_interlib_client.err'
case "${CPPFLAGS}" in
*-DNLOG*)
_pipeline="${_pipeline} | \
grep -Ev '^\[MAIN \|info] \.\./log_interlib_client\.c'";;
*-DNLIBLOG*)
_pipeline="${_pipeline} | \
grep -Ev '^\[MAIN \|info\] \.\./log_interlib\.c'";;
esac
eval "${_pipeline}" | diff -u - log_test_interlib_client.err.real

View File

@ -1,319 +0,0 @@
#!/bin/sh
# Copyright 2017 Red Hat, Inc.
#
# 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/>.
# Given the source RPM for libqb, this will run through the basic test matrix
# so as to figure out the outcomes for particular linker (pre-2.29 and 2.29+
# differing in visibility of orphan section delimiting boundary symbols and
# hence possibly causing harm to the logging facility of libqb) being used
# for particular part of the composite logging system (libqb itself,
# it's direct client / (client library + it's own client that uses logging)
# as well). While this is tailored to Fedora, it should be possible to
# run this testsuite wherever following is present:
#
# - rpm (for parsing archive name embedded in libqb.src.rpm [note that
# rpm2cpio is part of rpm package as well] because the extracted dir
# follows the same naming, which we need to know)
# - mock (https://github.com/rpm-software-management/mock/)
# + dependencies + fedora-27-${arch} configuration for mock
# (or whatever other configuration if some variables below are
# changed appropriately)
# - koji (https://pagure.io/koji/) + dependencies (but binutils packages
# can be precached when downloaded from https://koji.fedoraproject.org/
# manually)
# - internet connection (but see the above statement for koji, and
# possibly the full package set within the build'n'test underlying
# container can be precached without further details on "how")
# - commons (coreutils, findutils, sed, ...)
#
# The testsuite will not mangle with your host system as mock spawns
# it's somewhat private container for be worked with under the hood.
#
# Note that in order not to get mad when entering the root password anytime
# mock is invoked, you can add the user initiating the test run to the
# 'mock' group. Be aware of the associated security risks, though:
# https://github.com/rpm-software-management/mock/wiki#setup
set -eu
# change following as suitable
arch=x86_64
mock_args="-r fedora-27-${arch}"
pkg_binutils_228=binutils-2.28-14.fc27
#pkg_binutils_228=binutils-2.27-23.fc27 # alternatively test with 2.27 ...
pkg_binutils_229=binutils-2.29-6.fc27
#pkg_binutils_229=binutils-2.29.1-2.fc28 # alternatively test with 2.29.1
#
# prettified reporters
#
do_progress () { printf "\x1b[7m%s\x1b[0m\n" "$*"; }
do_info () { printf "\x1b[36mINFO: %s\x1b[0m\n" "$*"; }
do_warn () { printf "\x1b[31mWARNING: %s\x1b[0m\n" "$*"; }
do_die () { printf "\x1b[31mFATAL: %s\x1b[0m\n" "$*"; exit 1; }
#
# actual building blocks
#
# $1, ... $N: packages (and possibly related subpackages) to be downloaded
do_download () {
while test $# -gt 0; do
if test -d "_pkgs/$1" 2>/dev/null; then
do_info "$1 already downloaded"
shift; continue
fi
mkdir -p "_pkgs/$1"
( cd "_pkgs/$1" && koji download-build --arch="${arch}" "$1" )
shift
done
}
# $1, ... $N: descriptors of packages to be installed
do_install () {
while test $# -gt 0; do
if test -d "_pkgs/$1" 2>/dev/null; then
do_install_inner "_pkgs/$1"/*.rpm
else
do_warn "$1 is not downloaded, hence skipped"
fi
shift
done
}
# $1, ... $N: concrete packages to be installed
do_install_inner () {
_remove_cmd="mock ${mock_args} -- shell \"rpm --nodeps --erase"
_install_cmd="mock ${mock_args}"
while test $# -gt 0; do
case "$1" in
*.src.rpm|*-debuginfo*|*-debugsource*) ;;
*)
_pkg_name="$(basename "$1" | sed 's|\(-[0-9].*\)||')"
_remove_cmd="${_remove_cmd} \'${_pkg_name}\'"
_install_cmd="${_install_cmd} --install \"$1\"";;
esac
shift
done
eval "${_remove_cmd}\"" || : # extra quotation mark intentional
eval "${_install_cmd}"
}
# $1: full path of srpm to be rebuilt
# $2: %{dist} macro for rpmbuild (distinguishing the builds)
do_buildsrpm () {
_pkg_descriptor="$(basename "$1" | sed 's|\.src\.rpm$||')"
# need to prune due to possible duplicates caused by differing %{dist}
rm -f -- "_pkgs/${_pkg_descriptor}"/*
mock ${mock_args} -Nn --define "dist $2" --define '_without_check 1' \
--resultdir "_pkgs/${_pkg_descriptor}" --rebuild "$1"
}
# $1: full path srpm to be rebuilt
# $2: extra (presumably) variable assignments for the make goal invocation
do_compile_interlib () {
mock ${mock_args} --shell \
"find \"builddir/build/BUILD/$1/tests/functional\" \
\( -name log_internal -o -name '*.c' \) -prune \
-o -name '*liblog_inter*' \
-exec rm -- {} \;"
mock ${mock_args} --shell "( cd \"builddir/build/BUILD/$1\"; ./configure )"
mock ${mock_args} --shell \
"make -C \"builddir/build/BUILD/$1/tests/functional/log_external\" \
liblog_inter.la $2"
}
# $1: full path srpm to be rebuilt
# $2: which type of client to work with (client/interclient)
# $3: base (on-host) directory for test results
# $4: output file to capture particular test result
# $5: extra (presumably) variable assignments for the make goal invocation
do_compile_and_test_client () {
_result=$4
case "$2" in
interclient)
_logfile=log_test_interlib_client
mock ${mock_args} --shell \
"find \"builddir/build/BUILD/$1/tests/functional\" \
\( -name log_internal -o -name '*.err' -o -name '*.c' \) -prune \
-o \( -name '*log_interlib_client*' -o -name \"${_logfile}.log\" \) \
-exec rm -- {} \;"
;;
client|*)
_logfile=log_test_client
mock ${mock_args} --shell \
"find \"builddir/build/BUILD/$1/tests/functional\" \
\( -name log_internal -o -name '*.err' -o -name '*.c' \) -prune \
-o \( -name '*log_client*' -o -name \"${_logfile}.log\" \) \
-exec rm -- {} \;"
;;
esac
mock ${mock_args} --copyin "syslog-stdout.py" "builddir"
mock ${mock_args} --shell "( cd \"builddir/build/BUILD/$1\"; ./configure )"
mock ${mock_args} --shell \
"python3 builddir/syslog-stdout.py \
>\"builddir/build/BUILD/$1/tests/functional/log_external/.syslog\" & \
{ sleep 2; make -C \"builddir/build/BUILD/$1/tests/functional/log_external\" \
check-TESTS \"TESTS=../${_logfile}.sh\" $5; } \
&& ! test -s \"builddir/build/BUILD/$1/tests/functional/log_external/.syslog\"; \
ret_ec=\$?; \
( cd \"builddir/build/BUILD/$1/tests/functional/log_external\"; \
cat .syslog >> test-suite.log; \
echo SYSLOG-begin; cat .syslog; echo SYSLOG-end ); \
ret () { return \$1; }; ret \${ret_ec}" \
&& _result="${_result}_good" \
|| _result="${_result}_bad"
mock ${mock_args} --copyout \
"builddir/build/BUILD/$1/tests/functional/log_external/test-suite.log" \
"$3/${_result}"
}
do_shell () {
mock ${mock_args} --shell
}
# $1, ... $N: "argv"
do_proceed () {
_makevars=
_resultsdir_tag=
_selfcheck=1
_clientlogging=1
_interliblogging=1
while :; do
case "$1" in
shell) shift; do_shell "$@"; return;;
-nsc) _resultsdir_tag="${_resultsdir_tag}$1"; shift; _selfcheck=0;;
-ncl) _resultsdir_tag="${_resultsdir_tag}$1"; shift; _clientlogging=0;;
-nil) _resultsdir_tag="${_resultsdir_tag}$1"; shift; _interliblogging=0;;
-*) do_die "Uknown option: $1";;
*) break;;
esac
done
if test -n "${_resultsdir_tag}"; then
_makevars="CPPFLAGS=\"$(test "${_selfcheck}" -eq 1 || printf %s ' -DNSELFCHECK') \
$(test "${_clientlogging}" -eq 1 || printf %s ' -DNLOG') \
$(test "${_interliblogging}" -eq 1 || printf %s ' -DNLIBLOG')\""
_makevars=$(echo ${_makevars})
fi
test -s "$1" || do_die "Not an input file: $1"
_libqb_descriptor_path="$1"
_libqb_descriptor="$(basename "${_libqb_descriptor_path}" \
| sed 's|\.src\.rpm$||')"
_libqb_descriptor_archive="$(rpm -q --qf '[%{FILENAMES}\n]' \
-p "${_libqb_descriptor_path}" \
| sed -n '/\.tar/{s|\.tar\.[^.]*$||;p;q}')"
_resultsdir="_results/$(date '+%y%m%d_%H%M%S')_${_libqb_descriptor}${_resultsdir_tag}"
mkdir -p "${_resultsdir}"
rm -f -- "${_resultsdir}/*"
_dist=
_outfile=
_outfile_client=
_outfile_qb=
do_download "${pkg_binutils_228}" "${pkg_binutils_229}"
for _pkg_binutils_libqb in "${pkg_binutils_228}" "${pkg_binutils_229}"; do
case "${_pkg_binutils_libqb}" in
${pkg_binutils_228}) _outfile_qb="qb+"; _dist=.binutils228;;
${pkg_binutils_229}) _outfile_qb="qb-"; _dist=.binutils229;;
*) _outfile_qb="?";;
esac
do_progress "installing ${_pkg_binutils_libqb} so as to build" \
"libqb [${_outfile_qb}]"
do_install "${_pkg_binutils_libqb}"
do_progress "building ${_libqb_descriptor_path} with" \
"${_pkg_binutils_libqb} [${_outfile_qb}]"
do_buildsrpm "${_libqb_descriptor_path}" "${_dist}"
do_progress "installing ${_libqb_descriptor}-based packages" \
"built with ${_pkg_binutils_libqb} [${_outfile_qb}]"
do_install "${_libqb_descriptor}"
# from now on, we can work fully offline, also to speed
# the whole thing up (and not to bother the mirrors)
mock_args="${mock_args} --offline"
for _pkg_binutils_interlib in none "${pkg_binutils_228}" "${pkg_binutils_229}"; do
case "${_pkg_binutils_interlib}" in
none) _outfile="${_outfile_qb}";;
${pkg_binutils_228}) _outfile="${_outfile_qb}_il+";;
${pkg_binutils_229}) _outfile="${_outfile_qb}_il-";;
*) _outfile="${_outfile_qb}_?";;
esac
case "${_pkg_binutils_interlib}" in
none) ;;
*)
do_progress "installing ${_pkg_binutils_interlib}" \
"so as to build interlib [${_outfile}]"
do_install "${_pkg_binutils_interlib}"
do_progress "building interlib with ${_libqb_descriptor_archive}" \
"+ ${_pkg_binutils_interlib} [${_outfile}]" \
"{${_makevars}}"
do_compile_interlib "${_libqb_descriptor_archive}" "${_makevars}"
;;
esac
for _pkg_binutils_client in "${pkg_binutils_228}" "${pkg_binutils_229}"; do
_client=client
test "${_pkg_binutils_interlib}" = none || _client=interclient
case "${_pkg_binutils_client}" in
${pkg_binutils_228}) _outfile_client="${_outfile}_c+";;
${pkg_binutils_229}) _outfile_client="${_outfile}_c-";;
*) _outfile_client="${_outfile}_?";;
esac
do_progress "installing ${_pkg_binutils_client}" \
"so as to build ${_client} [${_outfile_client}]"
do_install "${_pkg_binutils_client}"
do_progress "building ${_client} with ${_libqb_descriptor_archive}" \
"+ ${_pkg_binutils_client} [${_outfile_client}]" \
"{${_makevars}}"
do_compile_and_test_client "${_libqb_descriptor_archive}" \
"${_client}" "${_resultsdir}" \
"${_outfile_client}" "${_makevars}"
done
done
done
}
{ test $# -eq 0 || test "$1" = -h || test "$1" = --help; } \
&& printf '%s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n' \
"usage: $0 {[-n{sc,cl,il}]* <libqb.src.rpm> | shell}" \
"- use '-nsc' to suppress optional self-check (\"see whole story\")" \
"- use '-ncl' to suppress client-side logging" \
"- use '-nil' to suppress interlib-side logging" \
"- 'make -C ../.. srpm' (or so) can generate the requested input" \
" (in that case, apparently, refer to '../../libqb-X.src.rpm')" \
"- _pkgs dir caches (intermediate or not) packages to work with" \
"- results stored in '_results/<timestamp>_<input_name>[_<tag>]'" \
|| do_proceed "$@"

View File

@ -1,51 +0,0 @@
#!/usr/bin/python3
# Copyright 2017 Red Hat, Inc.
#
# 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/>.
"""Simple /dev/log to stdout forwarding"""
import socket
from atexit import register
from os import remove
from sys import argv
# no locking, but anyway
try:
remove("/dev/log")
except FileNotFoundError:
pass
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind("/dev/log")
def shutdown():
sock.close()
remove("/dev/log")
def main(*argv):
register(shutdown)
while True:
try:
b = sock.recv(4096)
# flushing is crucial here
print(">>> " + str(b, 'ascii').split(' ', 3)[-1], flush=True)
except IOError:
pass
if __name__ == '__main__':
main(*argv)