"Fossies" - the Fresh Open Source Software Archive

Member "fimex-1.6.7/modules/python/pyfimex0_logging.cc" (1 Jul 2021, 4635 Bytes) of package /linux/privat/fimex-1.6.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pyfimex0_logging.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.6.6_vs_1.6.7.

    1 /*
    2  * Fimex, pyfimex0_logging.cc
    3  *
    4  * (C) Copyright 2017-2019, met.no
    5  *
    6  * Project Info:  https://wiki.met.no/fimex/start
    7  *
    8  * This library is free software; you can redistribute it and/or modify it
    9  * under the terms of the GNU Lesser General Public License as published by
   10  * the Free Software Foundation; either version 2.1 of the License, or
   11  * (at your option) any later version.
   12  *
   13  * This library is distributed in the hope that it will be useful, but
   14  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
   16  * License for more details.
   17  *
   18  * You should have received a copy of the GNU Lesser General Public
   19  * License along with this library; if not, write to the Free Software
   20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
   21  * USA.
   22  *
   23  *  Created on: Aug 1, 2017
   24  *      Author: Alexander B├╝rger
   25  */
   26 
   27 #include "fimex/Logger.h"
   28 
   29 #include <pybind11/pybind11.h>
   30 
   31 using namespace MetNoFimex;
   32 namespace py = pybind11;
   33 
   34 #define PY_GIL_ACQUIRE py::gil_scoped_acquire acquire
   35 
   36 // ignore exeptions from logging
   37 #define PY_GIL_IGNORE_EXCEPTIONS(x) \
   38     do { try { \
   39         PY_GIL_ACQUIRE; \
   40         x; \
   41     } catch (...) { \
   42     } } while (false)
   43 
   44 // rethrow exeptions from logging, treating StopIteration specially
   45 #define PY_GIL_RETHROW_EXCEPTIONS(x) \
   46     do { try { \
   47         PY_GIL_ACQUIRE; \
   48         x; \
   49     } catch (py::error_already_set& pex) { \
   50         if (pex.matches(PyExc_StopIteration)) { \
   51             throw py::stop_iteration(); \
   52         } else { \
   53             throw; \
   54         } \
   55     } } while (false)
   56 
   57 #define PY_GIL_EXCEPTIONS(x) \
   58     PY_GIL_IGNORE_EXCEPTIONS(x)
   59 
   60 namespace {
   61 
   62 // see https://docs.python.org/3.5/library/logging.html#levels
   63 enum PythonLoggingLevel {
   64     PY_NOTSET = 0,
   65     PY_DEBUG = 10,
   66     PY_INFO = 20,
   67     PY_WARNING = 30,
   68     PY_ERROR = 40,
   69     PY_CRITICAL = 50
   70 };
   71 
   72 int toPythonLevel(Logger::LogLevel level)
   73 {
   74     switch (level) {
   75     case Logger::FATAL: return PY_CRITICAL;
   76     case Logger::ERROR: return PY_ERROR;
   77     case Logger::WARN: return PY_WARNING;
   78     case Logger::INFO: return PY_INFO;
   79     case Logger::DEBUG: return PY_DEBUG;
   80     case Logger::OFF: return PY_NOTSET;
   81     }
   82     return PY_NOTSET;
   83 }
   84 
   85 class PythonLoggingImpl : public LoggerImpl {
   86 public:
   87     PythonLoggingImpl(const py::object& log);
   88     ~PythonLoggingImpl();
   89     bool isEnabledFor(Logger::LogLevel level) /* override */;
   90     void log(Logger::LogLevel level, const std::string& message, const char* filename, unsigned int lineNumber) /* override */;
   91 
   92 private:
   93     py::object log_;
   94 };
   95 
   96 PythonLoggingImpl::PythonLoggingImpl(const py::object& log)
   97 {
   98     if (!log.is_none())
   99         PY_GIL_EXCEPTIONS(log_ = log);
  100 }
  101 
  102 PythonLoggingImpl::~PythonLoggingImpl()
  103 {
  104     if (!log_.is_none())
  105         PY_GIL_IGNORE_EXCEPTIONS(log_ = py::none());
  106 }
  107 
  108 bool PythonLoggingImpl::isEnabledFor(Logger::LogLevel level)
  109 {
  110     const int pylevel = toPythonLevel(level);
  111 
  112     if (!log_.is_none())
  113         PY_GIL_EXCEPTIONS(return log_.attr("isEnabledFor")(pylevel).cast<bool>());
  114     return false;
  115 }
  116 
  117 void PythonLoggingImpl::log(Logger::LogLevel level, const std::string& message, const char* filename, unsigned int lineNumber)
  118 {
  119     if (log_.is_none())
  120         return;
  121 
  122     std::ostringstream py_message;
  123     py_message << message
  124            << " in " << filename
  125            << " at line " << lineNumber;
  126     const std::string py_msg = py_message.str();
  127     const int pylevel = toPythonLevel(level);
  128 
  129     PY_GIL_EXCEPTIONS(log_.attr("log")(pylevel, py_msg));
  130 }
  131 
  132 class PythonLoggingClass : public LoggerClass {
  133 public:
  134     PythonLoggingClass();
  135     LoggerImpl* loggerFor(Logger* logger, const std::string& className) /* override */;
  136     py::module python_logging;
  137 };
  138 
  139 PythonLoggingClass::PythonLoggingClass()
  140 {
  141     PY_GIL_ACQUIRE;
  142     python_logging = py::module::import("logging");
  143 }
  144 
  145 LoggerImpl* PythonLoggingClass::loggerFor(Logger* logger, const std::string& className)
  146 {
  147     remember(logger);
  148     py::object py_logger;
  149     PY_GIL_EXCEPTIONS(py_logger = python_logging.attr("getLogger")(className));
  150     return new PythonLoggingImpl(py_logger);
  151 }
  152 
  153 } // namespace
  154 
  155 void pyfimex0_logging(py::module m)
  156 {
  157     if (char* disable = getenv("FIMEX_PYTHON_NO_LOGGING")) {
  158         Logger::setClass(nullptr);
  159     } else {
  160         // see https://pybind11.readthedocs.io/en/stable/advanced/misc.html#module-destructors
  161         auto atexit = py::module::import("atexit");
  162         atexit.attr("register")(py::cpp_function([]() { Logger::setClass(nullptr); }));
  163 
  164         Logger::setClass(new PythonLoggingClass);
  165     }
  166 }