123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- // 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.h>
- using namespace isc::log;
- 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);
- delete testDictionary;
- testDictionary = NULL;
- try {
- 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*) {
- // TODO Should we check we got exactly 0 arguments?
- // But who cares, it's testing function only
- LoggerManager::reset();
- Py_RETURN_NONE;
- }
- PyObject*
- init(PyObject*, PyObject* args) {
- const char* root;
- const char* file(NULL);
- const char* severity("INFO");
- int dbglevel(0);
- if (!PyArg_ParseTuple(args, "s|zsi", &root, &file, &severity, &dbglevel)) {
- return (NULL);
- }
- try {
- LoggerManager::init(root, file, 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;
- }
- 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_VARARGS,
- "Reset all logging. For testing purposes only, do not use."},
- {"init", &init, METH_VARARGS,
- "Run-time initialization. You need to call this before you do any "
- "logging, to configure the root logger name. You may also provide "
- "a filename with message translations (or None if you don't want "
- "any), logging severity (one of 'DEBUG', 'INFO', 'WARN', 'ERROR' or "
- "'FATAL') and a debug level (integer in the range 0-99)."},
- {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(LoggerWrapper* self, PyObject* args) {
- 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) {
- delete self->logger_;
- self->logger_ = NULL;
- Py_TYPE(self)->tp_free(self);
- }
- PyMethodDef loggerMethods[] = {
- { NULL, NULL, 0, NULL }
- };
- PyTypeObject logger_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "isc.log.Logger",
- sizeof(LoggerWrapper), // tp_basicsize
- 0, // tp_itemsize
- reinterpret_cast<destructor>(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
- reinterpret_cast<initproc>(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
- };
- }
- PyMODINIT_FUNC
- PyInit_log(void) {
- PyObject* mod = PyModule_Create(&iscLog);
- if (mod == NULL) {
- return (NULL);
- }
- if (PyType_Ready(&logger_type) < 0) {
- return (NULL);
- }
- if (PyModule_AddObject(mod, "Logger",
- static_cast<PyObject*>(static_cast<void*>(
- &logger_type))) < 0) {
- return (NULL);
- }
- Py_INCREF(&logger_type);
- return (mod);
- }
|