1 /*-*- Mode: C; c-basic-offset: 8; 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;
42 PyDoc_STRVAR(module__doc__,
43 "Class to reads the systemd journal similar to journalctl.");
46 #if PY_MAJOR_VERSION >= 3
47 static PyTypeObject MonotonicType;
49 PyDoc_STRVAR(MonotonicType__doc__,
50 "A tuple of (timestamp, bootid) for holding monotonic timestamps");
52 static PyStructSequence_Field MonotonicType_fields[] = {
53 {(char*) "timestamp", (char*) "Time"},
54 {(char*) "bootid", (char*) "Unique identifier of the boot"},
58 static PyStructSequence_Desc Monotonic_desc = {
59 (char*) "journal.Monotonic",
67 * Convert a Python sequence object into a strv (char**), and
68 * None into a NULL pointer.
70 static int strv_converter(PyObject* obj, void *_result) {
71 char ***result = _result;
84 if (!PySequence_Check(obj))
87 len = PySequence_Length(obj);
88 *result = new0(char*, len + 1);
90 set_error(-ENOMEM, NULL, NULL);
94 for (i = 0; i < len; i++) {
96 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
102 item = PySequence_ITEM(obj, i);
103 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
104 r = PyUnicode_FSConverter(item, &bytes);
108 s = PyBytes_AsString(bytes);
110 s = PyString_AsString(item);
131 static void Reader_dealloc(Reader* self) {
132 sd_journal_close(self->j);
133 Py_TYPE(self)->tp_free((PyObject*)self);
136 PyDoc_STRVAR(Reader__doc__,
137 "_Reader([flags | path | files]) -> ...\n\n"
138 "_Reader allows filtering and retrieval of Journal entries.\n"
139 "Note: this is a low-level interface, and probably not what you\n"
140 "want, use systemd.journal.Reader instead.\n\n"
141 "Argument `flags` sets open flags of the journal, which can be one\n"
142 "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n"
143 "journal on local machine only; RUNTIME_ONLY opens only\n"
144 "volatile journal files; and SYSTEM opens journal files of\n"
145 "system services and the kernel, and CURRENT_USER opens files\n"
146 "of the current user.\n\n"
147 "Argument `path` is the directory of journal files.\n"
148 "Argument `files` is a list of files. Note that\n"
149 "`flags`, `path`, and `files` are exclusive.\n\n"
150 "_Reader implements the context manager protocol: the journal\n"
151 "will be closed when exiting the block.");
152 static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) {
157 static const char* const kwlist[] = {"flags", "path", "files", NULL};
158 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izO&:__init__", (char**) kwlist,
159 &flags, &path, strv_converter, &files))
162 if (!!flags + !!path + !!files > 1) {
163 PyErr_SetString(PyExc_ValueError, "cannot use more than one of flags, path, and files");
168 flags = SD_JOURNAL_LOCAL_ONLY;
170 Py_BEGIN_ALLOW_THREADS
172 r = sd_journal_open_directory(&self->j, path, 0);
174 r = sd_journal_open_files(&self->j, (const char**) files, 0);
176 r = sd_journal_open(&self->j, flags);
179 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) {
190 fd = sd_journal_get_fd(self->j);
191 set_error(fd, NULL, NULL);
194 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) {
205 r = sd_journal_reliable_fd(self->j);
206 if (set_error(r, NULL, NULL) < 0)
208 return PyBool_FromLong(r);
211 PyDoc_STRVAR(Reader_get_events__doc__,
212 "get_events() -> int\n\n"
213 "Returns a mask of poll() events to wait for on the file\n"
214 "descriptor returned by .fileno().\n\n"
215 "See man:sd_journal_get_events(3) for further discussion.");
216 static PyObject* Reader_get_events(Reader *self, PyObject *args) {
219 r = sd_journal_get_events(self->j);
220 if (set_error(r, NULL, NULL) < 0)
222 return long_FromLong(r);
225 PyDoc_STRVAR(Reader_get_timeout__doc__,
226 "get_timeout() -> int or None\n\n"
227 "Returns a timeout value for usage in poll(), the time since the\n"
228 "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
230 "The return value must be converted to a relative timeout in\n"
231 "milliseconds if it is to be used as an argument for poll().\n"
232 "See man:sd_journal_get_timeout(3) for further discussion.");
233 static PyObject* Reader_get_timeout(Reader *self, PyObject *args) {
237 r = sd_journal_get_timeout(self->j, &t);
238 if (set_error(r, NULL, NULL) < 0)
241 if (t == (uint64_t) -1)
244 assert_cc(sizeof(unsigned long long) == sizeof(t));
245 return PyLong_FromUnsignedLongLong(t);
248 PyDoc_STRVAR(Reader_get_timeout_ms__doc__,
249 "get_timeout_ms() -> int\n\n"
250 "Returns a timeout value suitable for usage in poll(), the value\n"
251 "returned by .get_timeout() converted to relative ms, or -1 if\n"
252 "no timeout is necessary.");
253 static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args) {
257 r = sd_journal_get_timeout(self->j, &t);
258 if (set_error(r, NULL, NULL) < 0)
261 return absolute_timeout(t);
264 PyDoc_STRVAR(Reader_close__doc__,
265 "close() -> None\n\n"
266 "Free resources allocated by this Reader object.\n"
267 "This method invokes sd_journal_close().\n"
268 "See man:sd_journal_close(3).");
269 static PyObject* Reader_close(Reader *self, PyObject *args) {
273 sd_journal_close(self->j);
278 PyDoc_STRVAR(Reader_get_usage__doc__,
279 "get_usage() -> int\n\n"
280 "Returns the total disk space currently used by journal\n"
281 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
282 "passed when opening the journal this value will only reflect\n"
283 "the size of journal files of the local host, otherwise\n"
285 "This method invokes sd_journal_get_usage().\n"
286 "See man:sd_journal_get_usage(3).");
287 static PyObject* Reader_get_usage(Reader *self, PyObject *args) {
291 r = sd_journal_get_usage(self->j, &bytes);
292 if (set_error(r, NULL, NULL) < 0)
295 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
296 return PyLong_FromUnsignedLongLong(bytes);
299 PyDoc_STRVAR(Reader___enter____doc__,
300 "__enter__() -> self\n\n"
301 "Part of the context manager protocol.\n"
303 static PyObject* Reader___enter__(PyObject *self, PyObject *args) {
311 PyDoc_STRVAR(Reader___exit____doc__,
312 "__exit__(type, value, traceback) -> None\n\n"
313 "Part of the context manager protocol.\n"
314 "Closes the journal.\n");
315 static PyObject* Reader___exit__(Reader *self, PyObject *args) {
316 return Reader_close(self, args);
319 PyDoc_STRVAR(Reader_next__doc__,
320 "next([skip]) -> bool\n\n"
321 "Go to the next log entry. Optional skip value means to go to\n"
322 "the `skip`\\-th log entry.\n"
323 "Returns False if at end of file, True otherwise.");
324 static PyObject* Reader_next(Reader *self, PyObject *args) {
328 if (!PyArg_ParseTuple(args, "|L:next", &skip))
332 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
336 Py_BEGIN_ALLOW_THREADS
338 r = sd_journal_next(self->j);
339 else if (skip == -1LL)
340 r = sd_journal_previous(self->j);
342 r = sd_journal_next_skip(self->j, skip);
343 else if (skip < -1LL)
344 r = sd_journal_previous_skip(self->j, -skip);
346 assert_not_reached("should not be here");
349 if (set_error(r, NULL, NULL) < 0)
351 return PyBool_FromLong(r);
354 PyDoc_STRVAR(Reader_previous__doc__,
355 "previous([skip]) -> bool\n\n"
356 "Go to the previous log entry. Optional skip value means to \n"
357 "go to the `skip`\\-th previous log entry.\n"
358 "Returns False if at start of file, True otherwise.");
359 static PyObject* Reader_previous(Reader *self, PyObject *args) {
361 if (!PyArg_ParseTuple(args, "|L:previous", &skip))
364 return PyObject_CallMethod((PyObject *)self, (char*) "_next",
368 static int extract(const char* msg, size_t msg_len,
369 PyObject **key, PyObject **value) {
370 PyObject *k = NULL, *v;
371 const char *delim_ptr;
373 delim_ptr = memchr(msg, '=', msg_len);
375 PyErr_SetString(PyExc_OSError,
376 "journal gave us a field without '='");
381 k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
387 v = PyBytes_FromStringAndSize(delim_ptr + 1,
388 (const char*) msg + msg_len - (delim_ptr + 1));
403 PyDoc_STRVAR(Reader_get__doc__,
404 "get(str) -> str\n\n"
405 "Return data associated with this key in current log entry.\n"
406 "Throws KeyError is the data is not available.");
407 static PyObject* Reader_get(Reader *self, PyObject *args) {
417 if (!PyArg_ParseTuple(args, "s:get", &field))
420 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
422 PyErr_SetString(PyExc_KeyError, field);
425 if (set_error(r, NULL, "field name is not valid") < 0)
428 r = extract(msg, msg_len, NULL, &value);
434 PyDoc_STRVAR(Reader_get_all__doc__,
435 "_get_all() -> dict\n\n"
436 "Return dictionary of the current log entry.");
437 static PyObject* Reader_get_all(Reader *self, PyObject *args) {
447 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
448 _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL;
450 r = extract(msg, msg_len, &key, &value);
454 if (PyDict_Contains(dict, key)) {
455 PyObject *cur_value = PyDict_GetItem(dict, key);
457 if (PyList_CheckExact(cur_value)) {
458 r = PyList_Append(cur_value, value);
462 _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0);
466 r = PyList_Append(tmp_list, cur_value);
470 r = PyList_Append(tmp_list, value);
474 r = PyDict_SetItem(dict, key, tmp_list);
479 r = PyDict_SetItem(dict, key, value);
492 PyDoc_STRVAR(Reader_get_realtime__doc__,
493 "get_realtime() -> int\n\n"
494 "Return the realtime timestamp for the current journal entry\n"
495 "in microseconds.\n\n"
496 "Wraps sd_journal_get_realtime_usec().\n"
497 "See man:sd_journal_get_realtime_usec(3).");
498 static PyObject* Reader_get_realtime(Reader *self, PyObject *args) {
505 r = sd_journal_get_realtime_usec(self->j, ×tamp);
506 if (set_error(r, NULL, NULL) < 0)
509 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
510 return PyLong_FromUnsignedLongLong(timestamp);
513 PyDoc_STRVAR(Reader_get_monotonic__doc__,
514 "get_monotonic() -> (timestamp, bootid)\n\n"
515 "Return the monotonic timestamp for the current journal entry\n"
516 "as a tuple of time in microseconds and bootid.\n\n"
517 "Wraps sd_journal_get_monotonic_usec().\n"
518 "See man:sd_journal_get_monotonic_usec(3).");
519 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args) {
522 PyObject *monotonic, *bootid, *tuple;
528 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
529 if (set_error(r, NULL, NULL) < 0)
532 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
533 monotonic = PyLong_FromUnsignedLongLong(timestamp);
534 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
535 #if PY_MAJOR_VERSION >= 3
536 tuple = PyStructSequence_New(&MonotonicType);
538 tuple = PyTuple_New(2);
540 if (!monotonic || !bootid || !tuple) {
541 Py_XDECREF(monotonic);
547 #if PY_MAJOR_VERSION >= 3
548 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
549 PyStructSequence_SET_ITEM(tuple, 1, bootid);
551 PyTuple_SET_ITEM(tuple, 0, monotonic);
552 PyTuple_SET_ITEM(tuple, 1, bootid);
558 PyDoc_STRVAR(Reader_add_match__doc__,
559 "add_match(match) -> None\n\n"
560 "Add a match to filter journal log entries. All matches of different\n"
561 "fields are combined with logical AND, and matches of the same field\n"
562 "are automatically combined with logical OR.\n"
563 "Match is a string of the form \"FIELD=value\".");
564 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds) {
567 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
570 r = sd_journal_add_match(self->j, match, match_len);
571 if (set_error(r, NULL, "Invalid match") < 0)
577 PyDoc_STRVAR(Reader_add_disjunction__doc__,
578 "add_disjunction() -> None\n\n"
579 "Inserts a logical OR between matches added since previous\n"
580 "add_disjunction() or add_conjunction() and the next\n"
581 "add_disjunction() or add_conjunction().\n\n"
582 "See man:sd_journal_add_disjunction(3) for explanation.");
583 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args) {
585 r = sd_journal_add_disjunction(self->j);
586 if (set_error(r, NULL, NULL) < 0)
591 PyDoc_STRVAR(Reader_add_conjunction__doc__,
592 "add_conjunction() -> None\n\n"
593 "Inserts a logical AND between matches added since previous\n"
594 "add_disjunction() or add_conjunction() and the next\n"
595 "add_disjunction() or add_conjunction().\n\n"
596 "See man:sd_journal_add_disjunction(3) for explanation.");
597 static PyObject* Reader_add_conjunction(Reader *self, PyObject *args) {
599 r = sd_journal_add_conjunction(self->j);
600 if (set_error(r, NULL, NULL) < 0)
605 PyDoc_STRVAR(Reader_flush_matches__doc__,
606 "flush_matches() -> None\n\n"
607 "Clear all current match filters.");
608 static PyObject* Reader_flush_matches(Reader *self, PyObject *args) {
609 sd_journal_flush_matches(self->j);
613 PyDoc_STRVAR(Reader_seek_head__doc__,
614 "seek_head() -> None\n\n"
615 "Jump to the beginning of the journal.\n"
616 "This method invokes sd_journal_seek_head().\n"
617 "See man:sd_journal_seek_head(3).");
618 static PyObject* Reader_seek_head(Reader *self, PyObject *args) {
620 Py_BEGIN_ALLOW_THREADS
621 r = sd_journal_seek_head(self->j);
624 if (set_error(r, NULL, NULL) < 0)
630 PyDoc_STRVAR(Reader_seek_tail__doc__,
631 "seek_tail() -> None\n\n"
632 "Jump to the end of the journal.\n"
633 "This method invokes sd_journal_seek_tail().\n"
634 "See man:sd_journal_seek_tail(3).");
635 static PyObject* Reader_seek_tail(Reader *self, PyObject *args) {
638 Py_BEGIN_ALLOW_THREADS
639 r = sd_journal_seek_tail(self->j);
642 if (set_error(r, NULL, NULL) < 0)
647 PyDoc_STRVAR(Reader_seek_realtime__doc__,
648 "seek_realtime(realtime) -> None\n\n"
649 "Seek to nearest matching journal entry to `realtime`. Argument\n"
650 "`realtime` in specified in seconds.");
651 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args) {
655 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
658 Py_BEGIN_ALLOW_THREADS
659 r = sd_journal_seek_realtime_usec(self->j, timestamp);
662 if (set_error(r, NULL, NULL) < 0)
668 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
669 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
670 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
671 "`monotonic` is an timestamp from boot in microseconds.\n"
672 "Argument `bootid` is a string representing which boot the\n"
673 "monotonic time is reference to. Defaults to current bootid.");
674 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args) {
680 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
684 r = sd_id128_from_string(bootid, &id);
685 if (set_error(r, NULL, "Invalid bootid") < 0)
688 Py_BEGIN_ALLOW_THREADS
689 r = sd_id128_get_boot(&id);
692 if (set_error(r, NULL, NULL) < 0)
696 Py_BEGIN_ALLOW_THREADS
697 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
700 if (set_error(r, NULL, NULL) < 0)
707 PyDoc_STRVAR(Reader_process__doc__,
708 "process() -> state change (integer)\n\n"
709 "Process events and reset the readable state of the file\n"
710 "descriptor returned by .fileno().\n\n"
711 "Will return constants: NOP if no change; APPEND if new\n"
712 "entries have been added to the end of the journal; and\n"
713 "INVALIDATE if journal files have been added or removed.\n\n"
714 "See man:sd_journal_process(3) for further discussion.");
715 static PyObject* Reader_process(Reader *self, PyObject *args) {
720 Py_BEGIN_ALLOW_THREADS
721 r = sd_journal_process(self->j);
723 if (set_error(r, NULL, NULL) < 0)
726 return long_FromLong(r);
729 PyDoc_STRVAR(Reader_wait__doc__,
730 "wait([timeout]) -> state change (integer)\n\n"
731 "Wait for a change in the journal. Argument `timeout` specifies\n"
732 "the maximum number of microseconds to wait before returning\n"
733 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
734 "then block forever.\n\n"
735 "Will return constants: NOP if no change; APPEND if new\n"
736 "entries have been added to the end of the journal; and\n"
737 "INVALIDATE if journal files have been added or removed.\n\n"
738 "See man:sd_journal_wait(3) for further discussion.");
739 static PyObject* Reader_wait(Reader *self, PyObject *args) {
743 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
746 Py_BEGIN_ALLOW_THREADS
747 r = sd_journal_wait(self->j, timeout);
750 if (set_error(r, NULL, NULL) < 0)
753 return long_FromLong(r);
756 PyDoc_STRVAR(Reader_seek_cursor__doc__,
757 "seek_cursor(cursor) -> None\n\n"
758 "Seek to journal entry by given unique reference `cursor`.");
759 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args) {
763 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
766 Py_BEGIN_ALLOW_THREADS
767 r = sd_journal_seek_cursor(self->j, cursor);
770 if (set_error(r, NULL, "Invalid cursor") < 0)
776 PyDoc_STRVAR(Reader_get_cursor__doc__,
777 "get_cursor() -> str\n\n"
778 "Return a cursor string for the current journal entry.\n\n"
779 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
780 static PyObject* Reader_get_cursor(Reader *self, PyObject *args) {
781 _cleanup_free_ char *cursor = NULL;
787 r = sd_journal_get_cursor(self->j, &cursor);
788 if (set_error(r, NULL, NULL) < 0)
791 return unicode_FromString(cursor);
794 PyDoc_STRVAR(Reader_test_cursor__doc__,
795 "test_cursor(str) -> bool\n\n"
796 "Test whether the cursor string matches current journal entry.\n\n"
797 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
798 static PyObject* Reader_test_cursor(Reader *self, PyObject *args) {
805 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
808 r = sd_journal_test_cursor(self->j, cursor);
809 if (set_error(r, NULL, NULL) < 0)
812 return PyBool_FromLong(r);
815 PyDoc_STRVAR(Reader_query_unique__doc__,
816 "query_unique(field) -> a set of values\n\n"
817 "Return a set of unique values appearing in journal for the\n"
818 "given `field`. Note this does not respect any journal matches.");
819 static PyObject* Reader_query_unique(Reader *self, PyObject *args) {
824 PyObject *value_set, *key, *value;
826 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
829 Py_BEGIN_ALLOW_THREADS
830 r = sd_journal_query_unique(self->j, query);
833 if (set_error(r, NULL, "Invalid field name") < 0)
836 value_set = PySet_New(0);
837 key = unicode_FromString(query);
839 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
840 const char *delim_ptr;
842 delim_ptr = memchr(uniq, '=', uniq_len);
843 value = PyBytes_FromStringAndSize(
845 (const char*) uniq + uniq_len - (delim_ptr + 1));
846 PySet_Add(value_set, value);
854 PyDoc_STRVAR(Reader_get_catalog__doc__,
855 "get_catalog() -> str\n\n"
856 "Retrieve a message catalog entry for the current journal entry.\n"
857 "Will throw IndexError if the entry has no MESSAGE_ID\n"
858 "and KeyError is the id is specified, but hasn't been found\n"
859 "in the catalog.\n\n"
860 "Wraps man:sd_journal_get_catalog(3).");
861 static PyObject* Reader_get_catalog(Reader *self, PyObject *args) {
863 _cleanup_free_ char *msg = NULL;
868 Py_BEGIN_ALLOW_THREADS
869 r = sd_journal_get_catalog(self->j, &msg);
876 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
878 const size_t l = sizeof("MESSAGE_ID");
880 PyErr_Format(PyExc_KeyError, "%.*s", (int) (mid_len - l),
881 (const char*) mid + l);
882 } else if (r == -ENOENT)
883 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
885 set_error(r, NULL, NULL);
889 if (set_error(r, NULL, NULL) < 0)
892 return unicode_FromString(msg);
895 PyDoc_STRVAR(get_catalog__doc__,
896 "get_catalog(id128) -> str\n\n"
897 "Retrieve a message catalog entry for the given id.\n"
898 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
899 static PyObject* get_catalog(PyObject *self, PyObject *args) {
903 _cleanup_free_ char *msg = NULL;
908 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
911 r = sd_id128_from_string(id_, &id);
912 if (set_error(r, NULL, "Invalid id128") < 0)
915 Py_BEGIN_ALLOW_THREADS
916 r = sd_journal_get_catalog_for_message_id(id, &msg);
919 if (set_error(r, NULL, NULL) < 0)
922 return unicode_FromString(msg);
925 PyDoc_STRVAR(data_threshold__doc__,
926 "Threshold for field size truncation in bytes.\n\n"
927 "Fields longer than this will be truncated to the threshold size.\n"
928 "Defaults to 64Kb.");
930 static PyObject* Reader_get_data_threshold(Reader *self, void *closure) {
934 r = sd_journal_get_data_threshold(self->j, &cvalue);
935 if (set_error(r, NULL, NULL) < 0)
938 return long_FromSize_t(cvalue);
941 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure) {
945 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
949 if (!long_Check(value)){
950 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
954 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
955 return set_error(r, NULL, NULL);
958 PyDoc_STRVAR(closed__doc__,
959 "True iff journal is closed");
960 static PyObject* Reader_get_closed(Reader *self, void *closure) {
961 return PyBool_FromLong(self->j == NULL);
964 static PyGetSetDef Reader_getsetters[] = {
965 { (char*) "data_threshold",
966 (getter) Reader_get_data_threshold,
967 (setter) Reader_set_data_threshold,
968 (char*) data_threshold__doc__,
971 (getter) Reader_get_closed,
973 (char*) closed__doc__,
978 static PyMethodDef Reader_methods[] = {
979 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
980 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
981 {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__},
982 {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__},
983 {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__},
984 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
985 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
986 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
987 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
988 {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
989 {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__},
990 {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
991 {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__},
992 {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
993 {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
994 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
995 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
996 {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__},
997 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
998 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
999 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
1000 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
1001 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
1002 {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__},
1003 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
1004 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
1005 {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
1006 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
1007 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
1008 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
1012 static PyTypeObject ReaderType = {
1013 PyVarObject_HEAD_INIT(NULL, 0)
1014 .tp_name = "_reader._Reader",
1015 .tp_basicsize = sizeof(Reader),
1016 .tp_dealloc = (destructor) Reader_dealloc,
1017 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1018 .tp_doc = Reader__doc__,
1019 .tp_methods = Reader_methods,
1020 .tp_getset = Reader_getsetters,
1021 .tp_init = (initproc) Reader_init,
1022 .tp_new = PyType_GenericNew,
1025 static PyMethodDef methods[] = {
1026 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
1030 #if PY_MAJOR_VERSION >= 3
1031 static PyModuleDef module = {
1032 PyModuleDef_HEAD_INIT,
1040 #if PY_MAJOR_VERSION >= 3
1041 static bool initialized = false;
1044 DISABLE_WARNING_MISSING_PROTOTYPES;
1047 #if PY_MAJOR_VERSION >= 3
1048 PyInit__reader(void)
1057 if (PyType_Ready(&ReaderType) < 0)
1058 #if PY_MAJOR_VERSION >= 3
1064 #if PY_MAJOR_VERSION >= 3
1065 m = PyModule_Create(&module);
1070 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1074 m = Py_InitModule3("_reader", methods, module__doc__);
1079 Py_INCREF(&ReaderType);
1080 #if PY_MAJOR_VERSION >= 3
1081 Py_INCREF(&MonotonicType);
1083 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1084 #if PY_MAJOR_VERSION >= 3
1085 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1087 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1088 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1089 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1090 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1091 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1092 PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) ||
1093 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) ||
1094 PyModule_AddIntConstant(m, "CURRENT_USER", SD_JOURNAL_CURRENT_USER) ||
1095 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
1096 #if PY_MAJOR_VERSION >= 3
1102 #if PY_MAJOR_VERSION >= 3