1 /*-*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Steven Hiscocks, Zbigniew Jędrzejewski-Szmek
8 systemd 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.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <structmember.h>
28 #include <systemd/sd-journal.h>
40 static PyTypeObject ReaderType;
43 PyDoc_STRVAR(module__doc__,
44 "Class to reads the systemd journal similar to journalctl.");
47 #if PY_MAJOR_VERSION >= 3
48 static PyTypeObject MonotonicType;
50 PyDoc_STRVAR(MonotonicType__doc__,
51 "A tuple of (timestamp, bootid) for holding monotonic timestamps");
53 static PyStructSequence_Field MonotonicType_fields[] = {
54 {(char*) "timestamp", (char*) "Time"},
55 {(char*) "bootid", (char*) "Unique identifier of the boot"},
59 static PyStructSequence_Desc Monotonic_desc = {
60 (char*) "journal.Monotonic",
68 * Convert a Python sequence object into a strv (char**), and
69 * None into a NULL pointer.
71 static int strv_converter(PyObject* obj, void *_result) {
72 char ***result = _result;
85 if (!PySequence_Check(obj))
88 len = PySequence_Length(obj);
89 *result = new0(char*, len + 1);
91 set_error(-ENOMEM, NULL, NULL);
95 for (i = 0; i < len; i++) {
97 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
103 item = PySequence_ITEM(obj, i);
104 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
105 r = PyUnicode_FSConverter(item, &bytes);
109 s = PyBytes_AsString(bytes);
111 s = PyString_AsString(item);
132 static void Reader_dealloc(Reader* self)
134 sd_journal_close(self->j);
135 Py_TYPE(self)->tp_free((PyObject*)self);
138 PyDoc_STRVAR(Reader__doc__,
139 "_Reader([flags | path | files]) -> ...\n\n"
140 "_Reader allows filtering and retrieval of Journal entries.\n"
141 "Note: this is a low-level interface, and probably not what you\n"
142 "want, use systemd.journal.Reader instead.\n\n"
143 "Argument `flags` sets open flags of the journal, which can be one\n"
144 "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n"
145 "journal on local machine only; RUNTIME_ONLY opens only\n"
146 "volatile journal files; and SYSTEM opens journal files of\n"
147 "system services and the kernel, and CURRENT_USER opens files\n"
148 "of the current user.\n\n"
149 "Argument `path` is the directory of journal files.\n"
150 "Argument `files` is a list of files. Note that\n"
151 "`flags`, `path`, and `files` are exclusive.\n\n"
152 "_Reader implements the context manager protocol: the journal\n"
153 "will be closed when exiting the block.");
154 static int Reader_init(Reader *self, PyObject *args, PyObject *keywds)
160 static const char* const kwlist[] = {"flags", "path", "files", NULL};
161 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izO&:__init__", (char**) kwlist,
162 &flags, &path, strv_converter, &files))
165 if (!!flags + !!path + !!files > 1) {
166 PyErr_SetString(PyExc_ValueError, "cannot use more than one of flags, path, and files");
171 flags = SD_JOURNAL_LOCAL_ONLY;
173 Py_BEGIN_ALLOW_THREADS
175 r = sd_journal_open_directory(&self->j, path, 0);
177 r = sd_journal_open_files(&self->j, (const char**) files, 0);
179 r = sd_journal_open(&self->j, flags);
182 return set_error(r, path, "Invalid flags or path");
186 PyDoc_STRVAR(Reader_fileno__doc__,
187 "fileno() -> int\n\n"
188 "Get a file descriptor to poll for changes in the journal.\n"
189 "This method invokes sd_journal_get_fd().\n"
190 "See man:sd_journal_get_fd(3).");
191 static PyObject* Reader_fileno(Reader *self, PyObject *args)
193 int fd = sd_journal_get_fd(self->j);
194 set_error(fd, NULL, NULL);
197 return long_FromLong(fd);
201 PyDoc_STRVAR(Reader_reliable_fd__doc__,
202 "reliable_fd() -> bool\n\n"
203 "Returns True iff the journal can be polled reliably.\n"
204 "This method invokes sd_journal_reliable_fd().\n"
205 "See man:sd_journal_reliable_fd(3).");
206 static PyObject* Reader_reliable_fd(Reader *self, PyObject *args)
208 int r = sd_journal_reliable_fd(self->j);
209 set_error(r, NULL, NULL);
212 return PyBool_FromLong(r);
216 PyDoc_STRVAR(Reader_get_events__doc__,
217 "get_events() -> int\n\n"
218 "Returns a mask of poll() events to wait for on the file\n"
219 "descriptor returned by .fileno().\n\n"
220 "See man:sd_journal_get_events(3) for further discussion.");
221 static PyObject* Reader_get_events(Reader *self, PyObject *args)
223 int r = sd_journal_get_events(self->j);
224 set_error(r, NULL, NULL);
227 return long_FromLong(r);
231 PyDoc_STRVAR(Reader_get_timeout__doc__,
232 "get_timeout() -> int or None\n\n"
233 "Returns a timeout value for usage in poll(), the time since the\n"
234 "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
236 "The return value must be converted to a relative timeout in\n"
237 "milliseconds if it is to be used as an argument for poll().\n"
238 "See man:sd_journal_get_timeout(3) for further discussion.");
239 static PyObject* Reader_get_timeout(Reader *self, PyObject *args)
244 r = sd_journal_get_timeout(self->j, &t);
245 set_error(r, NULL, NULL);
249 if (t == (uint64_t) -1)
252 assert_cc(sizeof(unsigned long long) == sizeof(t));
253 return PyLong_FromUnsignedLongLong(t);
257 PyDoc_STRVAR(Reader_get_timeout_ms__doc__,
258 "get_timeout_ms() -> int\n\n"
259 "Returns a timeout value suitable for usage in poll(), the value\n"
260 "returned by .get_timeout() converted to relative ms, or -1 if\n"
261 "no timeout is necessary.");
262 static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args)
267 r = sd_journal_get_timeout(self->j, &t);
268 set_error(r, NULL, NULL);
272 return absolute_timeout(t);
276 PyDoc_STRVAR(Reader_close__doc__,
277 "close() -> None\n\n"
278 "Free resources allocated by this Reader object.\n"
279 "This method invokes sd_journal_close().\n"
280 "See man:sd_journal_close(3).");
281 static PyObject* Reader_close(Reader *self, PyObject *args)
286 sd_journal_close(self->j);
292 PyDoc_STRVAR(Reader_get_usage__doc__,
293 "get_usage() -> int\n\n"
294 "Returns the total disk space currently used by journal\n"
295 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
296 "passed when opening the journal this value will only reflect\n"
297 "the size of journal files of the local host, otherwise\n"
299 "This method invokes sd_journal_get_usage().\n"
300 "See man:sd_journal_get_usage(3).");
301 static PyObject* Reader_get_usage(Reader *self, PyObject *args)
306 r = sd_journal_get_usage(self->j, &bytes);
307 if (set_error(r, NULL, NULL))
310 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
311 return PyLong_FromUnsignedLongLong(bytes);
315 PyDoc_STRVAR(Reader___enter____doc__,
316 "__enter__() -> self\n\n"
317 "Part of the context manager protocol.\n"
319 static PyObject* Reader___enter__(PyObject *self, PyObject *args)
328 PyDoc_STRVAR(Reader___exit____doc__,
329 "__exit__(type, value, traceback) -> None\n\n"
330 "Part of the context manager protocol.\n"
331 "Closes the journal.\n");
332 static PyObject* Reader___exit__(Reader *self, PyObject *args)
334 return Reader_close(self, args);
338 PyDoc_STRVAR(Reader_next__doc__,
339 "next([skip]) -> bool\n\n"
340 "Go to the next log entry. Optional skip value means to go to\n"
341 "the `skip`\\-th log entry.\n"
342 "Returns False if at end of file, True otherwise.");
343 static PyObject* Reader_next(Reader *self, PyObject *args)
348 if (!PyArg_ParseTuple(args, "|L:next", &skip))
352 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
356 Py_BEGIN_ALLOW_THREADS
358 r = sd_journal_next(self->j);
359 else if (skip == -1LL)
360 r = sd_journal_previous(self->j);
362 r = sd_journal_next_skip(self->j, skip);
363 else if (skip < -1LL)
364 r = sd_journal_previous_skip(self->j, -skip);
366 assert_not_reached("should not be here");
369 set_error(r, NULL, NULL);
372 return PyBool_FromLong(r);
375 PyDoc_STRVAR(Reader_previous__doc__,
376 "previous([skip]) -> bool\n\n"
377 "Go to the previous log entry. Optional skip value means to \n"
378 "go to the `skip`\\-th previous log entry.\n"
379 "Returns False if at start of file, True otherwise.");
380 static PyObject* Reader_previous(Reader *self, PyObject *args)
383 if (!PyArg_ParseTuple(args, "|L:previous", &skip))
386 return PyObject_CallMethod((PyObject *)self, (char*) "_next",
391 static int extract(const char* msg, size_t msg_len,
392 PyObject **key, PyObject **value) {
393 PyObject *k = NULL, *v;
394 const char *delim_ptr;
396 delim_ptr = memchr(msg, '=', msg_len);
398 PyErr_SetString(PyExc_OSError,
399 "journal gave us a field without '='");
404 k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
410 v = PyBytes_FromStringAndSize(delim_ptr + 1,
411 (const char*) msg + msg_len - (delim_ptr + 1));
426 PyDoc_STRVAR(Reader_get__doc__,
427 "get(str) -> str\n\n"
428 "Return data associated with this key in current log entry.\n"
429 "Throws KeyError is the data is not available.");
430 static PyObject* Reader_get(Reader *self, PyObject *args)
441 if (!PyArg_ParseTuple(args, "s:get", &field))
444 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
446 PyErr_SetString(PyExc_KeyError, field);
448 } else if (set_error(r, NULL, "field name is not valid"))
451 r = extract(msg, msg_len, NULL, &value);
458 PyDoc_STRVAR(Reader_get_all__doc__,
459 "_get_all() -> dict\n\n"
460 "Return dictionary of the current log entry.");
461 static PyObject* Reader_get_all(Reader *self, PyObject *args)
472 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
473 _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL;
475 r = extract(msg, msg_len, &key, &value);
479 if (PyDict_Contains(dict, key)) {
480 PyObject *cur_value = PyDict_GetItem(dict, key);
482 if (PyList_CheckExact(cur_value)) {
483 r = PyList_Append(cur_value, value);
487 _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0);
491 r = PyList_Append(tmp_list, cur_value);
495 r = PyList_Append(tmp_list, value);
499 r = PyDict_SetItem(dict, key, tmp_list);
504 r = PyDict_SetItem(dict, key, value);
518 PyDoc_STRVAR(Reader_get_realtime__doc__,
519 "get_realtime() -> int\n\n"
520 "Return the realtime timestamp for the current journal entry\n"
521 "in microseconds.\n\n"
522 "Wraps sd_journal_get_realtime_usec().\n"
523 "See man:sd_journal_get_realtime_usec(3).");
524 static PyObject* Reader_get_realtime(Reader *self, PyObject *args)
532 r = sd_journal_get_realtime_usec(self->j, ×tamp);
533 if (set_error(r, NULL, NULL))
536 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
537 return PyLong_FromUnsignedLongLong(timestamp);
541 PyDoc_STRVAR(Reader_get_monotonic__doc__,
542 "get_monotonic() -> (timestamp, bootid)\n\n"
543 "Return the monotonic timestamp for the current journal entry\n"
544 "as a tuple of time in microseconds and bootid.\n\n"
545 "Wraps sd_journal_get_monotonic_usec().\n"
546 "See man:sd_journal_get_monotonic_usec(3).");
547 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args)
551 PyObject *monotonic, *bootid, *tuple;
557 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
558 if (set_error(r, NULL, NULL))
561 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
562 monotonic = PyLong_FromUnsignedLongLong(timestamp);
563 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
564 #if PY_MAJOR_VERSION >= 3
565 tuple = PyStructSequence_New(&MonotonicType);
567 tuple = PyTuple_New(2);
569 if (!monotonic || !bootid || !tuple) {
570 Py_XDECREF(monotonic);
576 #if PY_MAJOR_VERSION >= 3
577 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
578 PyStructSequence_SET_ITEM(tuple, 1, bootid);
580 PyTuple_SET_ITEM(tuple, 0, monotonic);
581 PyTuple_SET_ITEM(tuple, 1, bootid);
587 PyDoc_STRVAR(Reader_add_match__doc__,
588 "add_match(match) -> None\n\n"
589 "Add a match to filter journal log entries. All matches of different\n"
590 "fields are combined with logical AND, and matches of the same field\n"
591 "are automatically combined with logical OR.\n"
592 "Match is a string of the form \"FIELD=value\".");
593 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
597 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
600 r = sd_journal_add_match(self->j, match, match_len);
601 set_error(r, NULL, "Invalid match");
609 PyDoc_STRVAR(Reader_add_disjunction__doc__,
610 "add_disjunction() -> None\n\n"
611 "Inserts a logical OR between matches added since previous\n"
612 "add_disjunction() or add_conjunction() and the next\n"
613 "add_disjunction() or add_conjunction().\n\n"
614 "See man:sd_journal_add_disjunction(3) for explanation.");
615 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
618 r = sd_journal_add_disjunction(self->j);
619 set_error(r, NULL, NULL);
626 PyDoc_STRVAR(Reader_add_conjunction__doc__,
627 "add_conjunction() -> None\n\n"
628 "Inserts a logical AND between matches added since previous\n"
629 "add_disjunction() or add_conjunction() and the next\n"
630 "add_disjunction() or add_conjunction().\n\n"
631 "See man:sd_journal_add_disjunction(3) for explanation.");
632 static PyObject* Reader_add_conjunction(Reader *self, PyObject *args)
635 r = sd_journal_add_conjunction(self->j);
636 set_error(r, NULL, NULL);
643 PyDoc_STRVAR(Reader_flush_matches__doc__,
644 "flush_matches() -> None\n\n"
645 "Clear all current match filters.");
646 static PyObject* Reader_flush_matches(Reader *self, PyObject *args)
648 sd_journal_flush_matches(self->j);
653 PyDoc_STRVAR(Reader_seek_head__doc__,
654 "seek_head() -> None\n\n"
655 "Jump to the beginning of the journal.\n"
656 "This method invokes sd_journal_seek_head().\n"
657 "See man:sd_journal_seek_head(3).");
658 static PyObject* Reader_seek_head(Reader *self, PyObject *args)
661 Py_BEGIN_ALLOW_THREADS
662 r = sd_journal_seek_head(self->j);
664 if (set_error(r, NULL, NULL))
670 PyDoc_STRVAR(Reader_seek_tail__doc__,
671 "seek_tail() -> None\n\n"
672 "Jump to the end of the journal.\n"
673 "This method invokes sd_journal_seek_tail().\n"
674 "See man:sd_journal_seek_tail(3).");
675 static PyObject* Reader_seek_tail(Reader *self, PyObject *args)
678 Py_BEGIN_ALLOW_THREADS
679 r = sd_journal_seek_tail(self->j);
681 if (set_error(r, NULL, NULL))
687 PyDoc_STRVAR(Reader_seek_realtime__doc__,
688 "seek_realtime(realtime) -> None\n\n"
689 "Seek to nearest matching journal entry to `realtime`. Argument\n"
690 "`realtime` in specified in seconds.");
691 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args)
696 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
699 Py_BEGIN_ALLOW_THREADS
700 r = sd_journal_seek_realtime_usec(self->j, timestamp);
702 if (set_error(r, NULL, NULL))
708 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
709 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
710 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
711 "`monotonic` is an timestamp from boot in microseconds.\n"
712 "Argument `bootid` is a string representing which boot the\n"
713 "monotonic time is reference to. Defaults to current bootid.");
714 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args)
721 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
725 r = sd_id128_from_string(bootid, &id);
726 if (set_error(r, NULL, "Invalid bootid"))
729 Py_BEGIN_ALLOW_THREADS
730 r = sd_id128_get_boot(&id);
732 if (set_error(r, NULL, NULL))
736 Py_BEGIN_ALLOW_THREADS
737 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
739 if (set_error(r, NULL, NULL))
746 PyDoc_STRVAR(Reader_process__doc__,
747 "process() -> state change (integer)\n\n"
748 "Process events and reset the readable state of the file\n"
749 "descriptor returned by .fileno().\n\n"
750 "Will return constants: NOP if no change; APPEND if new\n"
751 "entries have been added to the end of the journal; and\n"
752 "INVALIDATE if journal files have been added or removed.\n\n"
753 "See man:sd_journal_process(3) for further discussion.");
754 static PyObject* Reader_process(Reader *self, PyObject *args)
760 Py_BEGIN_ALLOW_THREADS
761 r = sd_journal_process(self->j);
763 if (set_error(r, NULL, NULL) < 0)
766 return long_FromLong(r);
770 PyDoc_STRVAR(Reader_wait__doc__,
771 "wait([timeout]) -> state change (integer)\n\n"
772 "Wait for a change in the journal. Argument `timeout` specifies\n"
773 "the maximum number of microseconds to wait before returning\n"
774 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
775 "then block forever.\n\n"
776 "Will return constants: NOP if no change; APPEND if new\n"
777 "entries have been added to the end of the journal; and\n"
778 "INVALIDATE if journal files have been added or removed.\n\n"
779 "See man:sd_journal_wait(3) for further discussion.");
780 static PyObject* Reader_wait(Reader *self, PyObject *args)
785 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
788 Py_BEGIN_ALLOW_THREADS
789 r = sd_journal_wait(self->j, timeout);
791 if (set_error(r, NULL, NULL) < 0)
794 return long_FromLong(r);
798 PyDoc_STRVAR(Reader_seek_cursor__doc__,
799 "seek_cursor(cursor) -> None\n\n"
800 "Seek to journal entry by given unique reference `cursor`.");
801 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
806 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
809 Py_BEGIN_ALLOW_THREADS
810 r = sd_journal_seek_cursor(self->j, cursor);
812 if (set_error(r, NULL, "Invalid cursor"))
818 PyDoc_STRVAR(Reader_get_cursor__doc__,
819 "get_cursor() -> str\n\n"
820 "Return a cursor string for the current journal entry.\n\n"
821 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
822 static PyObject* Reader_get_cursor(Reader *self, PyObject *args)
824 _cleanup_free_ char *cursor = NULL;
830 r = sd_journal_get_cursor(self->j, &cursor);
831 if (set_error(r, NULL, NULL))
834 return unicode_FromString(cursor);
838 PyDoc_STRVAR(Reader_test_cursor__doc__,
839 "test_cursor(str) -> bool\n\n"
840 "Test whether the cursor string matches current journal entry.\n\n"
841 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
842 static PyObject* Reader_test_cursor(Reader *self, PyObject *args)
850 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
853 r = sd_journal_test_cursor(self->j, cursor);
854 set_error(r, NULL, NULL);
858 return PyBool_FromLong(r);
861 PyDoc_STRVAR(Reader_query_unique__doc__,
862 "query_unique(field) -> a set of values\n\n"
863 "Return a set of unique values appearing in journal for the\n"
864 "given `field`. Note this does not respect any journal matches.");
865 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
871 PyObject *value_set, *key, *value;
873 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
876 Py_BEGIN_ALLOW_THREADS
877 r = sd_journal_query_unique(self->j, query);
879 if (set_error(r, NULL, "Invalid field name"))
882 value_set = PySet_New(0);
883 key = unicode_FromString(query);
885 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
886 const char *delim_ptr;
888 delim_ptr = memchr(uniq, '=', uniq_len);
889 value = PyBytes_FromStringAndSize(
891 (const char*) uniq + uniq_len - (delim_ptr + 1));
892 PySet_Add(value_set, value);
900 PyDoc_STRVAR(Reader_get_catalog__doc__,
901 "get_catalog() -> str\n\n"
902 "Retrieve a message catalog entry for the current journal entry.\n"
903 "Will throw IndexError if the entry has no MESSAGE_ID\n"
904 "and KeyError is the id is specified, but hasn't been found\n"
905 "in the catalog.\n\n"
906 "Wraps man:sd_journal_get_catalog(3).");
907 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
910 _cleanup_free_ char *msg = NULL;
915 Py_BEGIN_ALLOW_THREADS
916 r = sd_journal_get_catalog(self->j, &msg);
922 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
924 const size_t l = sizeof("MESSAGE_ID");
926 PyErr_Format(PyExc_KeyError, "%.*s", (int) (mid_len - l),
927 (const char*) mid + l);
928 } else if (r == -ENOENT)
929 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
931 set_error(r, NULL, NULL);
933 } else if (set_error(r, NULL, NULL))
936 return unicode_FromString(msg);
940 PyDoc_STRVAR(get_catalog__doc__,
941 "get_catalog(id128) -> str\n\n"
942 "Retrieve a message catalog entry for the given id.\n"
943 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
944 static PyObject* get_catalog(PyObject *self, PyObject *args)
949 _cleanup_free_ char *msg = NULL;
954 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
957 r = sd_id128_from_string(id_, &id);
958 if (set_error(r, NULL, "Invalid id128"))
961 Py_BEGIN_ALLOW_THREADS
962 r = sd_journal_get_catalog_for_message_id(id, &msg);
964 if (set_error(r, NULL, NULL))
967 return unicode_FromString(msg);
971 PyDoc_STRVAR(data_threshold__doc__,
972 "Threshold for field size truncation in bytes.\n\n"
973 "Fields longer than this will be truncated to the threshold size.\n"
974 "Defaults to 64Kb.");
976 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
981 r = sd_journal_get_data_threshold(self->j, &cvalue);
982 if (set_error(r, NULL, NULL))
985 return long_FromSize_t(cvalue);
988 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
992 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
995 if (!long_Check(value)){
996 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
999 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
1000 return set_error(r, NULL, NULL);
1004 PyDoc_STRVAR(closed__doc__,
1005 "True iff journal is closed");
1006 static PyObject* Reader_get_closed(Reader *self, void *closure)
1008 return PyBool_FromLong(self->j == NULL);
1012 static PyGetSetDef Reader_getsetters[] = {
1013 {(char*) "data_threshold",
1014 (getter) Reader_get_data_threshold,
1015 (setter) Reader_set_data_threshold,
1016 (char*) data_threshold__doc__,
1019 (getter) Reader_get_closed,
1021 (char*) closed__doc__,
1026 static PyMethodDef Reader_methods[] = {
1027 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
1028 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
1029 {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__},
1030 {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__},
1031 {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__},
1032 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
1033 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
1034 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
1035 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
1036 {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
1037 {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__},
1038 {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
1039 {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__},
1040 {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
1041 {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
1042 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
1043 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
1044 {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__},
1045 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
1046 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
1047 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
1048 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
1049 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
1050 {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__},
1051 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
1052 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
1053 {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
1054 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
1055 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
1056 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
1060 static PyTypeObject ReaderType = {
1061 PyVarObject_HEAD_INIT(NULL, 0)
1062 .tp_name = "_reader._Reader",
1063 .tp_basicsize = sizeof(Reader),
1064 .tp_dealloc = (destructor) Reader_dealloc,
1065 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1066 .tp_doc = Reader__doc__,
1067 .tp_methods = Reader_methods,
1068 .tp_getset = Reader_getsetters,
1069 .tp_init = (initproc) Reader_init,
1070 .tp_new = PyType_GenericNew,
1073 static PyMethodDef methods[] = {
1074 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
1078 #if PY_MAJOR_VERSION >= 3
1079 static PyModuleDef module = {
1080 PyModuleDef_HEAD_INIT,
1088 #if PY_MAJOR_VERSION >= 3
1089 static bool initialized = false;
1092 #pragma GCC diagnostic push
1093 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
1096 #if PY_MAJOR_VERSION >= 3
1097 PyInit__reader(void)
1106 if (PyType_Ready(&ReaderType) < 0)
1107 #if PY_MAJOR_VERSION >= 3
1113 #if PY_MAJOR_VERSION >= 3
1114 m = PyModule_Create(&module);
1119 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1123 m = Py_InitModule3("_reader", methods, module__doc__);
1128 Py_INCREF(&ReaderType);
1129 #if PY_MAJOR_VERSION >= 3
1130 Py_INCREF(&MonotonicType);
1132 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1133 #if PY_MAJOR_VERSION >= 3
1134 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1136 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1137 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1138 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1139 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1140 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1141 PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) ||
1142 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) ||
1143 PyModule_AddIntConstant(m, "CURRENT_USER", SD_JOURNAL_CURRENT_USER) ||
1144 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
1145 #if PY_MAJOR_VERSION >= 3
1151 #if PY_MAJOR_VERSION >= 3
1156 #pragma GCC diagnostic pop