log.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #define PY_SSIZE_T_CLEAN
  15. #include <Python.h>
  16. #include <structmember.h>
  17. #include <config.h>
  18. #include <log/message_dictionary.h>
  19. #include <log/logger_manager.h>
  20. #include <log/logger.h>
  21. #include <config/ccsession.h>
  22. #include <string>
  23. #include <boost/bind.hpp>
  24. using namespace isc::log;
  25. using std::string;
  26. using boost::bind;
  27. namespace {
  28. // This is for testing only. The real module will have it always set as
  29. // NULL and will use the global dictionary.
  30. MessageDictionary* testDictionary = NULL;
  31. // To propagate python exceptions trough our code
  32. // This exception is used to signal to the calling function that a
  33. // proper Python Exception has already been set, and the caller
  34. // should now return NULL.
  35. // Since it is only used internally, and should not pass any
  36. // information itself, is is not derived from std::exception
  37. class InternalError {};
  38. PyObject*
  39. setTestDictionary(PyObject*, PyObject* args) {
  40. PyObject* enableO;
  41. // The API doesn't seem to provide conversion to bool,
  42. // so we do it little bit manually
  43. if (!PyArg_ParseTuple(args, "O", &enableO)) {
  44. return (NULL);
  45. }
  46. int enableI(PyObject_IsTrue(enableO));
  47. if (enableI == -1) {
  48. return (NULL);
  49. }
  50. bool enable(enableI != 0);
  51. try {
  52. delete testDictionary;
  53. testDictionary = NULL;
  54. if (enable) {
  55. testDictionary = new MessageDictionary;
  56. }
  57. }
  58. catch (const std::exception& e) {
  59. PyErr_SetString(PyExc_RuntimeError, e.what());
  60. return (NULL);
  61. }
  62. catch (...) {
  63. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  64. return (NULL);
  65. }
  66. Py_RETURN_NONE;
  67. }
  68. PyObject*
  69. createMessage(PyObject*, PyObject* args) {
  70. const char* mid;
  71. const char* text;
  72. // We parse the strings
  73. if (!PyArg_ParseTuple(args, "ss", &mid, &text)) {
  74. return (NULL);
  75. }
  76. PyObject* origMid;
  77. // And extract the original representation of the message
  78. // ID, so we can return it instead of creating another instance.
  79. // This call shouldn't fail if the previous suceeded.
  80. if (!PyArg_ParseTuple(args, "Os", &origMid, &text)) {
  81. return (NULL);
  82. }
  83. try {
  84. MessageDictionary* dict = testDictionary ? testDictionary :
  85. &MessageDictionary::globalDictionary();
  86. // We ignore the result, they will be in some kind of dupe list
  87. // if there's a problem
  88. dict->add(mid, text);
  89. }
  90. catch (const std::exception& e) {
  91. PyErr_SetString(PyExc_RuntimeError, e.what());
  92. return (NULL);
  93. }
  94. catch (...) {
  95. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  96. return (NULL);
  97. }
  98. // Return the ID
  99. Py_INCREF(origMid);
  100. return (origMid);
  101. }
  102. PyObject*
  103. getMessage(PyObject*, PyObject* args) {
  104. const char* mid;
  105. if (!PyArg_ParseTuple(args, "s", &mid)) {
  106. return (NULL);
  107. }
  108. try {
  109. MessageDictionary* dict = testDictionary ? testDictionary :
  110. &MessageDictionary::globalDictionary();
  111. const std::string& result(dict->getText(mid));
  112. if (result.empty()) {
  113. Py_RETURN_NONE;
  114. } else {
  115. return (Py_BuildValue("s", result.c_str()));
  116. }
  117. }
  118. catch (const std::exception& e) {
  119. PyErr_SetString(PyExc_RuntimeError, e.what());
  120. return (NULL);
  121. }
  122. catch (...) {
  123. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  124. return (NULL);
  125. }
  126. }
  127. PyObject*
  128. reset(PyObject*, PyObject*) {
  129. LoggerManager::reset();
  130. Py_RETURN_NONE;
  131. }
  132. PyObject*
  133. init(PyObject*, PyObject* args) {
  134. const char* root;
  135. const char* file(NULL);
  136. const char* severity("INFO");
  137. int dbglevel(0);
  138. if (!PyArg_ParseTuple(args, "s|siz", &root, &severity, &dbglevel, &file)) {
  139. return (NULL);
  140. }
  141. try {
  142. LoggerManager::init(root, getSeverity(severity), dbglevel, file);
  143. }
  144. catch (const std::exception& e) {
  145. PyErr_SetString(PyExc_RuntimeError, e.what());
  146. return (NULL);
  147. }
  148. catch (...) {
  149. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  150. return (NULL);
  151. }
  152. Py_RETURN_NONE;
  153. }
  154. PyObject*
  155. logConfigUpdate(PyObject*, PyObject* args) {
  156. // we have no wrappers for ElementPtr and ConfigData,
  157. // So we expect JSON strings and convert them.
  158. // The new_config object is assumed to have been validated.
  159. const char* new_config_json;
  160. const char* mod_spec_json;
  161. if (!PyArg_ParseTuple(args, "ss",
  162. &new_config_json, &mod_spec_json)) {
  163. return (NULL);
  164. }
  165. try {
  166. isc::data::ConstElementPtr new_config =
  167. isc::data::Element::fromJSON(new_config_json);
  168. isc::data::ConstElementPtr mod_spec_e =
  169. isc::data::Element::fromJSON(mod_spec_json);
  170. isc::config::ModuleSpec mod_spec(mod_spec_e);
  171. isc::config::ConfigData config_data(mod_spec);
  172. isc::config::default_logconfig_handler("logging", new_config,
  173. config_data);
  174. Py_RETURN_NONE;
  175. } catch (const isc::data::JSONError& je) {
  176. std::string error_msg = std::string("JSON format error: ") + je.what();
  177. PyErr_SetString(PyExc_TypeError, error_msg.c_str());
  178. } catch (const isc::data::TypeError& de) {
  179. PyErr_SetString(PyExc_TypeError, "argument 1 of log_config_update "
  180. "is not a map of config data");
  181. } catch (const isc::config::ModuleSpecError& mse) {
  182. PyErr_SetString(PyExc_TypeError, "argument 2 of log_config_update "
  183. "is not a correct module specification");
  184. } catch (const std::exception& e) {
  185. PyErr_SetString(PyExc_RuntimeError, e.what());
  186. } catch (...) {
  187. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  188. }
  189. return (NULL);
  190. }
  191. PyMethodDef methods[] = {
  192. {"set_test_dictionary", setTestDictionary, METH_VARARGS,
  193. "Set or unset testing mode for message dictionary. In testing, "
  194. "the create_message and get_message functions work on different "
  195. "than the logger-global dictionary, not polluting it."},
  196. {"create_message", createMessage, METH_VARARGS,
  197. "Creates a new message in the dictionary. You shouldn't need to "
  198. "call this directly, it should be called by the generated message "
  199. "file. Returns the identifier to be used in logging. The text "
  200. "shouldn't be empty."},
  201. {"get_message", getMessage, METH_VARARGS,
  202. "Get a message. This function is for testing purposes and you don't "
  203. "need to call it. It returns None if the message does not exist."},
  204. {"reset", reset, METH_NOARGS,
  205. "Reset all logging. For testing purposes only, do not use."},
  206. {"init", init, METH_VARARGS,
  207. "Run-time initialization. You need to call this before you do any "
  208. "logging, to configure the root logger name. You may also provide "
  209. "logging severity (one of 'DEBUG', 'INFO', 'WARN', 'ERROR' or "
  210. "'FATAL'), a debug level (integer in the range 0-99) and a file name "
  211. "of a dictionary with message text translations."},
  212. {"log_config_update", logConfigUpdate, METH_VARARGS,
  213. "Update logger settings. This method is automatically used when "
  214. "ModuleCCSession is initialized with handle_logging_config set "
  215. "to True. When called, the first argument is the new logging "
  216. "configuration (in JSON format). The second argument is "
  217. "the raw specification (as returned from "
  218. "ConfigData.get_module_spec().get_full_spec(), and converted to "
  219. "JSON format).\n"
  220. "Raises a TypeError if either argument is not a (correct) JSON "
  221. "string, or if the spec is not a correct spec.\n"
  222. "If this call succeeds, the global logger settings have "
  223. "been updated."
  224. },
  225. {NULL, NULL, 0, NULL}
  226. };
  227. class LoggerWrapper : public PyObject {
  228. // Everything is public here, as it is accessible only inside this .cc file.
  229. public:
  230. Logger *logger_;
  231. };
  232. extern PyTypeObject logger_type;
  233. int
  234. Logger_init(LoggerWrapper* self, PyObject* args) {
  235. const char* name;
  236. if (!PyArg_ParseTuple(args, "s", &name)) {
  237. return (-1);
  238. }
  239. try {
  240. self->logger_ = new Logger(name);
  241. return (0);
  242. }
  243. catch (const std::exception& e) {
  244. PyErr_SetString(PyExc_RuntimeError, e.what());
  245. return (-1);
  246. }
  247. catch (...) {
  248. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  249. return (-1);
  250. }
  251. }
  252. void
  253. Logger_destroy(LoggerWrapper* const self) {
  254. delete self->logger_;
  255. self->logger_ = NULL;
  256. Py_TYPE(self)->tp_free(self);
  257. }
  258. // The isc::log doesn't contain function to convert this way
  259. const char*
  260. severityToText(const Severity& severity) {
  261. switch (severity) {
  262. case DEFAULT:
  263. return ("DEFAULT");
  264. case DEBUG:
  265. return ("DEBUG");
  266. case INFO:
  267. return ("INFO");
  268. case WARN:
  269. return ("WARN");
  270. case ERROR:
  271. return ("ERROR");
  272. case FATAL:
  273. return ("FATAL");
  274. default:
  275. return (NULL);
  276. }
  277. }
  278. PyObject*
  279. Logger_getEffectiveSeverity(LoggerWrapper* self, PyObject*) {
  280. try {
  281. return (Py_BuildValue("s",
  282. severityToText(
  283. self->logger_->getEffectiveSeverity())));
  284. }
  285. catch (const std::exception& e) {
  286. PyErr_SetString(PyExc_RuntimeError, e.what());
  287. return (NULL);
  288. }
  289. catch (...) {
  290. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  291. return (NULL);
  292. }
  293. }
  294. PyObject*
  295. Logger_getEffectiveDebugLevel(LoggerWrapper* self, PyObject*) {
  296. try {
  297. return (Py_BuildValue("i", self->logger_->getEffectiveDebugLevel()));
  298. }
  299. catch (const std::exception& e) {
  300. PyErr_SetString(PyExc_RuntimeError, e.what());
  301. return (NULL);
  302. }
  303. catch (...) {
  304. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  305. return (NULL);
  306. }
  307. }
  308. PyObject*
  309. Logger_setSeverity(LoggerWrapper* self, PyObject* args) {
  310. const char* severity;
  311. int dbgLevel = 0;
  312. if (!PyArg_ParseTuple(args, "z|i", &severity, &dbgLevel)) {
  313. return (NULL);
  314. }
  315. try {
  316. self->logger_->setSeverity((severity == NULL) ? DEFAULT :
  317. getSeverity(severity), dbgLevel);
  318. }
  319. catch (const std::exception& e) {
  320. PyErr_SetString(PyExc_RuntimeError, e.what());
  321. return (NULL);
  322. }
  323. catch (...) {
  324. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  325. return (NULL);
  326. }
  327. Py_RETURN_NONE;
  328. }
  329. template<class FPtr> // Who should remember the pointer-to-method syntax
  330. PyObject*
  331. Logger_isLevelEnabled(LoggerWrapper* self, FPtr function) {
  332. try {
  333. if ((self->logger_->*function)()) {
  334. Py_RETURN_TRUE;
  335. } else {
  336. Py_RETURN_FALSE;
  337. }
  338. }
  339. catch (const std::exception& e) {
  340. PyErr_SetString(PyExc_RuntimeError, e.what());
  341. return (NULL);
  342. }
  343. catch (...) {
  344. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  345. return (NULL);
  346. }
  347. }
  348. PyObject*
  349. Logger_isInfoEnabled(LoggerWrapper* self, PyObject*) {
  350. return (Logger_isLevelEnabled(self, &Logger::isInfoEnabled));
  351. }
  352. PyObject*
  353. Logger_isWarnEnabled(LoggerWrapper* self, PyObject*) {
  354. return (Logger_isLevelEnabled(self, &Logger::isWarnEnabled));
  355. }
  356. PyObject*
  357. Logger_isErrorEnabled(LoggerWrapper* self, PyObject*) {
  358. return (Logger_isLevelEnabled(self, &Logger::isErrorEnabled));
  359. }
  360. PyObject*
  361. Logger_isFatalEnabled(LoggerWrapper* self, PyObject*) {
  362. return (Logger_isLevelEnabled(self, &Logger::isFatalEnabled));
  363. }
  364. PyObject*
  365. Logger_isDebugEnabled(LoggerWrapper* self, PyObject* args) {
  366. int level = MIN_DEBUG_LEVEL;
  367. if (!PyArg_ParseTuple(args, "|i", &level)) {
  368. return (NULL);
  369. }
  370. try {
  371. if (self->logger_->isDebugEnabled(level)) {
  372. Py_RETURN_TRUE;
  373. } else {
  374. Py_RETURN_FALSE;
  375. }
  376. }
  377. catch (const std::exception& e) {
  378. PyErr_SetString(PyExc_RuntimeError, e.what());
  379. return (NULL);
  380. }
  381. catch (...) {
  382. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  383. return (NULL);
  384. }
  385. }
  386. string
  387. objectToStr(PyObject* object, bool convert) {
  388. PyObject* cleanup(NULL);
  389. if (convert) {
  390. object = cleanup = PyObject_Str(object);
  391. if (object == NULL) {
  392. throw InternalError();
  393. }
  394. }
  395. const char* value;
  396. PyObject* tuple(Py_BuildValue("(O)", object));
  397. if (tuple == NULL) {
  398. if (cleanup != NULL) {
  399. Py_DECREF(cleanup);
  400. }
  401. throw InternalError();
  402. }
  403. if (!PyArg_ParseTuple(tuple, "s", &value)) {
  404. Py_DECREF(tuple);
  405. if (cleanup != NULL) {
  406. Py_DECREF(cleanup);
  407. }
  408. throw InternalError();
  409. }
  410. string result(value);
  411. Py_DECREF(tuple);
  412. if (cleanup != NULL) {
  413. Py_DECREF(cleanup);
  414. }
  415. return (result);
  416. }
  417. // Generic function to output the logging message. Called by the real functions.
  418. template<class Function>
  419. PyObject*
  420. Logger_performOutput(Function function, PyObject* args, bool dbgLevel) {
  421. try {
  422. Py_ssize_t number(PyObject_Length(args));
  423. if (number < 0) {
  424. return (NULL);
  425. }
  426. // Which argument is the first to format?
  427. size_t start(1);
  428. if (dbgLevel) {
  429. start ++;
  430. }
  431. if (number < start) {
  432. return (PyErr_Format(PyExc_TypeError, "Too few arguments to "
  433. "logging call, at least %zu needed and %zd "
  434. "given", start, number));
  435. }
  436. // Extract the fixed arguments
  437. PyObject *midO(PySequence_GetItem(args, start - 1));
  438. if (midO == NULL) {
  439. return (NULL);
  440. }
  441. string mid(objectToStr(midO, false));
  442. long dbg(0);
  443. if (dbgLevel) {
  444. PyObject *dbgO(PySequence_GetItem(args, 0));
  445. if (dbgO == NULL) {
  446. return (NULL);
  447. }
  448. dbg = PyLong_AsLong(dbgO);
  449. if (PyErr_Occurred()) {
  450. return (NULL);
  451. }
  452. }
  453. // We create the logging message right now. If we fail to convert a
  454. // parameter to string, at least the part that we already did will
  455. // be output
  456. Logger::Formatter formatter(function(dbg, mid.c_str()));
  457. // Now process the rest of parameters, convert each to string and put
  458. // into the formatter. It will print itself in the end.
  459. for (size_t i(start); i < number; ++ i) {
  460. PyObject* param(PySequence_GetItem(args, i));
  461. if (param == NULL) {
  462. return (NULL);
  463. }
  464. formatter = formatter.arg(objectToStr(param, true));
  465. }
  466. Py_RETURN_NONE;
  467. }
  468. catch (const InternalError&) {
  469. return (NULL);
  470. }
  471. catch (const std::exception& e) {
  472. PyErr_SetString(PyExc_RuntimeError, e.what());
  473. return (NULL);
  474. }
  475. catch (...) {
  476. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  477. return (NULL);
  478. }
  479. }
  480. // Now map the functions into the performOutput. I wish C++ could do
  481. // functional programming.
  482. PyObject*
  483. Logger_debug(LoggerWrapper* self, PyObject* args) {
  484. return (Logger_performOutput(bind(&Logger::debug, self->logger_, _1, _2),
  485. args, true));
  486. }
  487. PyObject*
  488. Logger_info(LoggerWrapper* self, PyObject* args) {
  489. return (Logger_performOutput(bind(&Logger::info, self->logger_, _2),
  490. args, false));
  491. }
  492. PyObject*
  493. Logger_warn(LoggerWrapper* self, PyObject* args) {
  494. return (Logger_performOutput(bind(&Logger::warn, self->logger_, _2),
  495. args, false));
  496. }
  497. PyObject*
  498. Logger_error(LoggerWrapper* self, PyObject* args) {
  499. return (Logger_performOutput(bind(&Logger::error, self->logger_, _2),
  500. args, false));
  501. }
  502. PyObject*
  503. Logger_fatal(LoggerWrapper* self, PyObject* args) {
  504. return (Logger_performOutput(bind(&Logger::fatal, self->logger_, _2),
  505. args, false));
  506. }
  507. PyMethodDef loggerMethods[] = {
  508. { "get_effective_severity",
  509. reinterpret_cast<PyCFunction>(Logger_getEffectiveSeverity),
  510. METH_NOARGS, "Returns the effective logging severity as string" },
  511. { "get_effective_debug_level",
  512. reinterpret_cast<PyCFunction>(Logger_getEffectiveDebugLevel),
  513. METH_NOARGS, "Returns the current debug level." },
  514. { "set_severity",
  515. reinterpret_cast<PyCFunction>(Logger_setSeverity), METH_VARARGS,
  516. "Sets the severity of a logger. The parameters are severity as a "
  517. "string and, optionally, a debug level (integer in range 0-99). "
  518. "The severity may be NULL, in which case an inherited value is taken."
  519. },
  520. { "is_debug_enabled", reinterpret_cast<PyCFunction>(Logger_isDebugEnabled),
  521. METH_VARARGS, "Returns if the logger would log debug message now. "
  522. "You can provide a desired debug level." },
  523. { "is_info_enabled", reinterpret_cast<PyCFunction>(Logger_isInfoEnabled),
  524. METH_NOARGS, "Returns if the logger would log info message now." },
  525. { "is_warn_enabled", reinterpret_cast<PyCFunction>(Logger_isWarnEnabled),
  526. METH_NOARGS, "Returns if the logger would log warn message now." },
  527. { "is_error_enabled", reinterpret_cast<PyCFunction>(Logger_isErrorEnabled),
  528. METH_NOARGS, "Returns if the logger would log error message now." },
  529. { "is_fatal_enabled", reinterpret_cast<PyCFunction>(Logger_isFatalEnabled),
  530. METH_NOARGS, "Returns if the logger would log fatal message now." },
  531. { "debug", reinterpret_cast<PyCFunction>(Logger_debug), METH_VARARGS,
  532. "Logs a debug-severity message. It takes the debug level, message ID "
  533. "and any number of stringifiable arguments to the message." },
  534. { "info", reinterpret_cast<PyCFunction>(Logger_info), METH_VARARGS,
  535. "Logs a info-severity message. It taskes the message ID and any "
  536. "number of stringifiable arguments to the message." },
  537. { "warn", reinterpret_cast<PyCFunction>(Logger_warn), METH_VARARGS,
  538. "Logs a warn-severity message. It taskes the message ID and any "
  539. "number of stringifiable arguments to the message." },
  540. { "error", reinterpret_cast<PyCFunction>(Logger_error), METH_VARARGS,
  541. "Logs a error-severity message. It taskes the message ID and any "
  542. "number of stringifiable arguments to the message." },
  543. { "fatal", reinterpret_cast<PyCFunction>(Logger_fatal), METH_VARARGS,
  544. "Logs a fatal-severity message. It taskes the message ID and any "
  545. "number of stringifiable arguments to the message." },
  546. { NULL, NULL, 0, NULL }
  547. };
  548. PyTypeObject logger_type = {
  549. PyVarObject_HEAD_INIT(NULL, 0)
  550. "isc.log.Logger",
  551. sizeof(LoggerWrapper), // tp_basicsize
  552. 0, // tp_itemsize
  553. reinterpret_cast<destructor>(Logger_destroy), // tp_dealloc
  554. NULL, // tp_print
  555. NULL, // tp_getattr
  556. NULL, // tp_setattr
  557. NULL, // tp_reserved
  558. NULL, // tp_repr
  559. NULL, // tp_as_number
  560. NULL, // tp_as_sequence
  561. NULL, // tp_as_mapping
  562. NULL, // tp_hash
  563. NULL, // tp_call
  564. NULL, // tp_str
  565. NULL, // tp_getattro
  566. NULL, // tp_setattro
  567. NULL, // tp_as_buffer
  568. Py_TPFLAGS_DEFAULT, // tp_flags
  569. "Wrapper around the C++ isc::log::Logger class."
  570. "It is not complete, but everything important should be here.",
  571. NULL, // tp_traverse
  572. NULL, // tp_clear
  573. NULL, // tp_richcompare
  574. 0, // tp_weaklistoffset
  575. NULL, // tp_iter
  576. NULL, // tp_iternext
  577. loggerMethods, // tp_methods
  578. NULL, // tp_members
  579. NULL, // tp_getset
  580. NULL, // tp_base
  581. NULL, // tp_dict
  582. NULL, // tp_descr_get
  583. NULL, // tp_descr_set
  584. 0, // tp_dictoffset
  585. reinterpret_cast<initproc>(Logger_init), // tp_init
  586. NULL, // tp_alloc
  587. PyType_GenericNew, // tp_new
  588. NULL, // tp_free
  589. NULL, // tp_is_gc
  590. NULL, // tp_bases
  591. NULL, // tp_mro
  592. NULL, // tp_cache
  593. NULL, // tp_subclasses
  594. NULL, // tp_weaklist
  595. NULL, // tp_del
  596. 0 // tp_version_tag
  597. };
  598. PyModuleDef iscLog = {
  599. { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
  600. "log",
  601. "Python bindings for the classes in the isc::log namespace.\n\n"
  602. "These bindings are close match to the C++ API, but they are not complete "
  603. "(some parts are not needed) and some are done in more python-like ways.",
  604. -1,
  605. methods,
  606. NULL,
  607. NULL,
  608. NULL,
  609. NULL
  610. };
  611. } // end anonymous namespace
  612. PyMODINIT_FUNC
  613. PyInit_log(void) {
  614. PyObject* mod = PyModule_Create(&iscLog);
  615. if (mod == NULL) {
  616. return (NULL);
  617. }
  618. if (PyType_Ready(&logger_type) < 0) {
  619. return (NULL);
  620. }
  621. if (PyModule_AddObject(mod, "Logger",
  622. static_cast<PyObject*>(static_cast<void*>(
  623. &logger_type))) < 0) {
  624. return (NULL);
  625. }
  626. Py_INCREF(&logger_type);
  627. return (mod);
  628. }