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>
39 static PyTypeObject ReaderType;
41 static int set_error(int r, const char* path, const char* invalid_message) {
44 if (r == -EINVAL && invalid_message)
45 PyErr_SetString(PyExc_ValueError, invalid_message);
46 else if (r == -ENOMEM)
47 PyErr_SetString(PyExc_MemoryError, "Not enough memory");
50 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
56 PyDoc_STRVAR(module__doc__,
57 "Class to reads the systemd journal similar to journalctl.");
60 #if PY_MAJOR_VERSION >= 3
61 static PyTypeObject MonotonicType;
63 PyDoc_STRVAR(MonotonicType__doc__,
64 "A tuple of (timestamp, bootid) for holding monotonic timestamps");
66 static PyStructSequence_Field MonotonicType_fields[] = {
67 {(char*) "timestamp", (char*) "Time"},
68 {(char*) "bootid", (char*) "Unique identifier of the boot"},
72 static PyStructSequence_Desc Monotonic_desc = {
73 (char*) "journal.Monotonic",
81 static void Reader_dealloc(Reader* self)
83 sd_journal_close(self->j);
84 Py_TYPE(self)->tp_free((PyObject*)self);
87 PyDoc_STRVAR(Reader__doc__,
88 "_Reader([flags | path]) -> ...\n\n"
89 "_Reader allows filtering and retrieval of Journal entries.\n"
90 "Note: this is a low-level interface, and probably not what you\n"
91 "want, use systemd.journal.Reader instead.\n\n"
92 "Argument `flags` sets open flags of the journal, which can be one\n"
93 "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n"
94 "journal on local machine only; RUNTIME_ONLY opens only\n"
95 "volatile journal files; and SYSTEM_ONLY opens only\n"
96 "journal files of system services and the kernel.\n\n"
97 "Argument `path` is the directory of journal files. Note that\n"
98 "`flags` and `path` are exclusive.\n\n"
99 "_Reader implements the context manager protocol: the journal\n"
100 "will be closed when exiting the block.");
101 static int Reader_init(Reader *self, PyObject *args, PyObject *keywds)
106 static const char* const kwlist[] = {"flags", "path", NULL};
107 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iz", (char**) kwlist,
112 flags = SD_JOURNAL_LOCAL_ONLY;
115 PyErr_SetString(PyExc_ValueError, "cannot use both flags and path");
119 Py_BEGIN_ALLOW_THREADS
121 r = sd_journal_open_directory(&self->j, path, 0);
123 r = sd_journal_open(&self->j, flags);
126 return set_error(r, path, "Invalid flags or path");
130 PyDoc_STRVAR(Reader_fileno__doc__,
131 "fileno() -> int\n\n"
132 "Get a file descriptor to poll for changes in the journal.\n"
133 "This method invokes sd_journal_get_fd().\n"
134 "See man:sd_journal_get_fd(3).");
135 static PyObject* Reader_fileno(Reader *self, PyObject *args)
137 int fd = sd_journal_get_fd(self->j);
138 set_error(fd, NULL, NULL);
141 return long_FromLong(fd);
145 PyDoc_STRVAR(Reader_reliable_fd__doc__,
146 "reliable_fd() -> bool\n\n"
147 "Returns True iff the journal can be polled reliably.\n"
148 "This method invokes sd_journal_reliable_fd().\n"
149 "See man:sd_journal_reliable_fd(3).");
150 static PyObject* Reader_reliable_fd(Reader *self, PyObject *args)
152 int r = sd_journal_reliable_fd(self->j);
153 set_error(r, NULL, NULL);
156 return PyBool_FromLong(r);
160 PyDoc_STRVAR(Reader_get_events__doc__,
161 "get_events() -> int\n\n"
162 "Returns a mask of poll() events to wait for on the file\n"
163 "descriptor returned by .fileno().\n\n"
164 "See man:sd_journal_get_events(3) for further discussion.");
165 static PyObject* Reader_get_events(Reader *self, PyObject *args)
167 int r = sd_journal_get_events(self->j);
168 set_error(r, NULL, NULL);
171 return long_FromLong(r);
175 PyDoc_STRVAR(Reader_get_timeout__doc__,
176 "get_timeout() -> int or None\n\n"
177 "Returns a timeout value for usage in poll(), the time since the\n"
178 "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
180 "The return value must be converted to a relative timeout in \n"
181 "milliseconds if it is to be used as an argument for poll().\n"
182 "See man:sd_journal_get_timeout(3) for further discussion.");
183 static PyObject* Reader_get_timeout(Reader *self, PyObject *args)
188 r = sd_journal_get_timeout(self->j, &t);
189 set_error(r, NULL, NULL);
193 if (t == (uint64_t) -1)
196 assert_cc(sizeof(unsigned long long) == sizeof(t));
197 return PyLong_FromUnsignedLongLong(t);
201 PyDoc_STRVAR(Reader_get_timeout_ms__doc__,
202 "get_timeout_ms() -> int\n\n"
203 "Returns a timeout value suitable for usage in poll(), the value\n"
204 "returned by .get_timeout() converted to relative ms, or -1 if\n"
205 "no timeout is necessary.");
206 static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args)
211 r = sd_journal_get_timeout(self->j, &t);
212 set_error(r, NULL, NULL);
216 return absolute_timeout(t);
220 PyDoc_STRVAR(Reader_close__doc__,
221 "close() -> None\n\n"
222 "Free resources allocated by this Reader object.\n"
223 "This method invokes sd_journal_close().\n"
224 "See man:sd_journal_close(3).");
225 static PyObject* Reader_close(Reader *self, PyObject *args)
230 sd_journal_close(self->j);
236 PyDoc_STRVAR(Reader_get_usage__doc__,
237 "get_usage() -> int\n\n"
238 "Returns the total disk space currently used by journal\n"
239 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
240 "passed when opening the journal this value will only reflect\n"
241 "the size of journal files of the local host, otherwise\n"
243 "This method invokes sd_journal_get_usage().\n"
244 "See man:sd_journal_get_usage(3).");
245 static PyObject* Reader_get_usage(Reader *self, PyObject *args)
250 r = sd_journal_get_usage(self->j, &bytes);
251 if (set_error(r, NULL, NULL))
254 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
255 return PyLong_FromUnsignedLongLong(bytes);
259 PyDoc_STRVAR(Reader___enter____doc__,
260 "__enter__() -> self\n\n"
261 "Part of the context manager protocol.\n"
263 static PyObject* Reader___enter__(PyObject *self, PyObject *args)
272 PyDoc_STRVAR(Reader___exit____doc__,
273 "__exit__(type, value, traceback) -> None\n\n"
274 "Part of the context manager protocol.\n"
275 "Closes the journal.\n");
276 static PyObject* Reader___exit__(Reader *self, PyObject *args)
280 sd_journal_close(self->j);
286 PyDoc_STRVAR(Reader_next__doc__,
287 "next([skip]) -> bool\n\n"
288 "Go to the next log entry. Optional skip value means to go to\n"
289 "the `skip`\\-th log entry.\n"
290 "Returns False if at end of file, True otherwise.");
291 static PyObject* Reader_next(Reader *self, PyObject *args)
296 if (!PyArg_ParseTuple(args, "|L:next", &skip))
300 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
304 Py_BEGIN_ALLOW_THREADS
306 r = sd_journal_next(self->j);
307 else if (skip == -1LL)
308 r = sd_journal_previous(self->j);
310 r = sd_journal_next_skip(self->j, skip);
311 else if (skip < -1LL)
312 r = sd_journal_previous_skip(self->j, -skip);
314 assert_not_reached("should not be here");
317 set_error(r, NULL, NULL);
320 return PyBool_FromLong(r);
323 PyDoc_STRVAR(Reader_previous__doc__,
324 "previous([skip]) -> bool\n\n"
325 "Go to the previous log entry. Optional skip value means to \n"
326 "go to the `skip`\\-th previous log entry.\n"
327 "Returns False if at start of file, True otherwise.");
328 static PyObject* Reader_previous(Reader *self, PyObject *args)
331 if (!PyArg_ParseTuple(args, "|L:previous", &skip))
334 return PyObject_CallMethod((PyObject *)self, (char*) "_next",
339 static int extract(const char* msg, size_t msg_len,
340 PyObject **key, PyObject **value) {
341 PyObject *k = NULL, *v;
342 const char *delim_ptr;
344 delim_ptr = memchr(msg, '=', msg_len);
346 PyErr_SetString(PyExc_OSError,
347 "journal gave us a field without '='");
352 k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
358 v = PyBytes_FromStringAndSize(delim_ptr + 1,
359 (const char*) msg + msg_len - (delim_ptr + 1));
374 PyDoc_STRVAR(Reader_get__doc__,
375 "get(str) -> str\n\n"
376 "Return data associated with this key in current log entry.\n"
377 "Throws KeyError is the data is not available.");
378 static PyObject* Reader_get(Reader *self, PyObject *args)
389 if (!PyArg_ParseTuple(args, "s:get", &field))
392 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
394 PyErr_SetString(PyExc_KeyError, field);
396 } else if (set_error(r, NULL, "field name is not valid"))
399 r = extract(msg, msg_len, NULL, &value);
406 PyDoc_STRVAR(Reader_get_all__doc__,
407 "_get_all() -> dict\n\n"
408 "Return dictionary of the current log entry.");
409 static PyObject* Reader_get_all(Reader *self, PyObject *args)
420 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
421 _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL;
423 r = extract(msg, msg_len, &key, &value);
427 if (PyDict_Contains(dict, key)) {
428 PyObject *cur_value = PyDict_GetItem(dict, key);
430 if (PyList_CheckExact(cur_value)) {
431 r = PyList_Append(cur_value, value);
435 _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0);
439 r = PyList_Append(tmp_list, cur_value);
443 r = PyList_Append(tmp_list, value);
447 r = PyDict_SetItem(dict, key, tmp_list);
452 r = PyDict_SetItem(dict, key, value);
466 PyDoc_STRVAR(Reader_get_realtime__doc__,
467 "get_realtime() -> int\n\n"
468 "Return the realtime timestamp for the current journal entry\n"
469 "in microseconds.\n\n"
470 "Wraps sd_journal_get_realtime_usec().\n"
471 "See man:sd_journal_get_realtime_usec(3).");
472 static PyObject* Reader_get_realtime(Reader *self, PyObject *args)
480 r = sd_journal_get_realtime_usec(self->j, ×tamp);
481 if (set_error(r, NULL, NULL))
484 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
485 return PyLong_FromUnsignedLongLong(timestamp);
489 PyDoc_STRVAR(Reader_get_monotonic__doc__,
490 "get_monotonic() -> (timestamp, bootid)\n\n"
491 "Return the monotonic timestamp for the current journal entry\n"
492 "as a tuple of time in microseconds and bootid.\n\n"
493 "Wraps sd_journal_get_monotonic_usec().\n"
494 "See man:sd_journal_get_monotonic_usec(3).");
495 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args)
499 PyObject *monotonic, *bootid, *tuple;
505 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
506 if (set_error(r, NULL, NULL))
509 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
510 monotonic = PyLong_FromUnsignedLongLong(timestamp);
511 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
512 #if PY_MAJOR_VERSION >= 3
513 tuple = PyStructSequence_New(&MonotonicType);
515 tuple = PyTuple_New(2);
517 if (!monotonic || !bootid || !tuple) {
518 Py_XDECREF(monotonic);
524 #if PY_MAJOR_VERSION >= 3
525 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
526 PyStructSequence_SET_ITEM(tuple, 1, bootid);
528 PyTuple_SET_ITEM(tuple, 0, monotonic);
529 PyTuple_SET_ITEM(tuple, 1, bootid);
535 PyDoc_STRVAR(Reader_add_match__doc__,
536 "add_match(match) -> None\n\n"
537 "Add a match to filter journal log entries. All matches of different\n"
538 "fields are combined with logical AND, and matches of the same field\n"
539 "are automatically combined with logical OR.\n"
540 "Match is a string of the form \"FIELD=value\".");
541 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
545 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
548 r = sd_journal_add_match(self->j, match, match_len);
549 set_error(r, NULL, "Invalid match");
557 PyDoc_STRVAR(Reader_add_disjunction__doc__,
558 "add_disjunction() -> None\n\n"
559 "Inserts a logical OR between matches added since previous\n"
560 "add_disjunction() or add_conjunction() and the next\n"
561 "add_disjunction() or add_conjunction().\n\n"
562 "See man:sd_journal_add_disjunction(3) for explanation.");
563 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
566 r = sd_journal_add_disjunction(self->j);
567 set_error(r, NULL, NULL);
574 PyDoc_STRVAR(Reader_add_conjunction__doc__,
575 "add_conjunction() -> None\n\n"
576 "Inserts a logical AND between matches added since previous\n"
577 "add_disjunction() or add_conjunction() and the next\n"
578 "add_disjunction() or add_conjunction().\n\n"
579 "See man:sd_journal_add_disjunction(3) for explanation.");
580 static PyObject* Reader_add_conjunction(Reader *self, PyObject *args)
583 r = sd_journal_add_conjunction(self->j);
584 set_error(r, NULL, NULL);
591 PyDoc_STRVAR(Reader_flush_matches__doc__,
592 "flush_matches() -> None\n\n"
593 "Clear all current match filters.");
594 static PyObject* Reader_flush_matches(Reader *self, PyObject *args)
596 sd_journal_flush_matches(self->j);
601 PyDoc_STRVAR(Reader_seek_head__doc__,
602 "seek_head() -> None\n\n"
603 "Jump to the beginning of the journal.\n"
604 "This method invokes sd_journal_seek_head().\n"
605 "See man:sd_journal_seek_head(3).");
606 static PyObject* Reader_seek_head(Reader *self, PyObject *args)
609 Py_BEGIN_ALLOW_THREADS
610 r = sd_journal_seek_head(self->j);
612 if (set_error(r, NULL, NULL))
618 PyDoc_STRVAR(Reader_seek_tail__doc__,
619 "seek_tail() -> None\n\n"
620 "Jump to the end of the journal.\n"
621 "This method invokes sd_journal_seek_tail().\n"
622 "See man:sd_journal_seek_tail(3).");
623 static PyObject* Reader_seek_tail(Reader *self, PyObject *args)
626 Py_BEGIN_ALLOW_THREADS
627 r = sd_journal_seek_tail(self->j);
629 if (set_error(r, NULL, NULL))
635 PyDoc_STRVAR(Reader_seek_realtime__doc__,
636 "seek_realtime(realtime) -> None\n\n"
637 "Seek to nearest matching journal entry to `realtime`. Argument\n"
638 "`realtime` in specified in seconds.");
639 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args)
644 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
647 Py_BEGIN_ALLOW_THREADS
648 r = sd_journal_seek_realtime_usec(self->j, timestamp);
650 if (set_error(r, NULL, NULL))
656 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
657 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
658 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
659 "`monotonic` is an timestamp from boot in microseconds.\n"
660 "Argument `bootid` is a string representing which boot the\n"
661 "monotonic time is reference to. Defaults to current bootid.");
662 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args)
669 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
673 r = sd_id128_from_string(bootid, &id);
674 if (set_error(r, NULL, "Invalid bootid"))
677 Py_BEGIN_ALLOW_THREADS
678 r = sd_id128_get_boot(&id);
680 if (set_error(r, NULL, NULL))
684 Py_BEGIN_ALLOW_THREADS
685 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
687 if (set_error(r, NULL, NULL))
694 PyDoc_STRVAR(Reader_process__doc__,
695 "process() -> state change (integer)\n\n"
696 "Process events and reset the readable state of the file\n"
697 "descriptor returned by .fileno().\n\n"
698 "Will return constants: NOP if no change; APPEND if new\n"
699 "entries have been added to the end of the journal; and\n"
700 "INVALIDATE if journal files have been added or removed.\n\n"
701 "See man:sd_journal_process(3) for further discussion.");
702 static PyObject* Reader_process(Reader *self, PyObject *args)
708 Py_BEGIN_ALLOW_THREADS
709 r = sd_journal_process(self->j);
711 if (set_error(r, NULL, NULL) < 0)
714 return long_FromLong(r);
718 PyDoc_STRVAR(Reader_wait__doc__,
719 "wait([timeout]) -> state change (integer)\n\n"
720 "Wait for a change in the journal. Argument `timeout` specifies\n"
721 "the maximum number of microseconds to wait before returning\n"
722 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
723 "then block forever.\n\n"
724 "Will return constants: NOP if no change; APPEND if new\n"
725 "entries have been added to the end of the journal; and\n"
726 "INVALIDATE if journal files have been added or removed.\n\n"
727 "See man:sd_journal_wait(3) for further discussion.");
728 static PyObject* Reader_wait(Reader *self, PyObject *args)
733 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
736 Py_BEGIN_ALLOW_THREADS
737 r = sd_journal_wait(self->j, timeout);
739 if (set_error(r, NULL, NULL) < 0)
742 return long_FromLong(r);
746 PyDoc_STRVAR(Reader_seek_cursor__doc__,
747 "seek_cursor(cursor) -> None\n\n"
748 "Seek to journal entry by given unique reference `cursor`.");
749 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
754 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
757 Py_BEGIN_ALLOW_THREADS
758 r = sd_journal_seek_cursor(self->j, cursor);
760 if (set_error(r, NULL, "Invalid cursor"))
766 PyDoc_STRVAR(Reader_get_cursor__doc__,
767 "get_cursor() -> str\n\n"
768 "Return a cursor string for the current journal entry.\n\n"
769 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
770 static PyObject* Reader_get_cursor(Reader *self, PyObject *args)
772 _cleanup_free_ char *cursor = NULL;
778 r = sd_journal_get_cursor(self->j, &cursor);
779 if (set_error(r, NULL, NULL))
782 return unicode_FromString(cursor);
786 PyDoc_STRVAR(Reader_test_cursor__doc__,
787 "test_cursor(str) -> bool\n\n"
788 "Test whether the cursor string matches current journal entry.\n\n"
789 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
790 static PyObject* Reader_test_cursor(Reader *self, PyObject *args)
798 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
801 r = sd_journal_test_cursor(self->j, cursor);
802 set_error(r, NULL, NULL);
806 return PyBool_FromLong(r);
809 PyDoc_STRVAR(Reader_query_unique__doc__,
810 "query_unique(field) -> a set of values\n\n"
811 "Return a set of unique values appearing in journal for the\n"
812 "given `field`. Note this does not respect any journal matches.");
813 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
819 PyObject *value_set, *key, *value;
821 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
824 Py_BEGIN_ALLOW_THREADS
825 r = sd_journal_query_unique(self->j, query);
827 if (set_error(r, NULL, "Invalid field name"))
830 value_set = PySet_New(0);
831 key = unicode_FromString(query);
833 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
834 const char *delim_ptr;
836 delim_ptr = memchr(uniq, '=', uniq_len);
837 value = PyBytes_FromStringAndSize(
839 (const char*) uniq + uniq_len - (delim_ptr + 1));
840 PySet_Add(value_set, value);
848 PyDoc_STRVAR(Reader_get_catalog__doc__,
849 "get_catalog() -> str\n\n"
850 "Retrieve a message catalog entry for the current journal entry.\n"
851 "Will throw IndexError if the entry has no MESSAGE_ID\n"
852 "and KeyError is the id is specified, but hasn't been found\n"
853 "in the catalog.\n\n"
854 "Wraps man:sd_journal_get_catalog(3).");
855 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
858 _cleanup_free_ char *msg = NULL;
863 Py_BEGIN_ALLOW_THREADS
864 r = sd_journal_get_catalog(self->j, &msg);
870 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
872 const int l = sizeof("MESSAGE_ID");
874 PyErr_Format(PyExc_KeyError, "%.*s", (int) mid_len - l,
875 (const char*) mid + l);
876 } else if (r == -ENOENT)
877 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
879 set_error(r, NULL, NULL);
881 } else if (set_error(r, NULL, NULL))
884 return unicode_FromString(msg);
888 PyDoc_STRVAR(get_catalog__doc__,
889 "get_catalog(id128) -> str\n\n"
890 "Retrieve a message catalog entry for the given id.\n"
891 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
892 static PyObject* get_catalog(PyObject *self, PyObject *args)
897 _cleanup_free_ char *msg = NULL;
902 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
905 r = sd_id128_from_string(id_, &id);
906 if (set_error(r, NULL, "Invalid id128"))
909 Py_BEGIN_ALLOW_THREADS
910 r = sd_journal_get_catalog_for_message_id(id, &msg);
912 if (set_error(r, NULL, NULL))
915 return unicode_FromString(msg);
919 PyDoc_STRVAR(data_threshold__doc__,
920 "Threshold for field size truncation in bytes.\n\n"
921 "Fields longer than this will be truncated to the threshold size.\n"
922 "Defaults to 64Kb.");
924 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
929 r = sd_journal_get_data_threshold(self->j, &cvalue);
930 if (set_error(r, NULL, NULL))
933 return long_FromSize_t(cvalue);
936 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
940 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
943 if (!long_Check(value)){
944 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
947 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
948 return set_error(r, NULL, NULL);
952 PyDoc_STRVAR(closed__doc__,
953 "True iff journal is closed");
954 static PyObject* Reader_get_closed(Reader *self, void *closure)
956 return PyBool_FromLong(self->j == NULL);
960 static PyGetSetDef Reader_getsetters[] = {
961 {(char*) "data_threshold",
962 (getter) Reader_get_data_threshold,
963 (setter) Reader_set_data_threshold,
964 (char*) data_threshold__doc__,
967 (getter) Reader_get_closed,
969 (char*) closed__doc__,
974 static PyMethodDef Reader_methods[] = {
975 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
976 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
977 {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__},
978 {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__},
979 {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__},
980 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
981 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
982 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
983 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
984 {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
985 {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__},
986 {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
987 {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__},
988 {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
989 {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
990 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
991 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
992 {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__},
993 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
994 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
995 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
996 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
997 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
998 {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__},
999 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
1000 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
1001 {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
1002 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
1003 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
1004 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
1008 static PyTypeObject ReaderType = {
1009 PyVarObject_HEAD_INIT(NULL, 0)
1010 "_reader._Reader", /*tp_name*/
1011 sizeof(Reader), /*tp_basicsize*/
1013 (destructor)Reader_dealloc, /*tp_dealloc*/
1020 0, /*tp_as_sequence*/
1021 0, /*tp_as_mapping*/
1028 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1029 Reader__doc__, /* tp_doc */
1030 0, /* tp_traverse */
1032 0, /* tp_richcompare */
1033 0, /* tp_weaklistoffset */
1035 0, /* tp_iternext */
1036 Reader_methods, /* tp_methods */
1038 Reader_getsetters, /* tp_getset */
1041 0, /* tp_descr_get */
1042 0, /* tp_descr_set */
1043 0, /* tp_dictoffset */
1044 (initproc) Reader_init, /* tp_init */
1046 PyType_GenericNew, /* tp_new */
1049 static PyMethodDef methods[] = {
1050 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
1051 { NULL, NULL, 0, NULL } /* Sentinel */
1054 #if PY_MAJOR_VERSION >= 3
1055 static PyModuleDef module = {
1056 PyModuleDef_HEAD_INIT,
1061 NULL, NULL, NULL, NULL
1065 #if PY_MAJOR_VERSION >= 3
1066 static bool initialized = false;
1069 #pragma GCC diagnostic push
1070 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
1073 #if PY_MAJOR_VERSION >= 3
1074 PyInit__reader(void)
1083 if (PyType_Ready(&ReaderType) < 0)
1084 #if PY_MAJOR_VERSION >= 3
1090 #if PY_MAJOR_VERSION >= 3
1091 m = PyModule_Create(&module);
1096 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1100 m = Py_InitModule3("_reader", methods, module__doc__);
1105 Py_INCREF(&ReaderType);
1106 #if PY_MAJOR_VERSION >= 3
1107 Py_INCREF(&MonotonicType);
1109 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1110 #if PY_MAJOR_VERSION >= 3
1111 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1113 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1114 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1115 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1116 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1117 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1118 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) ||
1119 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
1120 #if PY_MAJOR_VERSION >= 3
1126 #if PY_MAJOR_VERSION >= 3
1131 #pragma GCC diagnostic pop