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 if (t == (uint64_t) -1)
217 return PyLong_FromLong(-1);
223 clock_gettime(CLOCK_MONOTONIC, &ts);
224 n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
225 msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
227 return PyLong_FromLong(msec);
232 PyDoc_STRVAR(Reader_close__doc__,
233 "close() -> None\n\n"
234 "Free resources allocated by this Reader object.\n"
235 "This method invokes sd_journal_close().\n"
236 "See man:sd_journal_close(3).");
237 static PyObject* Reader_close(Reader *self, PyObject *args)
242 sd_journal_close(self->j);
248 PyDoc_STRVAR(Reader_get_usage__doc__,
249 "get_usage() -> int\n\n"
250 "Returns the total disk space currently used by journal\n"
251 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
252 "passed when opening the journal this value will only reflect\n"
253 "the size of journal files of the local host, otherwise\n"
255 "This method invokes sd_journal_get_usage().\n"
256 "See man:sd_journal_get_usage(3).");
257 static PyObject* Reader_get_usage(Reader *self, PyObject *args)
262 r = sd_journal_get_usage(self->j, &bytes);
263 if (set_error(r, NULL, NULL))
266 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
267 return PyLong_FromUnsignedLongLong(bytes);
271 PyDoc_STRVAR(Reader___enter____doc__,
272 "__enter__() -> self\n\n"
273 "Part of the context manager protocol.\n"
275 static PyObject* Reader___enter__(PyObject *self, PyObject *args)
284 PyDoc_STRVAR(Reader___exit____doc__,
285 "__exit__(type, value, traceback) -> None\n\n"
286 "Part of the context manager protocol.\n"
287 "Closes the journal.\n");
288 static PyObject* Reader___exit__(Reader *self, PyObject *args)
292 sd_journal_close(self->j);
298 PyDoc_STRVAR(Reader_next__doc__,
299 "next([skip]) -> bool\n\n"
300 "Go to the next log entry. Optional skip value means to go to\n"
301 "the `skip`\\-th log entry.\n"
302 "Returns False if at end of file, True otherwise.");
303 static PyObject* Reader_next(Reader *self, PyObject *args)
308 if (!PyArg_ParseTuple(args, "|L:next", &skip))
312 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
316 Py_BEGIN_ALLOW_THREADS
318 r = sd_journal_next(self->j);
319 else if (skip == -1LL)
320 r = sd_journal_previous(self->j);
322 r = sd_journal_next_skip(self->j, skip);
323 else if (skip < -1LL)
324 r = sd_journal_previous_skip(self->j, -skip);
326 assert_not_reached("should not be here");
329 set_error(r, NULL, NULL);
332 return PyBool_FromLong(r);
335 PyDoc_STRVAR(Reader_previous__doc__,
336 "previous([skip]) -> bool\n\n"
337 "Go to the previous log entry. Optional skip value means to \n"
338 "go to the `skip`\\-th previous log entry.\n"
339 "Returns False if at start of file, True otherwise.");
340 static PyObject* Reader_previous(Reader *self, PyObject *args)
343 if (!PyArg_ParseTuple(args, "|L:previous", &skip))
346 return PyObject_CallMethod((PyObject *)self, (char*) "_next",
351 static int extract(const char* msg, size_t msg_len,
352 PyObject **key, PyObject **value) {
353 PyObject *k = NULL, *v;
354 const char *delim_ptr;
356 delim_ptr = memchr(msg, '=', msg_len);
358 PyErr_SetString(PyExc_OSError,
359 "journal gave us a field without '='");
364 k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
370 v = PyBytes_FromStringAndSize(delim_ptr + 1,
371 (const char*) msg + msg_len - (delim_ptr + 1));
386 PyDoc_STRVAR(Reader_get__doc__,
387 "get(str) -> str\n\n"
388 "Return data associated with this key in current log entry.\n"
389 "Throws KeyError is the data is not available.");
390 static PyObject* Reader_get(Reader *self, PyObject *args)
401 if (!PyArg_ParseTuple(args, "s:get", &field))
404 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
406 PyErr_SetString(PyExc_KeyError, field);
408 } else if (set_error(r, NULL, "field name is not valid"))
411 r = extract(msg, msg_len, NULL, &value);
418 PyDoc_STRVAR(Reader_get_all__doc__,
419 "_get_all() -> dict\n\n"
420 "Return dictionary of the current log entry.");
421 static PyObject* Reader_get_all(Reader *self, PyObject *args)
432 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
433 _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL;
435 r = extract(msg, msg_len, &key, &value);
439 if (PyDict_Contains(dict, key)) {
440 PyObject *cur_value = PyDict_GetItem(dict, key);
442 if (PyList_CheckExact(cur_value)) {
443 r = PyList_Append(cur_value, value);
447 _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0);
451 r = PyList_Append(tmp_list, cur_value);
455 r = PyList_Append(tmp_list, value);
459 r = PyDict_SetItem(dict, key, tmp_list);
464 r = PyDict_SetItem(dict, key, value);
478 PyDoc_STRVAR(Reader_get_realtime__doc__,
479 "get_realtime() -> int\n\n"
480 "Return the realtime timestamp for the current journal entry\n"
481 "in microseconds.\n\n"
482 "Wraps sd_journal_get_realtime_usec().\n"
483 "See man:sd_journal_get_realtime_usec(3).");
484 static PyObject* Reader_get_realtime(Reader *self, PyObject *args)
492 r = sd_journal_get_realtime_usec(self->j, ×tamp);
493 if (set_error(r, NULL, NULL))
496 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
497 return PyLong_FromUnsignedLongLong(timestamp);
501 PyDoc_STRVAR(Reader_get_monotonic__doc__,
502 "get_monotonic() -> (timestamp, bootid)\n\n"
503 "Return the monotonic timestamp for the current journal entry\n"
504 "as a tuple of time in microseconds and bootid.\n\n"
505 "Wraps sd_journal_get_monotonic_usec().\n"
506 "See man:sd_journal_get_monotonic_usec(3).");
507 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args)
511 PyObject *monotonic, *bootid, *tuple;
517 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
518 if (set_error(r, NULL, NULL))
521 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
522 monotonic = PyLong_FromUnsignedLongLong(timestamp);
523 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
524 #if PY_MAJOR_VERSION >= 3
525 tuple = PyStructSequence_New(&MonotonicType);
527 tuple = PyTuple_New(2);
529 if (!monotonic || !bootid || !tuple) {
530 Py_XDECREF(monotonic);
536 #if PY_MAJOR_VERSION >= 3
537 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
538 PyStructSequence_SET_ITEM(tuple, 1, bootid);
540 PyTuple_SET_ITEM(tuple, 0, monotonic);
541 PyTuple_SET_ITEM(tuple, 1, bootid);
547 PyDoc_STRVAR(Reader_add_match__doc__,
548 "add_match(match) -> None\n\n"
549 "Add a match to filter journal log entries. All matches of different\n"
550 "fields are combined with logical AND, and matches of the same field\n"
551 "are automatically combined with logical OR.\n"
552 "Match is a string of the form \"FIELD=value\".");
553 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
557 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
560 r = sd_journal_add_match(self->j, match, match_len);
561 set_error(r, NULL, "Invalid match");
569 PyDoc_STRVAR(Reader_add_disjunction__doc__,
570 "add_disjunction() -> None\n\n"
571 "Inserts a logical OR between matches added since previous\n"
572 "add_disjunction() or add_conjunction() and the next\n"
573 "add_disjunction() or add_conjunction().\n\n"
574 "See man:sd_journal_add_disjunction(3) for explanation.");
575 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
578 r = sd_journal_add_disjunction(self->j);
579 set_error(r, NULL, NULL);
586 PyDoc_STRVAR(Reader_add_conjunction__doc__,
587 "add_conjunction() -> None\n\n"
588 "Inserts a logical AND between matches added since previous\n"
589 "add_disjunction() or add_conjunction() and the next\n"
590 "add_disjunction() or add_conjunction().\n\n"
591 "See man:sd_journal_add_disjunction(3) for explanation.");
592 static PyObject* Reader_add_conjunction(Reader *self, PyObject *args)
595 r = sd_journal_add_conjunction(self->j);
596 set_error(r, NULL, NULL);
603 PyDoc_STRVAR(Reader_flush_matches__doc__,
604 "flush_matches() -> None\n\n"
605 "Clear all current match filters.");
606 static PyObject* Reader_flush_matches(Reader *self, PyObject *args)
608 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)
621 Py_BEGIN_ALLOW_THREADS
622 r = sd_journal_seek_head(self->j);
624 if (set_error(r, NULL, NULL))
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);
641 if (set_error(r, NULL, NULL))
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)
656 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
659 Py_BEGIN_ALLOW_THREADS
660 r = sd_journal_seek_realtime_usec(self->j, timestamp);
662 if (set_error(r, NULL, NULL))
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)
681 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
685 r = sd_id128_from_string(bootid, &id);
686 if (set_error(r, NULL, "Invalid bootid"))
689 Py_BEGIN_ALLOW_THREADS
690 r = sd_id128_get_boot(&id);
692 if (set_error(r, NULL, NULL))
696 Py_BEGIN_ALLOW_THREADS
697 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
699 if (set_error(r, NULL, NULL))
706 PyDoc_STRVAR(Reader_process__doc__,
707 "process() -> state change (integer)\n\n"
708 "Process events and reset the readable state of the file\n"
709 "descriptor returned by .fileno().\n\n"
710 "Will return constants: NOP if no change; APPEND if new\n"
711 "entries have been added to the end of the journal; and\n"
712 "INVALIDATE if journal files have been added or removed.\n\n"
713 "See man:sd_journal_process(3) for further discussion.");
714 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);
730 PyDoc_STRVAR(Reader_wait__doc__,
731 "wait([timeout]) -> state change (integer)\n\n"
732 "Wait for a change in the journal. Argument `timeout` specifies\n"
733 "the maximum number of microseconds to wait before returning\n"
734 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
735 "then block forever.\n\n"
736 "Will return constants: NOP if no change; APPEND if new\n"
737 "entries have been added to the end of the journal; and\n"
738 "INVALIDATE if journal files have been added or removed.\n\n"
739 "See man:sd_journal_wait(3) for further discussion.");
740 static PyObject* Reader_wait(Reader *self, PyObject *args)
745 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
748 Py_BEGIN_ALLOW_THREADS
749 r = sd_journal_wait(self->j, timeout);
751 if (set_error(r, NULL, NULL) < 0)
754 return long_FromLong(r);
758 PyDoc_STRVAR(Reader_seek_cursor__doc__,
759 "seek_cursor(cursor) -> None\n\n"
760 "Seek to journal entry by given unique reference `cursor`.");
761 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
766 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
769 Py_BEGIN_ALLOW_THREADS
770 r = sd_journal_seek_cursor(self->j, cursor);
772 if (set_error(r, NULL, "Invalid cursor"))
778 PyDoc_STRVAR(Reader_get_cursor__doc__,
779 "get_cursor() -> str\n\n"
780 "Return a cursor string for the current journal entry.\n\n"
781 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
782 static PyObject* Reader_get_cursor(Reader *self, PyObject *args)
784 _cleanup_free_ char *cursor = NULL;
790 r = sd_journal_get_cursor(self->j, &cursor);
791 if (set_error(r, NULL, NULL))
794 return unicode_FromString(cursor);
798 PyDoc_STRVAR(Reader_test_cursor__doc__,
799 "test_cursor(str) -> bool\n\n"
800 "Test whether the cursor string matches current journal entry.\n\n"
801 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
802 static PyObject* Reader_test_cursor(Reader *self, PyObject *args)
810 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
813 r = sd_journal_test_cursor(self->j, cursor);
814 set_error(r, NULL, NULL);
818 return PyBool_FromLong(r);
821 PyDoc_STRVAR(Reader_query_unique__doc__,
822 "query_unique(field) -> a set of values\n\n"
823 "Return a set of unique values appearing in journal for the\n"
824 "given `field`. Note this does not respect any journal matches.");
825 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
831 PyObject *value_set, *key, *value;
833 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
836 Py_BEGIN_ALLOW_THREADS
837 r = sd_journal_query_unique(self->j, query);
839 if (set_error(r, NULL, "Invalid field name"))
842 value_set = PySet_New(0);
843 key = unicode_FromString(query);
845 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
846 const char *delim_ptr;
848 delim_ptr = memchr(uniq, '=', uniq_len);
849 value = PyBytes_FromStringAndSize(
851 (const char*) uniq + uniq_len - (delim_ptr + 1));
852 PySet_Add(value_set, value);
860 PyDoc_STRVAR(Reader_get_catalog__doc__,
861 "get_catalog() -> str\n\n"
862 "Retrieve a message catalog entry for the current journal entry.\n"
863 "Will throw IndexError if the entry has no MESSAGE_ID\n"
864 "and KeyError is the id is specified, but hasn't been found\n"
865 "in the catalog.\n\n"
866 "Wraps man:sd_journal_get_catalog(3).");
867 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
870 _cleanup_free_ char *msg = NULL;
875 Py_BEGIN_ALLOW_THREADS
876 r = sd_journal_get_catalog(self->j, &msg);
882 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
884 const int l = sizeof("MESSAGE_ID");
886 PyErr_Format(PyExc_KeyError, "%.*s", (int) mid_len - l,
887 (const char*) mid + l);
888 } else if (r == -ENOENT)
889 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
891 set_error(r, NULL, NULL);
893 } else if (set_error(r, NULL, NULL))
896 return unicode_FromString(msg);
900 PyDoc_STRVAR(get_catalog__doc__,
901 "get_catalog(id128) -> str\n\n"
902 "Retrieve a message catalog entry for the given id.\n"
903 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
904 static PyObject* get_catalog(PyObject *self, PyObject *args)
909 _cleanup_free_ char *msg = NULL;
914 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
917 r = sd_id128_from_string(id_, &id);
918 if (set_error(r, NULL, "Invalid id128"))
921 Py_BEGIN_ALLOW_THREADS
922 r = sd_journal_get_catalog_for_message_id(id, &msg);
924 if (set_error(r, NULL, NULL))
927 return unicode_FromString(msg);
931 PyDoc_STRVAR(data_threshold__doc__,
932 "Threshold for field size truncation in bytes.\n\n"
933 "Fields longer than this will be truncated to the threshold size.\n"
934 "Defaults to 64Kb.");
936 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
941 r = sd_journal_get_data_threshold(self->j, &cvalue);
942 if (set_error(r, NULL, NULL))
945 return long_FromSize_t(cvalue);
948 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
952 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
955 if (!long_Check(value)){
956 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
959 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
960 return set_error(r, NULL, NULL);
964 PyDoc_STRVAR(closed__doc__,
965 "True iff journal is closed");
966 static PyObject* Reader_get_closed(Reader *self, void *closure)
968 return PyBool_FromLong(self->j == NULL);
972 static PyGetSetDef Reader_getsetters[] = {
973 {(char*) "data_threshold",
974 (getter) Reader_get_data_threshold,
975 (setter) Reader_set_data_threshold,
976 (char*) data_threshold__doc__,
979 (getter) Reader_get_closed,
981 (char*) closed__doc__,
986 static PyMethodDef Reader_methods[] = {
987 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
988 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
989 {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__},
990 {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__},
991 {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__},
992 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
993 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
994 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
995 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
996 {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
997 {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__},
998 {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
999 {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__},
1000 {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
1001 {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
1002 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
1003 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
1004 {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__},
1005 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
1006 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
1007 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
1008 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
1009 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
1010 {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__},
1011 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
1012 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
1013 {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
1014 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
1015 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
1016 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
1020 static PyTypeObject ReaderType = {
1021 PyVarObject_HEAD_INIT(NULL, 0)
1022 "_reader._Reader", /*tp_name*/
1023 sizeof(Reader), /*tp_basicsize*/
1025 (destructor)Reader_dealloc, /*tp_dealloc*/
1032 0, /*tp_as_sequence*/
1033 0, /*tp_as_mapping*/
1040 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1041 Reader__doc__, /* tp_doc */
1042 0, /* tp_traverse */
1044 0, /* tp_richcompare */
1045 0, /* tp_weaklistoffset */
1047 0, /* tp_iternext */
1048 Reader_methods, /* tp_methods */
1050 Reader_getsetters, /* tp_getset */
1053 0, /* tp_descr_get */
1054 0, /* tp_descr_set */
1055 0, /* tp_dictoffset */
1056 (initproc) Reader_init, /* tp_init */
1058 PyType_GenericNew, /* tp_new */
1061 static PyMethodDef methods[] = {
1062 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
1063 { NULL, NULL, 0, NULL } /* Sentinel */
1066 #if PY_MAJOR_VERSION >= 3
1067 static PyModuleDef module = {
1068 PyModuleDef_HEAD_INIT,
1073 NULL, NULL, NULL, NULL
1077 #if PY_MAJOR_VERSION >= 3
1078 static bool initialized = false;
1081 #pragma GCC diagnostic push
1082 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
1085 #if PY_MAJOR_VERSION >= 3
1086 PyInit__reader(void)
1095 if (PyType_Ready(&ReaderType) < 0)
1096 #if PY_MAJOR_VERSION >= 3
1102 #if PY_MAJOR_VERSION >= 3
1103 m = PyModule_Create(&module);
1108 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1112 m = Py_InitModule3("_reader", methods, module__doc__);
1117 Py_INCREF(&ReaderType);
1118 #if PY_MAJOR_VERSION >= 3
1119 Py_INCREF(&MonotonicType);
1121 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1122 #if PY_MAJOR_VERSION >= 3
1123 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1125 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1126 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1127 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1128 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1129 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1130 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) ||
1131 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
1132 #if PY_MAJOR_VERSION >= 3
1138 #if PY_MAJOR_VERSION >= 3
1143 #pragma GCC diagnostic pop