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 for (i = 0; i < len; i++) {
93 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
99 item = PySequence_ITEM(obj, i);
100 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
101 r = PyUnicode_FSConverter(item, &bytes);
105 s = PyBytes_AsString(bytes);
107 s = PyString_AsString(item);
128 static void Reader_dealloc(Reader* self)
130 sd_journal_close(self->j);
131 Py_TYPE(self)->tp_free((PyObject*)self);
134 PyDoc_STRVAR(Reader__doc__,
135 "_Reader([flags | path | files]) -> ...\n\n"
136 "_Reader allows filtering and retrieval of Journal entries.\n"
137 "Note: this is a low-level interface, and probably not what you\n"
138 "want, use systemd.journal.Reader instead.\n\n"
139 "Argument `flags` sets open flags of the journal, which can be one\n"
140 "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n"
141 "journal on local machine only; RUNTIME_ONLY opens only\n"
142 "volatile journal files; and SYSTEM opens journal files of\n"
143 "system services and the kernel, and CURRENT_USER opens files\n"
144 "of the current user.\n\n"
145 "Argument `path` is the directory of journal files.\n"
146 "Argument `files` is a list of files. Note that\n"
147 "`flags`, `path`, and `files` are exclusive.\n\n"
148 "_Reader implements the context manager protocol: the journal\n"
149 "will be closed when exiting the block.");
150 static int Reader_init(Reader *self, PyObject *args, PyObject *keywds)
156 static const char* const kwlist[] = {"flags", "path", "files", NULL};
157 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izO&", (char**) kwlist,
158 &flags, &path, strv_converter, &files))
161 if (!!flags + !!path + !!files > 1) {
162 PyErr_SetString(PyExc_ValueError, "cannot use more than one of flags, path, and files");
167 flags = SD_JOURNAL_LOCAL_ONLY;
169 Py_BEGIN_ALLOW_THREADS
171 r = sd_journal_open_directory(&self->j, path, 0);
173 r = sd_journal_open_files(&self->j, (const char**) files, 0);
175 r = sd_journal_open(&self->j, flags);
178 return set_error(r, path, "Invalid flags or path");
182 PyDoc_STRVAR(Reader_fileno__doc__,
183 "fileno() -> int\n\n"
184 "Get a file descriptor to poll for changes in the journal.\n"
185 "This method invokes sd_journal_get_fd().\n"
186 "See man:sd_journal_get_fd(3).");
187 static PyObject* Reader_fileno(Reader *self, PyObject *args)
189 int fd = sd_journal_get_fd(self->j);
190 set_error(fd, NULL, NULL);
193 return long_FromLong(fd);
197 PyDoc_STRVAR(Reader_reliable_fd__doc__,
198 "reliable_fd() -> bool\n\n"
199 "Returns True iff the journal can be polled reliably.\n"
200 "This method invokes sd_journal_reliable_fd().\n"
201 "See man:sd_journal_reliable_fd(3).");
202 static PyObject* Reader_reliable_fd(Reader *self, PyObject *args)
204 int r = sd_journal_reliable_fd(self->j);
205 set_error(r, NULL, NULL);
208 return PyBool_FromLong(r);
212 PyDoc_STRVAR(Reader_get_events__doc__,
213 "get_events() -> int\n\n"
214 "Returns a mask of poll() events to wait for on the file\n"
215 "descriptor returned by .fileno().\n\n"
216 "See man:sd_journal_get_events(3) for further discussion.");
217 static PyObject* Reader_get_events(Reader *self, PyObject *args)
219 int r = sd_journal_get_events(self->j);
220 set_error(r, NULL, NULL);
223 return long_FromLong(r);
227 PyDoc_STRVAR(Reader_get_timeout__doc__,
228 "get_timeout() -> int or None\n\n"
229 "Returns a timeout value for usage in poll(), the time since the\n"
230 "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
232 "The return value must be converted to a relative timeout in\n"
233 "milliseconds if it is to be used as an argument for poll().\n"
234 "See man:sd_journal_get_timeout(3) for further discussion.");
235 static PyObject* Reader_get_timeout(Reader *self, PyObject *args)
240 r = sd_journal_get_timeout(self->j, &t);
241 set_error(r, NULL, NULL);
245 if (t == (uint64_t) -1)
248 assert_cc(sizeof(unsigned long long) == sizeof(t));
249 return PyLong_FromUnsignedLongLong(t);
253 PyDoc_STRVAR(Reader_get_timeout_ms__doc__,
254 "get_timeout_ms() -> int\n\n"
255 "Returns a timeout value suitable for usage in poll(), the value\n"
256 "returned by .get_timeout() converted to relative ms, or -1 if\n"
257 "no timeout is necessary.");
258 static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args)
263 r = sd_journal_get_timeout(self->j, &t);
264 set_error(r, NULL, NULL);
268 return absolute_timeout(t);
272 PyDoc_STRVAR(Reader_close__doc__,
273 "close() -> None\n\n"
274 "Free resources allocated by this Reader object.\n"
275 "This method invokes sd_journal_close().\n"
276 "See man:sd_journal_close(3).");
277 static PyObject* Reader_close(Reader *self, PyObject *args)
282 sd_journal_close(self->j);
288 PyDoc_STRVAR(Reader_get_usage__doc__,
289 "get_usage() -> int\n\n"
290 "Returns the total disk space currently used by journal\n"
291 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
292 "passed when opening the journal this value will only reflect\n"
293 "the size of journal files of the local host, otherwise\n"
295 "This method invokes sd_journal_get_usage().\n"
296 "See man:sd_journal_get_usage(3).");
297 static PyObject* Reader_get_usage(Reader *self, PyObject *args)
302 r = sd_journal_get_usage(self->j, &bytes);
303 if (set_error(r, NULL, NULL))
306 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
307 return PyLong_FromUnsignedLongLong(bytes);
311 PyDoc_STRVAR(Reader___enter____doc__,
312 "__enter__() -> self\n\n"
313 "Part of the context manager protocol.\n"
315 static PyObject* Reader___enter__(PyObject *self, PyObject *args)
324 PyDoc_STRVAR(Reader___exit____doc__,
325 "__exit__(type, value, traceback) -> None\n\n"
326 "Part of the context manager protocol.\n"
327 "Closes the journal.\n");
328 static PyObject* Reader___exit__(Reader *self, PyObject *args)
330 return Reader_close(self, args);
334 PyDoc_STRVAR(Reader_next__doc__,
335 "next([skip]) -> bool\n\n"
336 "Go to the next log entry. Optional skip value means to go to\n"
337 "the `skip`\\-th log entry.\n"
338 "Returns False if at end of file, True otherwise.");
339 static PyObject* Reader_next(Reader *self, PyObject *args)
344 if (!PyArg_ParseTuple(args, "|L:next", &skip))
348 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
352 Py_BEGIN_ALLOW_THREADS
354 r = sd_journal_next(self->j);
355 else if (skip == -1LL)
356 r = sd_journal_previous(self->j);
358 r = sd_journal_next_skip(self->j, skip);
359 else if (skip < -1LL)
360 r = sd_journal_previous_skip(self->j, -skip);
362 assert_not_reached("should not be here");
365 set_error(r, NULL, NULL);
368 return PyBool_FromLong(r);
371 PyDoc_STRVAR(Reader_previous__doc__,
372 "previous([skip]) -> bool\n\n"
373 "Go to the previous log entry. Optional skip value means to \n"
374 "go to the `skip`\\-th previous log entry.\n"
375 "Returns False if at start of file, True otherwise.");
376 static PyObject* Reader_previous(Reader *self, PyObject *args)
379 if (!PyArg_ParseTuple(args, "|L:previous", &skip))
382 return PyObject_CallMethod((PyObject *)self, (char*) "_next",
387 static int extract(const char* msg, size_t msg_len,
388 PyObject **key, PyObject **value) {
389 PyObject *k = NULL, *v;
390 const char *delim_ptr;
392 delim_ptr = memchr(msg, '=', msg_len);
394 PyErr_SetString(PyExc_OSError,
395 "journal gave us a field without '='");
400 k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
406 v = PyBytes_FromStringAndSize(delim_ptr + 1,
407 (const char*) msg + msg_len - (delim_ptr + 1));
422 PyDoc_STRVAR(Reader_get__doc__,
423 "get(str) -> str\n\n"
424 "Return data associated with this key in current log entry.\n"
425 "Throws KeyError is the data is not available.");
426 static PyObject* Reader_get(Reader *self, PyObject *args)
437 if (!PyArg_ParseTuple(args, "s:get", &field))
440 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
442 PyErr_SetString(PyExc_KeyError, field);
444 } else if (set_error(r, NULL, "field name is not valid"))
447 r = extract(msg, msg_len, NULL, &value);
454 PyDoc_STRVAR(Reader_get_all__doc__,
455 "_get_all() -> dict\n\n"
456 "Return dictionary of the current log entry.");
457 static PyObject* Reader_get_all(Reader *self, PyObject *args)
468 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
469 _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL;
471 r = extract(msg, msg_len, &key, &value);
475 if (PyDict_Contains(dict, key)) {
476 PyObject *cur_value = PyDict_GetItem(dict, key);
478 if (PyList_CheckExact(cur_value)) {
479 r = PyList_Append(cur_value, value);
483 _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0);
487 r = PyList_Append(tmp_list, cur_value);
491 r = PyList_Append(tmp_list, value);
495 r = PyDict_SetItem(dict, key, tmp_list);
500 r = PyDict_SetItem(dict, key, value);
514 PyDoc_STRVAR(Reader_get_realtime__doc__,
515 "get_realtime() -> int\n\n"
516 "Return the realtime timestamp for the current journal entry\n"
517 "in microseconds.\n\n"
518 "Wraps sd_journal_get_realtime_usec().\n"
519 "See man:sd_journal_get_realtime_usec(3).");
520 static PyObject* Reader_get_realtime(Reader *self, PyObject *args)
528 r = sd_journal_get_realtime_usec(self->j, ×tamp);
529 if (set_error(r, NULL, NULL))
532 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
533 return PyLong_FromUnsignedLongLong(timestamp);
537 PyDoc_STRVAR(Reader_get_monotonic__doc__,
538 "get_monotonic() -> (timestamp, bootid)\n\n"
539 "Return the monotonic timestamp for the current journal entry\n"
540 "as a tuple of time in microseconds and bootid.\n\n"
541 "Wraps sd_journal_get_monotonic_usec().\n"
542 "See man:sd_journal_get_monotonic_usec(3).");
543 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args)
547 PyObject *monotonic, *bootid, *tuple;
553 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
554 if (set_error(r, NULL, NULL))
557 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
558 monotonic = PyLong_FromUnsignedLongLong(timestamp);
559 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
560 #if PY_MAJOR_VERSION >= 3
561 tuple = PyStructSequence_New(&MonotonicType);
563 tuple = PyTuple_New(2);
565 if (!monotonic || !bootid || !tuple) {
566 Py_XDECREF(monotonic);
572 #if PY_MAJOR_VERSION >= 3
573 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
574 PyStructSequence_SET_ITEM(tuple, 1, bootid);
576 PyTuple_SET_ITEM(tuple, 0, monotonic);
577 PyTuple_SET_ITEM(tuple, 1, bootid);
583 PyDoc_STRVAR(Reader_add_match__doc__,
584 "add_match(match) -> None\n\n"
585 "Add a match to filter journal log entries. All matches of different\n"
586 "fields are combined with logical AND, and matches of the same field\n"
587 "are automatically combined with logical OR.\n"
588 "Match is a string of the form \"FIELD=value\".");
589 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
593 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
596 r = sd_journal_add_match(self->j, match, match_len);
597 set_error(r, NULL, "Invalid match");
605 PyDoc_STRVAR(Reader_add_disjunction__doc__,
606 "add_disjunction() -> None\n\n"
607 "Inserts a logical OR between matches added since previous\n"
608 "add_disjunction() or add_conjunction() and the next\n"
609 "add_disjunction() or add_conjunction().\n\n"
610 "See man:sd_journal_add_disjunction(3) for explanation.");
611 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
614 r = sd_journal_add_disjunction(self->j);
615 set_error(r, NULL, NULL);
622 PyDoc_STRVAR(Reader_add_conjunction__doc__,
623 "add_conjunction() -> None\n\n"
624 "Inserts a logical AND between matches added since previous\n"
625 "add_disjunction() or add_conjunction() and the next\n"
626 "add_disjunction() or add_conjunction().\n\n"
627 "See man:sd_journal_add_disjunction(3) for explanation.");
628 static PyObject* Reader_add_conjunction(Reader *self, PyObject *args)
631 r = sd_journal_add_conjunction(self->j);
632 set_error(r, NULL, NULL);
639 PyDoc_STRVAR(Reader_flush_matches__doc__,
640 "flush_matches() -> None\n\n"
641 "Clear all current match filters.");
642 static PyObject* Reader_flush_matches(Reader *self, PyObject *args)
644 sd_journal_flush_matches(self->j);
649 PyDoc_STRVAR(Reader_seek_head__doc__,
650 "seek_head() -> None\n\n"
651 "Jump to the beginning of the journal.\n"
652 "This method invokes sd_journal_seek_head().\n"
653 "See man:sd_journal_seek_head(3).");
654 static PyObject* Reader_seek_head(Reader *self, PyObject *args)
657 Py_BEGIN_ALLOW_THREADS
658 r = sd_journal_seek_head(self->j);
660 if (set_error(r, NULL, NULL))
666 PyDoc_STRVAR(Reader_seek_tail__doc__,
667 "seek_tail() -> None\n\n"
668 "Jump to the end of the journal.\n"
669 "This method invokes sd_journal_seek_tail().\n"
670 "See man:sd_journal_seek_tail(3).");
671 static PyObject* Reader_seek_tail(Reader *self, PyObject *args)
674 Py_BEGIN_ALLOW_THREADS
675 r = sd_journal_seek_tail(self->j);
677 if (set_error(r, NULL, NULL))
683 PyDoc_STRVAR(Reader_seek_realtime__doc__,
684 "seek_realtime(realtime) -> None\n\n"
685 "Seek to nearest matching journal entry to `realtime`. Argument\n"
686 "`realtime` in specified in seconds.");
687 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args)
692 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
695 Py_BEGIN_ALLOW_THREADS
696 r = sd_journal_seek_realtime_usec(self->j, timestamp);
698 if (set_error(r, NULL, NULL))
704 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
705 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
706 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
707 "`monotonic` is an timestamp from boot in microseconds.\n"
708 "Argument `bootid` is a string representing which boot the\n"
709 "monotonic time is reference to. Defaults to current bootid.");
710 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args)
717 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
721 r = sd_id128_from_string(bootid, &id);
722 if (set_error(r, NULL, "Invalid bootid"))
725 Py_BEGIN_ALLOW_THREADS
726 r = sd_id128_get_boot(&id);
728 if (set_error(r, NULL, NULL))
732 Py_BEGIN_ALLOW_THREADS
733 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
735 if (set_error(r, NULL, NULL))
742 PyDoc_STRVAR(Reader_process__doc__,
743 "process() -> state change (integer)\n\n"
744 "Process events and reset the readable state of the file\n"
745 "descriptor returned by .fileno().\n\n"
746 "Will return constants: NOP if no change; APPEND if new\n"
747 "entries have been added to the end of the journal; and\n"
748 "INVALIDATE if journal files have been added or removed.\n\n"
749 "See man:sd_journal_process(3) for further discussion.");
750 static PyObject* Reader_process(Reader *self, PyObject *args)
756 Py_BEGIN_ALLOW_THREADS
757 r = sd_journal_process(self->j);
759 if (set_error(r, NULL, NULL) < 0)
762 return long_FromLong(r);
766 PyDoc_STRVAR(Reader_wait__doc__,
767 "wait([timeout]) -> state change (integer)\n\n"
768 "Wait for a change in the journal. Argument `timeout` specifies\n"
769 "the maximum number of microseconds to wait before returning\n"
770 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
771 "then block forever.\n\n"
772 "Will return constants: NOP if no change; APPEND if new\n"
773 "entries have been added to the end of the journal; and\n"
774 "INVALIDATE if journal files have been added or removed.\n\n"
775 "See man:sd_journal_wait(3) for further discussion.");
776 static PyObject* Reader_wait(Reader *self, PyObject *args)
781 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
784 Py_BEGIN_ALLOW_THREADS
785 r = sd_journal_wait(self->j, timeout);
787 if (set_error(r, NULL, NULL) < 0)
790 return long_FromLong(r);
794 PyDoc_STRVAR(Reader_seek_cursor__doc__,
795 "seek_cursor(cursor) -> None\n\n"
796 "Seek to journal entry by given unique reference `cursor`.");
797 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
802 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
805 Py_BEGIN_ALLOW_THREADS
806 r = sd_journal_seek_cursor(self->j, cursor);
808 if (set_error(r, NULL, "Invalid cursor"))
814 PyDoc_STRVAR(Reader_get_cursor__doc__,
815 "get_cursor() -> str\n\n"
816 "Return a cursor string for the current journal entry.\n\n"
817 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
818 static PyObject* Reader_get_cursor(Reader *self, PyObject *args)
820 _cleanup_free_ char *cursor = NULL;
826 r = sd_journal_get_cursor(self->j, &cursor);
827 if (set_error(r, NULL, NULL))
830 return unicode_FromString(cursor);
834 PyDoc_STRVAR(Reader_test_cursor__doc__,
835 "test_cursor(str) -> bool\n\n"
836 "Test whether the cursor string matches current journal entry.\n\n"
837 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
838 static PyObject* Reader_test_cursor(Reader *self, PyObject *args)
846 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
849 r = sd_journal_test_cursor(self->j, cursor);
850 set_error(r, NULL, NULL);
854 return PyBool_FromLong(r);
857 PyDoc_STRVAR(Reader_query_unique__doc__,
858 "query_unique(field) -> a set of values\n\n"
859 "Return a set of unique values appearing in journal for the\n"
860 "given `field`. Note this does not respect any journal matches.");
861 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
867 PyObject *value_set, *key, *value;
869 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
872 Py_BEGIN_ALLOW_THREADS
873 r = sd_journal_query_unique(self->j, query);
875 if (set_error(r, NULL, "Invalid field name"))
878 value_set = PySet_New(0);
879 key = unicode_FromString(query);
881 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
882 const char *delim_ptr;
884 delim_ptr = memchr(uniq, '=', uniq_len);
885 value = PyBytes_FromStringAndSize(
887 (const char*) uniq + uniq_len - (delim_ptr + 1));
888 PySet_Add(value_set, value);
896 PyDoc_STRVAR(Reader_get_catalog__doc__,
897 "get_catalog() -> str\n\n"
898 "Retrieve a message catalog entry for the current journal entry.\n"
899 "Will throw IndexError if the entry has no MESSAGE_ID\n"
900 "and KeyError is the id is specified, but hasn't been found\n"
901 "in the catalog.\n\n"
902 "Wraps man:sd_journal_get_catalog(3).");
903 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
906 _cleanup_free_ char *msg = NULL;
911 Py_BEGIN_ALLOW_THREADS
912 r = sd_journal_get_catalog(self->j, &msg);
918 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
920 const size_t l = sizeof("MESSAGE_ID");
922 PyErr_Format(PyExc_KeyError, "%.*s", (int) (mid_len - l),
923 (const char*) mid + l);
924 } else if (r == -ENOENT)
925 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
927 set_error(r, NULL, NULL);
929 } else if (set_error(r, NULL, NULL))
932 return unicode_FromString(msg);
936 PyDoc_STRVAR(get_catalog__doc__,
937 "get_catalog(id128) -> str\n\n"
938 "Retrieve a message catalog entry for the given id.\n"
939 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
940 static PyObject* get_catalog(PyObject *self, PyObject *args)
945 _cleanup_free_ char *msg = NULL;
950 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
953 r = sd_id128_from_string(id_, &id);
954 if (set_error(r, NULL, "Invalid id128"))
957 Py_BEGIN_ALLOW_THREADS
958 r = sd_journal_get_catalog_for_message_id(id, &msg);
960 if (set_error(r, NULL, NULL))
963 return unicode_FromString(msg);
967 PyDoc_STRVAR(data_threshold__doc__,
968 "Threshold for field size truncation in bytes.\n\n"
969 "Fields longer than this will be truncated to the threshold size.\n"
970 "Defaults to 64Kb.");
972 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
977 r = sd_journal_get_data_threshold(self->j, &cvalue);
978 if (set_error(r, NULL, NULL))
981 return long_FromSize_t(cvalue);
984 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
988 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
991 if (!long_Check(value)){
992 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
995 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
996 return set_error(r, NULL, NULL);
1000 PyDoc_STRVAR(closed__doc__,
1001 "True iff journal is closed");
1002 static PyObject* Reader_get_closed(Reader *self, void *closure)
1004 return PyBool_FromLong(self->j == NULL);
1008 static PyGetSetDef Reader_getsetters[] = {
1009 {(char*) "data_threshold",
1010 (getter) Reader_get_data_threshold,
1011 (setter) Reader_set_data_threshold,
1012 (char*) data_threshold__doc__,
1015 (getter) Reader_get_closed,
1017 (char*) closed__doc__,
1022 static PyMethodDef Reader_methods[] = {
1023 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
1024 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
1025 {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__},
1026 {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__},
1027 {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__},
1028 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
1029 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
1030 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
1031 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
1032 {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
1033 {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__},
1034 {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
1035 {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__},
1036 {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
1037 {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
1038 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
1039 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
1040 {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__},
1041 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
1042 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
1043 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
1044 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
1045 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
1046 {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__},
1047 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
1048 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
1049 {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
1050 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
1051 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
1052 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
1056 static PyTypeObject ReaderType = {
1057 PyVarObject_HEAD_INIT(NULL, 0)
1058 .tp_name = "_reader._Reader",
1059 .tp_basicsize = sizeof(Reader),
1060 .tp_dealloc = (destructor) Reader_dealloc,
1061 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1062 .tp_doc = Reader__doc__,
1063 .tp_methods = Reader_methods,
1064 .tp_getset = Reader_getsetters,
1065 .tp_init = (initproc) Reader_init,
1066 .tp_new = PyType_GenericNew,
1069 static PyMethodDef methods[] = {
1070 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
1074 #if PY_MAJOR_VERSION >= 3
1075 static PyModuleDef module = {
1076 PyModuleDef_HEAD_INIT,
1084 #if PY_MAJOR_VERSION >= 3
1085 static bool initialized = false;
1088 #pragma GCC diagnostic push
1089 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
1092 #if PY_MAJOR_VERSION >= 3
1093 PyInit__reader(void)
1102 if (PyType_Ready(&ReaderType) < 0)
1103 #if PY_MAJOR_VERSION >= 3
1109 #if PY_MAJOR_VERSION >= 3
1110 m = PyModule_Create(&module);
1115 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1119 m = Py_InitModule3("_reader", methods, module__doc__);
1124 Py_INCREF(&ReaderType);
1125 #if PY_MAJOR_VERSION >= 3
1126 Py_INCREF(&MonotonicType);
1128 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1129 #if PY_MAJOR_VERSION >= 3
1130 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1132 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1133 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1134 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1135 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1136 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1137 PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) ||
1138 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) ||
1139 PyModule_AddIntConstant(m, "CURRENT_USER", SD_JOURNAL_CURRENT_USER) ||
1140 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
1141 #if PY_MAJOR_VERSION >= 3
1147 #if PY_MAJOR_VERSION >= 3
1152 #pragma GCC diagnostic pop