Misc¶
Logging¶
PVXS internally logs warning/status messages using errlog.h from EPICS Base. User applications may control which messages are printed, and may add output.
#include <pvxs/log.h>
namespace pvxs { ... }
Control of log message output is available through named loggers. All internal logger names begin with the prefix “pvxs.”.
In addition to a name, each logger has an associated integer logging level. A message will be logged if the level of the message is less than or equal to the level of the associated logger.
To enable all logging at full detail.
export PVXS_LOG="*=DEBUG"
-
enum class pvxs::Level¶
Importance of message.
Values:
-
enumerator Debug¶
-
enumerator Info¶
-
enumerator Warn¶
-
enumerator Err¶
-
enumerator Crit¶
-
enumerator Debug¶
Controlling Logging¶
By default, all loggers have level Err.
It is recommended that user applications prefer configuration
through the environment variable $PVXS_LOG by calling pvxs::logger_config_env()
.
-
void pvxs::logger_config_env()¶
Configure logging from environment variable $PVXS_LOG
Value of the form “key=VAL,…”
Keys may be literal logger names, or may include ‘*’ wildcards to match multiple loggers. eg. “pvxs.*=DEBUG” will enable all internal log messages.
VAL may be one of “CRIT”, “ERR”, “WARN”, “INFO”, or “DEBUG”
If this is undesirable, logger levels may be (reset) manually.
-
void pvxs::logger_level_clear()¶
Remove any previously logger configurations. Does not change any logger::lvl Use prior to re-applying new configuration.
Logging from User applications¶
To emit log messages from user code, a new logger should be defined with DEFINE_LOGGER
which will be usable within the current translation unit.
It is allowable for multiple loggers to have the same name.
Logger names beginning with “pvxs.*” is reserved for internal usage, and must not be present in user code.
-
DEFINE_LOGGER(VAR, NAME)¶
Define a new logger global.
- Parameters:
VAR – The (static) variable name passed to log_printf() and friends.
NAME – A name string in “A.B.C” form.
-
log_crit_printf(LOGGER, FMT, ...)¶
-
log_err_printf(LOGGER, FMT, ...)¶
-
log_warn_printf(LOGGER, FMT, ...)¶
-
log_info_printf(LOGGER, FMT, ...)¶
-
log_debug_printf(LOGGER, FMT, ...)¶
-
log_printf(LOGGER, LVL, FMT, ...)¶
Try to log a message at the defined level.
Due to portability issues with MSVC, log formats must have at least one argument.
DEFINE_LOGGER(blah, "myapp.blah"); void blahfn(int x) { log_info_printf(blah, "blah happened with %d\n", x);
Identification¶
Compile time access to PVXS library version information.
#include <pvxs/util.h>
namespace pvxs { ... }
-
PVXS_VERSION¶
Current library version.
-
PVXS_ABI_VERSION¶
Current library ABI version
- Since
0.1.1
-
VERSION_INT(V, R, M, P)¶
Construct version number constant.
eg. to conditionally compile based on library version.
#if PVXS_VERSION < VERSION_INT(1,2,3,4)
// enable some compatibility code
#endif
-
unsigned long pvxs::version_int()¶
- Returns:
PVXS_VERSION captured at library compile time
-
const char *pvxs::version_str()¶
Library version as a string. eg. “PVXS 1.2.3”.
-
unsigned long pvxs::version_abi_int()¶
- Since
0.1.1
- Returns:
PVXS_ABI_VERSION captured at library compile time
-
static inline bool pvxs::version_abi_check()¶
Runtime ABI check.
This test is only meaningful if it is performed prior to any other library calls.
It is guaranteed that the library has no global constructors.
- Since
0.1.1
- Returns:
true if the header and library ABI versions match, and if the header version is not newer than the library version.
Unit-test helpers¶
Extensions to epicsUnitTest.h
#include <pvxs/unittest.h>
namespace pvxs { ... }
-
testTrue(EXPR)¶
Macro which assert that an expression evaluate to ‘true’. Evaluates to a pvxs::testCase
-
testFalse(EXPR)¶
Macro which assert that an expression evaluate to ‘true’. Evaluates to a pvxs::testCase
-
testEq(LHS, RHS)¶
Macro which asserts equality between LHS and RHS. Evaluates to a pvxs::testCase Roughly equivalent to
testOk((LHS)==(RHS), "...");
-
testNotEq(LHS, RHS)¶
Macro which asserts in-equality between LHS and RHS. Evaluates to a pvxs::testCase Roughly equivalent to
testOk((LHS)!=(RHS), "...");
-
testStrEq(LHS, RHS)¶
Macro which asserts equality between LHS and RHS. Evaluates to a pvxs::testCase Functionally equivalent to testEq() with two std::string instances. Prints diff-like output which is friendlier to multi-line strings.
-
testStrMatch(EXPR, STR)¶
Macro which asserts that STR matches the regular expression EXPR Evaluates to a pvxs::testCase
- Since
0.2.1 Expression syntax is POSIX extended.
- Since
0.1.1
-
testArrEq(LHS, RHS)¶
Macro which asserts equality between LHS and RHS. Evaluates to a pvxs::testCase Functionally equivalent to testEq() for objects with .size() and operator[]. Prints element by element differences
-
testShow()¶
Macro which prints diagnostic (non-test) lines. Evaluates to a pvxs::testCase Roughly equivalent to
testDiag("...");
The testEq() macro and friends expand to a function which returns a pvxs::testCase
instance
which may be used as a std::ostream
to append text describing a test. eg.
testEq(1, 1)<<"We really hope this is true.";
if(testNotEq(1, 2)<<"shouldn't be true") {
// further conditional tests if 1!=2
}
-
template<class Exception, typename FN>
testCase pvxs::testThrows(FN fn)¶ Assert that an exception is thrown.
testThrows<std::runtime_error>([]() { testShow()<<"Now you see me"; throw std::runtime_error("I happened"); testShow()<<"Now you don't"; })<<"some message";
- Template Parameters:
Exception – The exception type which should be thrown
- Parameters:
fn – A callable
- Returns:
A testCase which passes if an Exception instance was caught, and false otherwise (wrong type, or no exception).
-
template<class Exception, typename FN>
testCase pvxs::testThrowsMatch(const std::string &expr, FN fn)¶ Assert that an exception is throw with a certain message.
testThrowsMatch<std::runtime_error>("happened", []() { testShow()<<"Now you see me"; throw std::runtime_error("I happened"); testShow()<<"Now you don't"; })<<"some message";
- Since
0.1.1
- Template Parameters:
Exception – The exception type which should be thrown
- Parameters:
expr – A regular expression
fn – A callable
- Returns:
A testCase which passes if an Exception instance was caught and std::exception::what() matched the provided regular expression.
-
class testCase¶
A single test case (or diagnostic line).
Acts as an output string to accumulate test comment. Multi-line output results in one test line, and subsequent diagnostic lines.
Test line is printed when an active (non-moved) testCase is destroyed.
Public Functions
-
testCase()¶
new diag message
-
explicit testCase(bool result)¶
new test case
-
inline explicit operator bool() const¶
true when passing
-
testCase &setPassMatch(const std::string &expr, const std::string &inp)¶
Override current pass/fail result if input matches a regular expression
- Since
0.2.1 Expression syntax is POSIX extended.
- Since
0.1.1 Added
-
inline std::ostream &stream()¶
Access to underlying std::ostream used to accumulate notes. When our operator<< isn’t enough.
- Since
1.1.4
-
testCase()¶
IOC Testing¶
Additional helpers for testing IOC applications.
#include <pvxs/iochooks.h>
namespace pvxs { namespace ioc { ... } }
When possible, use of the TestIOC
class is recommended for both
forward and backward compatibility with EPICS Base (>= 3.15.0.1).
-
class TestIOC¶
Manage Test IOC life-cycle calls.
Makes necessary calls to dbUnitTest.h API as well as any added calls needed by PVXS components.
MAIN(mytest) { testPlan(0); // TODO: Set actual number of tests pvxs::testSetup(); pvxs::logger_config_env(); // (optional) { TestIOC ioc; // testdbPrepare() // mytestioc.dbd must include pvxsIoc.dbd testdbReadDatabase("mytestioc.dbd", NULL, NULL); mytestioc_registerRecordDeviceDriver(pdbbase); testdbReadDatabase("sometest.db", NULL, NULL); // tests before iocInit() ioc.init(); // tests after iocInit() ioc.shutdown(); // (optional) in ~TestIOC if omitted } { ... repeat ... } epicsExitCallAtExits(); pvxs::cleanup_for_valgrind(); }
- Since
1.3.0
Utilities¶
Misc. utility code.
#include <pvxs/util.h>
namespace pvxs { ... }
-
inline detail::Escaper pvxs::escape(const std::string &s)¶
Print string to output stream with non-printable characters escaped.
Outputs (almost) C-style escapes. Prefers short escapes for newline, tab, quote, etc (”\n”). Falls back to hex escape (eg. “\xab”).
Unlike C, hex escapes are always 2 chars. eg. the output “\xabcase” would need to be manually changed to “\xab””case” to be used as C source.
std::string blah("this \"is a test\""); std::cout<<pvxs::escape(blah);
-
inline detail::Escaper pvxs::escape(const char *s)¶
Print nil terminated char array to output stream with non-printable characters escaped.
std::cout<<pvxs::escape("this \"is a test\"");
-
inline detail::Escaper pvxs::escape(const char *s, size_t n)¶
Print fixed length char array to output stream with non-printable characters escaped.
std::cout<<pvxs::escape("this \"is a test\"", 6); // prints 'this \"'
-
void pvxs::cleanup_for_valgrind()¶
Free some internal global allocations to avoid false positives in valgrind (or similar) tools looking for memory leaks.
Calls libevent_global_shutdown() when available (libevent >=2.1).
Warning
This function is optional. If you don’t understand the intended use case, then do not call it!
- Pre:
Caller must release all resources explicitly allocated through PVXS (on all threads).
- Post:
Invalidates internal state. Use of any API functions afterwards is undefined!
-
class SigInt¶
Portable process signal handling in CLI tools.
epicsEvent evt; SigInt handle([&evt]() { evt.trigger(); }); ... setup network operations evt.wait(); // completion, or SIGINT
Saves existing handler, which are restored by dtor.
- Since
1.1.0 “handler” action runs in thread context. Safe to take locks etc. Previously handler action ran in signal handler context.
-
std::ostream &pvxs::target_information(std::ostream&)¶
Describe build and runtime configuration of current system.
Print information which may be using for when troubleshooting, or creating a bug report.
Printed by CLI “pvxinfo -D” and iocsh “pvxs_target_information”.
- Returns:
The same ostream passed as argument.
-
template<typename T>
class MPMCFIFO¶ Thread-safe, bounded, multi-producer, multi-consumer FIFO queue.
Queue value_type must be movable. If T is also copy constructable, then push(const T&) may be used.
As an exception, the destructor is not re-entrant. Concurrent calls to methods during destruction will result in undefined behavior.
MPMCFIFO<std::function<void()>> Q; ... while(auto work = Q.pop()) { // Q.push(nullptr) to break loop work(); }
- Since
0.2.0
Public Functions
-
inline explicit MPMCFIFO(size_t limit = 0u)¶
Construct a new queue
- Parameters:
limit – If non-zero, then emplace()/push() will block while while queue size is greater than or equal to this limit.
-
inline ~MPMCFIFO()¶
Destructor is not re-entrant.
-
inline size_t size() const¶
Poll number of elements in the work queue at this moment.