log.cc 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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. using namespace isc::log;
  22. namespace {
  23. // This is for testing only. The real module will have it always set as
  24. // NULL and will use the global dictionary.
  25. MessageDictionary* testDictionary = NULL;
  26. PyObject*
  27. setTestDictionary(PyObject*, PyObject* args) {
  28. PyObject* enableO;
  29. // The API doesn't seem to provide conversion to bool,
  30. // so we do it little bit manually
  31. if (!PyArg_ParseTuple(args, "O", &enableO)) {
  32. return (NULL);
  33. }
  34. int enableI(PyObject_IsTrue(enableO));
  35. if (enableI == -1) {
  36. return (NULL);
  37. }
  38. bool enable(enableI != 0);
  39. delete testDictionary;
  40. testDictionary = NULL;
  41. try {
  42. if (enable) {
  43. testDictionary = new MessageDictionary;
  44. }
  45. }
  46. catch (const std::exception& e) {
  47. PyErr_SetString(PyExc_RuntimeError, e.what());
  48. return (NULL);
  49. }
  50. catch (...) {
  51. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  52. return (NULL);
  53. }
  54. Py_RETURN_NONE;
  55. }
  56. PyObject*
  57. createMessage(PyObject*, PyObject* args) {
  58. const char* mid;
  59. const char* text;
  60. // We parse the strings
  61. if (!PyArg_ParseTuple(args, "ss", &mid, &text)) {
  62. return (NULL);
  63. }
  64. PyObject* origMid;
  65. // And extract the original representation of the message
  66. // ID, so we can return it instead of creating another instance.
  67. // This call shouldn't fail if the previous suceeded.
  68. if (!PyArg_ParseTuple(args, "Os", &origMid, &text)) {
  69. return (NULL);
  70. }
  71. try {
  72. MessageDictionary* dict = testDictionary ? testDictionary :
  73. &MessageDictionary::globalDictionary();
  74. // We ignore the result, they will be in some kind of dupe list
  75. // if there's a problem
  76. dict->add(mid, text);
  77. }
  78. catch (const std::exception& e) {
  79. PyErr_SetString(PyExc_RuntimeError, e.what());
  80. return (NULL);
  81. }
  82. catch (...) {
  83. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  84. return (NULL);
  85. }
  86. // Return the ID
  87. Py_INCREF(origMid);
  88. return (origMid);
  89. }
  90. PyObject*
  91. getMessage(PyObject*, PyObject* args) {
  92. const char* mid;
  93. if (!PyArg_ParseTuple(args, "s", &mid)) {
  94. return (NULL);
  95. }
  96. try {
  97. MessageDictionary* dict = testDictionary ? testDictionary :
  98. &MessageDictionary::globalDictionary();
  99. const std::string& result(dict->getText(mid));
  100. if (result.empty()) {
  101. Py_RETURN_NONE;
  102. } else {
  103. return (Py_BuildValue("s", result.c_str()));
  104. }
  105. }
  106. catch (const std::exception& e) {
  107. PyErr_SetString(PyExc_RuntimeError, e.what());
  108. return (NULL);
  109. }
  110. catch (...) {
  111. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  112. return (NULL);
  113. }
  114. }
  115. PyObject*
  116. reset(PyObject*, PyObject*) {
  117. // TODO Should we check we got exactly 0 arguments?
  118. // But who cares, it's testing function only
  119. LoggerManager::reset();
  120. Py_RETURN_NONE;
  121. }
  122. PyObject*
  123. init(PyObject*, PyObject* args) {
  124. const char* root;
  125. const char* file(NULL);
  126. const char* severity("INFO");
  127. int dbglevel(0);
  128. if (!PyArg_ParseTuple(args, "s|zsi", &root, &file, &severity, &dbglevel)) {
  129. return (NULL);
  130. }
  131. try {
  132. LoggerManager::init(root, file, getSeverity(severity), dbglevel);
  133. }
  134. catch (const std::exception& e) {
  135. PyErr_SetString(PyExc_RuntimeError, e.what());
  136. return (NULL);
  137. }
  138. catch (...) {
  139. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  140. return (NULL);
  141. }
  142. Py_RETURN_NONE;
  143. }
  144. PyMethodDef methods[] = {
  145. {"set_test_dictionary", &setTestDictionary, METH_VARARGS,
  146. "Set or unset testing mode for message dictionary. In testing, "
  147. "the create_message and get_message functions work on different "
  148. "than the logger-global dictionary, not polluting it."},
  149. {"create_message", &createMessage, METH_VARARGS,
  150. "Creates a new message in the dictionary. You shouldn't need to "
  151. "call this directly, it should be called by the generated message "
  152. "file. Returns the identifier to be used in logging. The text "
  153. "shouldn't be empty."},
  154. {"get_message", &getMessage, METH_VARARGS,
  155. "Get a message. This function is for testing purposes and you don't "
  156. "need to call it. It returns None if the message does not exist."},
  157. {"reset", &reset, METH_VARARGS,
  158. "Reset all logging. For testing purposes only, do not use."},
  159. {"init", &init, METH_VARARGS,
  160. "Run-time initialization. You need to call this before you do any "
  161. "logging, to configure the root logger name. You may also provide "
  162. "a filename with message translations (or None if you don't want "
  163. "any), logging severity (one of 'DEBUG', 'INFO', 'WARN', 'ERROR' or "
  164. "'FATAL') and a debug level (integer in the range 0-99)."},
  165. {NULL, NULL, 0, NULL}
  166. };
  167. class LoggerWrapper : public PyObject {
  168. // Everything is public here, as it is accessible only inside this .cc file.
  169. public:
  170. Logger *logger_;
  171. };
  172. extern PyTypeObject logger_type;
  173. int
  174. Logger_init(LoggerWrapper* self, PyObject* args) {
  175. const char* name;
  176. if (!PyArg_ParseTuple(args, "s", &name)) {
  177. return (-1);
  178. }
  179. try {
  180. self->logger_ = new Logger(name);
  181. return (0);
  182. }
  183. catch (const std::exception& e) {
  184. PyErr_SetString(PyExc_RuntimeError, e.what());
  185. return (-1);
  186. }
  187. catch (...) {
  188. PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
  189. return (-1);
  190. }
  191. }
  192. void
  193. Logger_destroy(LoggerWrapper* const self) {
  194. delete self->logger_;
  195. self->logger_ = NULL;
  196. Py_TYPE(self)->tp_free(self);
  197. }
  198. PyMethodDef loggerMethods[] = {
  199. { NULL, NULL, 0, NULL }
  200. };
  201. PyTypeObject logger_type = {
  202. PyVarObject_HEAD_INIT(NULL, 0)
  203. "isc.log.Logger",
  204. sizeof(LoggerWrapper), // tp_basicsize
  205. 0, // tp_itemsize
  206. reinterpret_cast<destructor>(Logger_destroy), // tp_dealloc
  207. NULL, // tp_print
  208. NULL, // tp_getattr
  209. NULL, // tp_setattr
  210. NULL, // tp_reserved
  211. NULL, // tp_repr
  212. NULL, // tp_as_number
  213. NULL, // tp_as_sequence
  214. NULL, // tp_as_mapping
  215. NULL, // tp_hash
  216. NULL, // tp_call
  217. NULL, // tp_str
  218. NULL, // tp_getattro
  219. NULL, // tp_setattro
  220. NULL, // tp_as_buffer
  221. Py_TPFLAGS_DEFAULT, // tp_flags
  222. "Wrapper around the C++ isc::log::Logger class."
  223. "It is not complete, but everything important should be here.",
  224. NULL, // tp_traverse
  225. NULL, // tp_clear
  226. NULL, // tp_richcompare
  227. 0, // tp_weaklistoffset
  228. NULL, // tp_iter
  229. NULL, // tp_iternext
  230. loggerMethods, // tp_methods
  231. NULL, // tp_members
  232. NULL, // tp_getset
  233. NULL, // tp_base
  234. NULL, // tp_dict
  235. NULL, // tp_descr_get
  236. NULL, // tp_descr_set
  237. 0, // tp_dictoffset
  238. reinterpret_cast<initproc>(Logger_init), // tp_init
  239. NULL, // tp_alloc
  240. PyType_GenericNew, // tp_new
  241. NULL, // tp_free
  242. NULL, // tp_is_gc
  243. NULL, // tp_bases
  244. NULL, // tp_mro
  245. NULL, // tp_cache
  246. NULL, // tp_subclasses
  247. NULL, // tp_weaklist
  248. NULL, // tp_del
  249. 0 // tp_version_tag
  250. };
  251. PyModuleDef iscLog = {
  252. { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
  253. "log",
  254. "Python bindings for the classes in the isc::log namespace.\n\n"
  255. "These bindings are close match to the C++ API, but they are not complete "
  256. "(some parts are not needed) and some are done in more python-like ways.",
  257. -1,
  258. methods,
  259. NULL,
  260. NULL,
  261. NULL,
  262. NULL
  263. };
  264. }
  265. PyMODINIT_FUNC
  266. PyInit_log(void) {
  267. PyObject* mod = PyModule_Create(&iscLog);
  268. if (mod == NULL) {
  269. return (NULL);
  270. }
  271. if (PyType_Ready(&logger_type) < 0) {
  272. return (NULL);
  273. }
  274. if (PyModule_AddObject(mod, "Logger",
  275. static_cast<PyObject*>(static_cast<void*>(
  276. &logger_type))) < 0) {
  277. return (NULL);
  278. }
  279. Py_INCREF(&logger_type);
  280. return (mod);
  281. }