123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779 |
- // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #define PY_SSIZE_T_CLEAN
- #include <Python.h>
- #include <structmember.h>
- #include <config.h>
- #include <log/message_dictionary.h>
- #include <log/logger_manager.h>
- #include <log/logger_support.h>
- #include <log/logger.h>
- #include <config/ccsession.h>
- #include <string>
- #include <boost/bind.hpp>
- #include <util/python/pycppwrapper_util.h>
- #include <log/log_dbglevels.h>
- using namespace isc::log;
- using namespace isc::util::python;
- using std::string;
- using boost::bind;
- // We encountered a strange problem with Clang (clang version 2.8
- // (tags/RELEASE_28 115909)) on OSX, where unwinding the stack
- // segfaults the moment this exception was thrown and caught.
- //
- // Placing it in a named namespace instead of the originalRecommend
- // unnamed namespace appears to solve this, so as a temporary
- // workaround, we create a local randomly named namespace here
- // to solve this issue.
- namespace clang_unnamed_namespace_workaround {
- // To propagate python exceptions through our code
- // This exception is used to signal to the calling function that a
- // proper Python Exception has already been set, and the caller
- // should now return NULL.
- // Since it is only used internally, and should not pass any
- // information itself, is is not derived from std::exception
- class InternalError : public std::exception {};
- }
- using namespace clang_unnamed_namespace_workaround;
- namespace {
- // This is for testing only. The real module will have it always set as
- // NULL and will use the global dictionary.
- MessageDictionary* testDictionary = NULL;
- PyObject*
- setTestDictionary(PyObject*, PyObject* args) {
- PyObject* enableO;
- // The API doesn't seem to provide conversion to bool,
- // so we do it little bit manually
- if (!PyArg_ParseTuple(args, "O", &enableO)) {
- return (NULL);
- }
- int enableI(PyObject_IsTrue(enableO));
- if (enableI == -1) {
- return (NULL);
- }
- bool enable(enableI != 0);
- try {
- delete testDictionary;
- testDictionary = NULL;
- if (enable) {
- testDictionary = new MessageDictionary;
- }
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- Py_RETURN_NONE;
- }
- PyObject*
- createMessage(PyObject*, PyObject* args) {
- const char* mid;
- const char* text;
- // We parse the strings
- if (!PyArg_ParseTuple(args, "ss", &mid, &text)) {
- return (NULL);
- }
- PyObject* origMid;
- // And extract the original representation of the message
- // ID, so we can return it instead of creating another instance.
- // This call shouldn't fail if the previous suceeded.
- if (!PyArg_ParseTuple(args, "Os", &origMid, &text)) {
- return (NULL);
- }
- try {
- MessageDictionary* dict = testDictionary ? testDictionary :
- &MessageDictionary::globalDictionary();
- // We ignore the result, they will be in some kind of dupe list
- // if there's a problem
- dict->add(mid, text);
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- // Return the ID
- Py_INCREF(origMid);
- return (origMid);
- }
- PyObject*
- getMessage(PyObject*, PyObject* args) {
- const char* mid;
- if (!PyArg_ParseTuple(args, "s", &mid)) {
- return (NULL);
- }
- try {
- MessageDictionary* dict = testDictionary ? testDictionary :
- &MessageDictionary::globalDictionary();
- const std::string& result(dict->getText(mid));
- if (result.empty()) {
- Py_RETURN_NONE;
- } else {
- return (Py_BuildValue("s", result.c_str()));
- }
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- }
- PyObject*
- reset(PyObject*, PyObject*) {
- LoggerManager::reset();
- Py_RETURN_NONE;
- }
- PyObject*
- init(PyObject*, PyObject* args, PyObject* arg_keywords) {
- const char* root;
- const char* file(NULL);
- const char* severity("INFO");
- bool buffer = false;
- int dbglevel(0);
- const char* const keywords[] = { "name", "severity", "debuglevel", "file",
- "buffer", NULL };
- if (!PyArg_ParseTupleAndKeywords(args, arg_keywords, "s|sizb",
- const_cast<char**>(keywords), &root,
- &severity, &dbglevel, &file, &buffer)) {
- return (NULL);
- }
- try {
- LoggerManager::init(root, getSeverity(severity), dbglevel, file,
- buffer);
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- Py_RETURN_NONE;
- }
- // This initialization is for unit tests. It allows message settings to
- // be determined by a set of B10_xxx environment variables. (See the
- // description of initLogger() for more details.) The function has been named
- // resetUnitTestRootLogger() here as being more descriptive and
- // trying to avoid confusion.
- PyObject*
- resetUnitTestRootLogger(PyObject*, PyObject*) {
- try {
- isc::log::resetUnitTestRootLogger();
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- Py_RETURN_NONE;
- }
- PyObject*
- logConfigUpdate(PyObject*, PyObject* args) {
- // we have no wrappers for ElementPtr and ConfigData,
- // So we expect JSON strings and convert them.
- // The new_config object is assumed to have been validated.
- const char* new_config_json;
- const char* mod_spec_json;
- if (!PyArg_ParseTuple(args, "ss",
- &new_config_json, &mod_spec_json)) {
- return (NULL);
- }
- try {
- isc::data::ConstElementPtr new_config =
- isc::data::Element::fromJSON(new_config_json);
- isc::data::ConstElementPtr mod_spec_e =
- isc::data::Element::fromJSON(mod_spec_json);
- isc::config::ModuleSpec mod_spec(mod_spec_e);
- isc::config::ConfigData config_data(mod_spec);
- isc::config::default_logconfig_handler("logging", new_config,
- config_data);
- Py_RETURN_NONE;
- } catch (const isc::data::JSONError& je) {
- std::string error_msg = std::string("JSON format error: ") + je.what();
- PyErr_SetString(PyExc_TypeError, error_msg.c_str());
- } catch (const isc::data::TypeError&) {
- PyErr_SetString(PyExc_TypeError, "argument 1 of log_config_update "
- "is not a map of config data");
- } catch (const isc::config::ModuleSpecError&) {
- PyErr_SetString(PyExc_TypeError, "argument 2 of log_config_update "
- "is not a correct module specification");
- } catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- } catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- }
- return (NULL);
- }
- PyMethodDef methods[] = {
- {"set_test_dictionary", setTestDictionary, METH_VARARGS,
- "Set or unset testing mode for message dictionary. In testing, "
- "the create_message and get_message functions work on different "
- "than the logger-global dictionary, not polluting it."},
- {"create_message", createMessage, METH_VARARGS,
- "Creates a new message in the dictionary. You shouldn't need to "
- "call this directly, it should be called by the generated message "
- "file. Returns the identifier to be used in logging. The text "
- "shouldn't be empty."},
- {"get_message", getMessage, METH_VARARGS,
- "Get a message. This function is for testing purposes and you don't "
- "need to call it. It returns None if the message does not exist."},
- {"reset", reset, METH_NOARGS,
- "Reset all logging. For testing purposes only, do not use."},
- {"init", reinterpret_cast<PyCFunction>(init), METH_VARARGS | METH_KEYWORDS,
- "Run-time initialization. You need to call this before you do any "
- "logging, to configure the root logger name. You may also provide "
- "Arguments:\n"
- "name: root logger name\n"
- "severity (optional): one of 'DEBUG', 'INFO', 'WARN', 'ERROR' or "
- "'FATAL'\n"
- "debuglevel (optional): a debug level (integer in the range 0-99) "
- "file (optional): a file name of a dictionary with message text "
- "translations\n"
- "buffer (optional), boolean, when True, causes all log messages "
- "to be stored internally until log_config_update is called, at "
- "which point they shall be logged."},
- {"resetUnitTestRootLogger", resetUnitTestRootLogger, METH_VARARGS,
- "Resets the configuration of the root logger to that set by the "
- "B10_XXX environment variables. It is aimed at unit tests, where "
- "the logging is initialized by the code under test; called before "
- "the unit test starts, this function resets the logging configuration "
- "to that in use for the C++ unit tests."},
- {"log_config_update", logConfigUpdate, METH_VARARGS,
- "Update logger settings. This method is automatically used when "
- "ModuleCCSession is initialized with handle_logging_config set "
- "to True. When called, the first argument is the new logging "
- "configuration (in JSON format). The second argument is "
- "the raw specification (as returned from "
- "ConfigData.get_module_spec().get_full_spec(), and converted to "
- "JSON format).\n"
- "Raises a TypeError if either argument is not a (correct) JSON "
- "string, or if the spec is not a correct spec.\n"
- "If this call succeeds, the global logger settings have "
- "been updated."
- },
- {NULL, NULL, 0, NULL}
- };
- class LoggerWrapper : public PyObject {
- // Everything is public here, as it is accessible only inside this .cc file.
- public:
- Logger *logger_;
- };
- extern PyTypeObject logger_type;
- int
- Logger_init(PyObject* po_self, PyObject* args, PyObject*) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- const char* name;
- if (!PyArg_ParseTuple(args, "s", &name)) {
- return (-1);
- }
- try {
- self->logger_ = new Logger(name);
- return (0);
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (-1);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (-1);
- }
- }
- void
- //Logger_destroy(LoggerWrapper* const self) {
- Logger_destroy(PyObject* po_self) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- delete self->logger_;
- self->logger_ = NULL;
- Py_TYPE(self)->tp_free(self);
- }
- // The isc::log doesn't contain function to convert this way
- const char*
- severityToText(const Severity& severity) {
- switch (severity) {
- case DEFAULT:
- return ("DEFAULT");
- case DEBUG:
- return ("DEBUG");
- case INFO:
- return ("INFO");
- case WARN:
- return ("WARN");
- case ERROR:
- return ("ERROR");
- case FATAL:
- return ("FATAL");
- default:
- return (NULL);
- }
- }
- PyObject*
- Logger_getEffectiveSeverity(PyObject* po_self, PyObject*) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- try {
- return (Py_BuildValue("s",
- severityToText(
- self->logger_->getEffectiveSeverity())));
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- }
- PyObject*
- Logger_getEffectiveDebugLevel(PyObject* po_self, PyObject*) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- try {
- return (Py_BuildValue("i", self->logger_->getEffectiveDebugLevel()));
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- }
- PyObject*
- Logger_setSeverity(PyObject* po_self, PyObject* args) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- const char* severity;
- int dbgLevel = 0;
- if (!PyArg_ParseTuple(args, "z|i", &severity, &dbgLevel)) {
- return (NULL);
- }
- try {
- self->logger_->setSeverity((severity == NULL) ? DEFAULT :
- getSeverity(severity), dbgLevel);
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- Py_RETURN_NONE;
- }
- template<class FPtr> // Who should remember the pointer-to-method syntax
- PyObject*
- Logger_isLevelEnabled(LoggerWrapper* self, FPtr function) {
- try {
- if ((self->logger_->*function)()) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- }
- PyObject*
- Logger_isInfoEnabled(PyObject* po_self, PyObject*) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- return (Logger_isLevelEnabled(self, &Logger::isInfoEnabled));
- }
- PyObject*
- Logger_isWarnEnabled(PyObject* po_self, PyObject*) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- return (Logger_isLevelEnabled(self, &Logger::isWarnEnabled));
- }
- PyObject*
- Logger_isErrorEnabled(PyObject* po_self, PyObject*) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- return (Logger_isLevelEnabled(self, &Logger::isErrorEnabled));
- }
- PyObject*
- Logger_isFatalEnabled(PyObject* po_self, PyObject*) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- return (Logger_isLevelEnabled(self, &Logger::isFatalEnabled));
- }
- PyObject*
- Logger_isDebugEnabled(PyObject* po_self, PyObject* args) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- int level = MIN_DEBUG_LEVEL;
- if (!PyArg_ParseTuple(args, "|i", &level)) {
- return (NULL);
- }
- try {
- if (self->logger_->isDebugEnabled(level)) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- }
- string
- objectToStr(PyObject* object, bool convert) {
- PyObjectContainer objstr_container;
- if (convert) {
- PyObject* text_obj = PyObject_Str(object);
- if (text_obj == NULL) {
- // PyObject_Str could fail for various reasons, including because
- // the object cannot be converted to a string. We exit with
- // InternalError to preserve the PyErr set in PyObject_Str.
- throw InternalError();
- }
- objstr_container.reset(text_obj);
- object = objstr_container.get();
- }
- PyObjectContainer tuple_container(Py_BuildValue("(O)", object));
- const char* value;
- if (!PyArg_ParseTuple(tuple_container.get(), "s", &value)) {
- throw InternalError();
- }
- return (string(value));
- }
- // Generic function to output the logging message. Called by the real functions.
- template <class Function>
- PyObject*
- Logger_performOutput(Function function, PyObject* args, bool dbgLevel) {
- try {
- const Py_ssize_t number(PyObject_Length(args));
- if (number < 0) {
- return (NULL);
- }
- // Which argument is the first to format?
- const size_t start = dbgLevel ? 2 : 1;
- if (number < start) {
- return (PyErr_Format(PyExc_TypeError, "Too few arguments to "
- "logging call, at least %zu needed and %zd "
- "given", start, number));
- }
- // Extract the fixed arguments
- long dbg(0);
- if (dbgLevel) {
- PyObjectContainer dbg_container(PySequence_GetItem(args, 0));
- dbg = PyLong_AsLong(dbg_container.get());
- if (PyErr_Occurred()) {
- return (NULL);
- }
- }
- // We create the logging message right now. If we fail to convert a
- // parameter to string, at least the part that we already did will
- // be output
- PyObjectContainer msgid_container(PySequence_GetItem(args, start - 1));
- const string mid(objectToStr(msgid_container.get(), false));
- Logger::Formatter formatter(function(dbg, mid.c_str()));
- // Now process the rest of parameters, convert each to string and put
- // into the formatter. It will print itself in the end.
- for (size_t i(start); i < number; ++ i) {
- PyObjectContainer param_container(PySequence_GetItem(args, i));
- try {
- formatter = formatter.arg(objectToStr(param_container.get(),
- true));
- }
- catch (...) {
- formatter.deactivate();
- throw;
- }
- }
- Py_RETURN_NONE;
- }
- catch (const InternalError&) {
- return (NULL);
- }
- catch (const std::exception& e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
- return (NULL);
- }
- catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return (NULL);
- }
- }
- // Now map the functions into the performOutput. I wish C++ could do
- // functional programming.
- PyObject*
- Logger_debug(PyObject* po_self, PyObject* args) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- return (Logger_performOutput(bind(&Logger::debug, self->logger_, _1, _2),
- args, true));
- }
- PyObject*
- Logger_info(PyObject* po_self, PyObject* args) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- return (Logger_performOutput(bind(&Logger::info, self->logger_, _2),
- args, false));
- }
- PyObject*
- Logger_warn(PyObject* po_self, PyObject* args) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- return (Logger_performOutput(bind(&Logger::warn, self->logger_, _2),
- args, false));
- }
- PyObject*
- Logger_error(PyObject* po_self, PyObject* args) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- return (Logger_performOutput(bind(&Logger::error, self->logger_, _2),
- args, false));
- }
- PyObject*
- Logger_fatal(PyObject* po_self, PyObject* args) {
- LoggerWrapper* self = static_cast<LoggerWrapper*>(po_self);
- return (Logger_performOutput(bind(&Logger::fatal, self->logger_, _2),
- args, false));
- }
- PyMethodDef loggerMethods[] = {
- { "get_effective_severity", Logger_getEffectiveSeverity, METH_NOARGS,
- "Returns the effective logging severity as string" },
- { "get_effective_debug_level", Logger_getEffectiveDebugLevel, METH_NOARGS,
- "Returns the current debug level." },
- { "set_severity", Logger_setSeverity, METH_VARARGS,
- "Sets the severity of a logger. The parameters are severity as a "
- "string and, optionally, a debug level (integer in range 0-99). "
- "The severity may be NULL, in which case an inherited value is taken."
- },
- { "is_debug_enabled", Logger_isDebugEnabled, METH_VARARGS,
- "Returns if the logger would log debug message now. "
- "You can provide a desired debug level." },
- { "is_info_enabled", Logger_isInfoEnabled, METH_NOARGS,
- "Returns if the logger would log info message now." },
- { "is_warn_enabled", Logger_isWarnEnabled, METH_NOARGS,
- "Returns if the logger would log warn message now." },
- { "is_error_enabled", Logger_isErrorEnabled, METH_NOARGS,
- "Returns if the logger would log error message now." },
- { "is_fatal_enabled", Logger_isFatalEnabled, METH_NOARGS,
- "Returns if the logger would log fatal message now." },
- { "debug", Logger_debug, METH_VARARGS,
- "Logs a debug-severity message. It takes the debug level, message ID "
- "and any number of stringifiable arguments to the message." },
- { "info", Logger_info, METH_VARARGS,
- "Logs a info-severity message. It taskes the message ID and any "
- "number of stringifiable arguments to the message." },
- { "warn", Logger_warn, METH_VARARGS,
- "Logs a warn-severity message. It taskes the message ID and any "
- "number of stringifiable arguments to the message." },
- { "error", Logger_error, METH_VARARGS,
- "Logs a error-severity message. It taskes the message ID and any "
- "number of stringifiable arguments to the message." },
- { "fatal", Logger_fatal, METH_VARARGS,
- "Logs a fatal-severity message. It taskes the message ID and any "
- "number of stringifiable arguments to the message." },
- { NULL, NULL, 0, NULL }
- };
- PyTypeObject logger_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "isc.log.Logger",
- sizeof(LoggerWrapper), // tp_basicsize
- 0, // tp_itemsize
- Logger_destroy, // tp_dealloc
- NULL, // tp_print
- NULL, // tp_getattr
- NULL, // tp_setattr
- NULL, // tp_reserved
- NULL, // tp_repr
- NULL, // tp_as_number
- NULL, // tp_as_sequence
- NULL, // tp_as_mapping
- NULL, // tp_hash
- NULL, // tp_call
- NULL, // tp_str
- NULL, // tp_getattro
- NULL, // tp_setattro
- NULL, // tp_as_buffer
- Py_TPFLAGS_DEFAULT, // tp_flags
- "Wrapper around the C++ isc::log::Logger class."
- "It is not complete, but everything important should be here.",
- NULL, // tp_traverse
- NULL, // tp_clear
- NULL, // tp_richcompare
- 0, // tp_weaklistoffset
- NULL, // tp_iter
- NULL, // tp_iternext
- loggerMethods, // tp_methods
- NULL, // tp_members
- NULL, // tp_getset
- NULL, // tp_base
- NULL, // tp_dict
- NULL, // tp_descr_get
- NULL, // tp_descr_set
- 0, // tp_dictoffset
- Logger_init, // tp_init
- NULL, // tp_alloc
- PyType_GenericNew, // tp_new
- NULL, // tp_free
- NULL, // tp_is_gc
- NULL, // tp_bases
- NULL, // tp_mro
- NULL, // tp_cache
- NULL, // tp_subclasses
- NULL, // tp_weaklist
- NULL, // tp_del
- 0 // tp_version_tag
- };
- PyModuleDef iscLog = {
- { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
- "log",
- "Python bindings for the classes in the isc::log namespace.\n\n"
- "These bindings are close match to the C++ API, but they are not complete "
- "(some parts are not needed) and some are done in more python-like ways.",
- -1,
- methods,
- NULL,
- NULL,
- NULL,
- NULL
- };
- } // end anonymous namespace
- PyMODINIT_FUNC
- PyInit_log(void) {
- PyObject* mod = PyModule_Create(&iscLog);
- if (mod == NULL) {
- return (NULL);
- }
- // Finalize logger class and add in the definitions of the standard debug
- // levels. These can then be referred to in Python through the constants
- // log.DBGLVL_XXX.
- // N.B. These should be kept in sync with the constants defined in
- // log_dbglevels.h.
- try {
- if (PyType_Ready(&logger_type) < 0) {
- throw InternalError();
- }
- void* p = &logger_type;
- if (PyModule_AddObject(mod, "Logger",
- static_cast<PyObject*>(p)) < 0) {
- throw InternalError();
- }
- installClassVariable(logger_type, "DBGLVL_START_SHUT",
- Py_BuildValue("I", DBGLVL_START_SHUT));
- installClassVariable(logger_type, "DBGLVL_COMMAND",
- Py_BuildValue("I", DBGLVL_COMMAND));
- installClassVariable(logger_type, "DBGLVL_COMMAND_DATA",
- Py_BuildValue("I", DBGLVL_COMMAND_DATA));
- installClassVariable(logger_type, "DBGLVL_TRACE_BASIC",
- Py_BuildValue("I", DBGLVL_TRACE_BASIC));
- installClassVariable(logger_type, "DBGLVL_TRACE_BASIC_DATA",
- Py_BuildValue("I", DBGLVL_TRACE_BASIC_DATA));
- installClassVariable(logger_type, "DBGLVL_TRACE_DETAIL",
- Py_BuildValue("I", DBGLVL_TRACE_DETAIL));
- installClassVariable(logger_type, "DBGLVL_TRACE_DETAIL_DATA",
- Py_BuildValue("I", DBGLVL_TRACE_DETAIL_DATA));
- } catch (const InternalError&) {
- Py_DECREF(mod);
- return (NULL);
- } catch (const std::exception& ex) {
- const std::string ex_what =
- "Unexpected failure in Log initialization: " +
- std::string(ex.what());
- PyErr_SetString(PyExc_SystemError, ex_what.c_str());
- Py_DECREF(mod);
- return (NULL);
- } catch (...) {
- PyErr_SetString(PyExc_SystemError,
- "Unexpected failure in Log initialization");
- Py_DECREF(mod);
- return (NULL);
- }
- Py_INCREF(&logger_type);
- return (mod);
- }
|