29 #include "log4cxx/patternlayout.h" 
   30 #include "log4cxx/helpers/stringhelper.h" 
   37 using namespace log4cxx::helpers;
 
   45     GilGuard() : gil_state(PyGILState_Ensure()) {}
 
   47     ~GilGuard() { PyGILState_Release(gil_state); }
 
   50     PyGILState_STATE gil_state;
 
   58     PyErr_Fetch(&ptype.
get(), &pvalue.
get(), &ptraceback.
get());
 
   61     if (pvalue != 
nullptr or ptype != 
nullptr) {
 
   64         exc_msg += PyUnicode_AsUTF8(exc_str);
 
   71 unsigned const MAX_LRU_CACHE_SIZE = 32;
 
   77 PyLogAppender::PyLogAppender() {
 
   81     PyObjectPtr logging(PyImport_ImportModule(
"logging"));
 
   82     if (logging == 
nullptr) {
 
   83         ::reraise(
"ImportError: Failed to import Python logging module");
 
   85     _getLogger = PyObject_GetAttrString(logging, 
"getLogger");
 
   86     if (_getLogger == 
nullptr) {
 
   87         ::reraise(
"AttributeError: logging.getLogger method does not exist");
 
   90     PyObjectPtr lsstlog_module(PyImport_ImportModule(
"lsst.log"));
 
   91     if (lsstlog_module == 
nullptr) {
 
   92         ::reraise(
"ImportError: Failed to import lsst.log module");
 
   94     _mdc_class = PyObject_GetAttrString(lsstlog_module, 
"MDCDict");
 
   95     if (_mdc_class == 
nullptr) {
 
   96         ::reraise(
"AttributeError: lsst.log.MDCDict class does not exist");
 
  104     log4cxx::helpers::Transcoder::encodeUTF8(event->getLoggerName(), logger_name);
 
  105     int const level = 
event->getLevel()->toInt();
 
  106     int const pyLevel = level / 1000;
 
  113         auto cache_iter = _cache.find(logger_name);
 
  114         if (cache_iter != _cache.end()) {
 
  116             logger = cache_iter->second.logger;
 
  125         if (logger_name == 
"root") {
 
  126             logger = PyObject_CallFunction(_getLogger, 
nullptr);
 
  128             logger = PyObject_CallFunction(_getLogger, 
"s", logger_name.
c_str());
 
  132         ::reraise(
"Failed to retrieve Python logger \"" + logger_name + 
"\"");
 
  136         _cache.emplace(logger_name, LRUEntry({
logger, _lru_age ++}));
 
  137         while (_cache.size() > ::MAX_LRU_CACHE_SIZE) {
 
  140                 _cache.begin(), _cache.end(),
 
  141                 [](
const LRUCache::value_type& lhs, 
const LRUCache::value_type& rhs) {
 
  142                     return lhs.second.age < rhs.second.age;
 
  150             for (
auto& cache_value: _cache) {
 
  152                 cache_value.second.age = _lru_age ++;
 
  158     PyObjectPtr py_is_enabled(PyObject_CallMethod(
logger, 
"isEnabledFor", 
"i", pyLevel));
 
  159     if (py_is_enabled == 
nullptr) {
 
  160         ::reraise(
"Failure when calling logger.isEnabledFor() method");
 
  162     if (not PyObject_IsTrue(py_is_enabled)) {
 
  167     auto& loc = 
event->getLocationInformation();
 
  169     if (loc.getFileName() != 
nullptr) {
 
  170         file_name = loc.getFileName();
 
  172     int const lineno = loc.getLineNumber();
 
  178         this->layout->format(msg, event, p);
 
  180         if (not msg.empty() and msg.back() == 
'\n') {
 
  183         log4cxx::helpers::Transcoder::encodeUTF8(msg, message);
 
  185         log4cxx::helpers::Transcoder::encodeUTF8(event->getMessage(), message);
 
  200     if (record == 
nullptr) {
 
  201         ::reraise(
"Failed to create LogRecord instance");
 
  211     PyObjectPtr mdc(PyObject_GetAttrString(record, 
"MDC"));
 
  212     if (mdc == 
nullptr) {
 
  215         mdc = PyObject_CallObject(_mdc_class, 
nullptr);
 
  216         if (mdc == 
nullptr) {
 
  217             ::reraise(
"Failed to make MDCDict instance");
 
  220         if (PyObject_SetAttrString(record, 
"MDC", mdc) == -1) {
 
  221             ::reraise(
"Failed to set LogRecord MDC attribute");
 
  226     for (
auto& mdc_key: event->getMDCKeySet()) {
 
  228         log4cxx::helpers::Transcoder::encodeUTF8(mdc_key, key);
 
  229         log4cxx::LogString mdc_value;
 
  230         event->getMDC(mdc_key, mdc_value);
 
  231         log4cxx::helpers::Transcoder::encodeUTF8(mdc_value, value);
 
  234         if (PyObject_SetItem(mdc, py_key, py_value) == -1) {
 
  236             ::reraise(
"Failed to update MDC dictionary");
 
  242     if (res == 
nullptr) {
 
  243         ::reraise(
"Logger failed to handle LogRecord");
 
  247 void PyLogAppender::close() {
 
  250 bool PyLogAppender::requiresLayout()
 const {
 
  254 void PyLogAppender::setOption(
const LogString &option, 
const LogString &value) {
 
  256     if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR(
"MESSAGEPATTERN"),
 
  257                                        LOG4CXX_STR(
"messagepattern"))) {
 
  258         setLayout(LayoutPtr(
new PatternLayout(value)));
 
  260         AppenderSkeleton::setOption(option, value);
 
This class defines special log4cxx appender which "appends" log messages to Python logging.
Smart pointer class for PyObject instances.
std::shared_ptr< FrameSet > append(FrameSet const &first, FrameSet const &second)
Construct a FrameSet that performs two transformations in series.