Program Listing for File client.hpp
↰ Return to documentation for file (rcppsw/er/plugin/log4cxx/client.hpp
)
#pragma once
/*******************************************************************************
* Includes
******************************************************************************/
#include <typeindex>
#include "rcppsw/er/er.hpp"
#include "rcppsw/er/plugin/plugin.hpp"
#include "rcppsw/er/macros.hpp"
#include "rcppsw/abi/abi.hpp"
/*******************************************************************************
* Macros
******************************************************************************/
#if (RCPPSW_ERL == RCPPSW_ERL_NONE)
#define ER_CLIENT_INIT(name) rer::client<typename std::remove_reference<decltype(*this)>::type>()
#define ER_LOGGING_INIT(fname)
#define ER_LOGFILE_SET(logger, fname)
#define ER_NDC_PUSH(s)
#define ER_NDC_POP(...)
#define ER_MDC_ADD(key, value)
#define ER_MDC_RM(key)
#define ER_ENV_VERIFY(...)
#elif (RCPPSW_ERL == RCPPSW_ERL_FATAL)
#define ER_CLIENT_INIT(name) rer::client<typename std::remove_reference<decltype(*this)>::type>()
#define ER_LOGGING_INIT(fname)
#define ER_LOGFILE_SET(logger, fname)
#define ER_NDC_PUSH(s)
#define ER_NDC_POP(...)
#define ER_MDC_ADD(key, value)
#define ER_MDC_RM(key)
#define ER_ENV_VERIFY(...)
#elif (RCPPSW_ERL == RCPPSW_ERL_ALL)
#define ER_CLIENT_INIT() \
rcppsw::er::client< \
typename std::remove_reference_t<decltype(*this)> \
> \
(rcppsw::abi::demangle(std::type_index(typeid(*this)).name()))
#define ER_LOGGING_INIT(fname) \
rcppsw::er::client< \
typename std::remove_reference_t<decltype(*this)>>::logging_init(fname)
#define ER_LOGFILE_SET(logger, fname) \
rcppsw::er::client< \
typename std::remove_reference_t<decltype(*this)>>::logfile_set(logger, \
fname)
#define ER_NDC_PUSH(s) \
rcppsw::er::client< \
typename std::remove_reference_t<decltype(*this)>>::ndc_push(s)
#define ER_NDC_POP(...) \
rcppsw::er::client< \
typename std::remove_reference_t<decltype(*this)>>::ndc_pop()
#define ER_MDC_ADD(key, value) \
rer::client< \
typename std::remove_reference_t<decltype(*this)>>::mdc_add(key, value)
#define ER_MDC_RM(key) \
rer::client< \
typename std::remove_reference_t<decltype(*this)>>::mdc_rm(key)
#define ER_ENV_VERIFY(...) \
rcppsw::er::client< \
typename std::remove_reference_t<decltype(*this)>>::env_verify()
#endif
/*******************************************************************************
* Namespaces/Decls
******************************************************************************/
namespace rcppsw::er {
/*******************************************************************************
* Class Definitions
******************************************************************************/
#if (RCPPSW_ERL == RCPPSW_ERL_ALL)
template <typename T>
class client {
public:
static void logging_init(const std::string& fpath) {
/*
* Multiple initializations will cause duplicate messages to show up in
* logfiles.
*/
if (!m_initialized) {
log4cxx::xml::DOMConfigurator::configure(fpath);
m_initialized = true;
}
}
static void logfile_set(const log4cxx::LoggerPtr& logger,
const std::string& name) {
for (auto& a : logger->getAllAppenders()) {
if (a->getName() == name) {
return;
}
} /* for(&a..) */
#if defined(RCPPSW_ER_OLD_LOG4CXX)
log4cxx::LayoutPtr layout = new log4cxx::PatternLayout(kFileLayout);
log4cxx::AppenderPtr appender =
new log4cxx::FileAppender(layout, name, false);
appender->setName(name);
logger->addAppender(appender);
#else
auto layout = std::make_shared<log4cxx::PatternLayout>(kFileLayout);
auto appender = std::make_shared<log4cxx::FileAppender>(layout,
name,
false);
appender->setName(name);
logger->addAppender(appender);
#endif
}
static void ndc_push(const std::string& s) { log4cxx::NDC::push(s); }
static void ndc_pop(void) { log4cxx::NDC::pop(); }
static void mdc_add(const std::string& key,
const std::string& value) {
log4cxx::MDC::put(key, value);
}
static void mdc_rm(const std::string& key) {
log4cxx::MDC::remove(key);
}
explicit client(const char* abiname)
: m_logger(log4cxx::Logger::getLogger(abi_name_to_logger_name(abiname))) {
/*
* DON'T add the appender here--results in multiple copies of some messages
* for reasons I can't understand. Doing it in the config file works though.
*/
}
virtual ~client(void) = default;
client(const client&) = default;
client& operator=(const client&) = default;
void logfile_set(const std::string& name) {
#if defined(RCPPSW_ER_OLD_LOG4CXX)
log4cxx::LayoutPtr layout = new log4cxx::PatternLayout(kFileLayout);
log4cxx::AppenderPtr appender = new log4cxx::FileAppender(layout, name);
#else
auto layout = std::make_shared<log4cxx::PatternLayout>(kFileLayout);
auto appender = std::make_shared<log4cxx::FileAppender>(layout, name);
#endif
logger()->addAppender(appender);
}
std::string logger_name(void) const {
std::string name;
m_logger->getName(name);
return name;
}
log4cxx::LoggerPtr logger(void) const { return m_logger; }
void env_verify(void) {
if (const char* env_p = std::getenv("LOG4CXX_CONFIGURATION")) {
ER_LOGGING_INIT(std::string(env_p));
} else {
std::cerr << "LOG4CXX_CONFIGURATION not defined" << std::endl;
std::exit(EXIT_FAILURE);
}
}
private:
static std::string abi_name_to_logger_name(const char* name) {
std::string tmp = name;
auto index1 = tmp.find("::");
/* replace all occurences of '::' with '.' */
while (index1 != tmp.npos) {
tmp = tmp.replace(index1, 2, ".");
index1 = tmp.find("::");
} /* while() */
/* remove all <..> in the typeid */
index1 = tmp.find("<");
while (index1 != tmp.npos) {
auto index2 = tmp.find(">");
tmp = tmp.erase(index1, index2 - index1 + 1);
index1 = tmp.find("<");
} /* while() */
return tmp;
}
/* clang-format off */
static inline const std::string kConsoleLayout = "%X{time} %x [%-5p] %c - %m%n";
static inline const std::string kFileLayout = "%X{time} %x [%-5p] %c %l - %m%n";
static inline bool m_initialized{false};
log4cxx::LoggerPtr m_logger{};
/* clang-format on */
};
#else
template<typename T>
class client {
public:
client(void) = default;
/* So that client objects can be constructed outside of class contexts */
explicit client(const std::string& ) {}
virtual ~client(void) = default;
};
#endif
} /* namespace rcppsw::er */