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>
38 static PyTypeObject ReaderType;
40 static int set_error(int r, const char* path, const char* invalid_message) {
43 if (r == -EINVAL && invalid_message)
44 PyErr_SetString(PyExc_ValueError, invalid_message);
45 else if (r == -ENOMEM)
46 PyErr_SetString(PyExc_MemoryError, "Not enough memory");
49 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
55 PyDoc_STRVAR(module__doc__,
56 "Class to reads the systemd journal similar to journalctl.");
59 #if PY_MAJOR_VERSION >= 3
60 static PyTypeObject MonotonicType;
62 PyDoc_STRVAR(MonotonicType__doc__,
63 "A tuple of (timestamp, bootid) for holding monotonic timestamps");
65 static PyStructSequence_Field MonotonicType_fields[] = {
66 {(char*) "timestamp", (char*) "Time"},
67 {(char*) "bootid", (char*) "Unique identifier of the boot"},
71 static PyStructSequence_Desc Monotonic_desc = {
72 (char*) "journal.Monotonic",
80 static void Reader_dealloc(Reader* self)
82 sd_journal_close(self->j);
83 Py_TYPE(self)->tp_free((PyObject*)self);
86 PyDoc_STRVAR(Reader__doc__,
87 "_Reader([flags | path]) -> ...\n\n"
88 "_Reader allows filtering and retrieval of Journal entries.\n"
89 "Note: this is a low-level interface, and probably not what you\n"
90 "want, use systemd.journal.Reader instead.\n\n"
91 "Argument `flags` sets open flags of the journal, which can be one\n"
92 "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n"
93 "journal on local machine only; RUNTIME_ONLY opens only\n"
94 "volatile journal files; and SYSTEM_ONLY opens only\n"
95 "journal files of system services and the kernel.\n\n"
96 "Argument `path` is the directory of journal files. Note that\n"
97 "`flags` and `path` are exclusive.\n\n"
98 "_Reader implements the context manager protocol: the journal\n"
99 "will be closed when exiting the block.");
100 static int Reader_init(Reader *self, PyObject *args, PyObject *keywds)
105 static const char* const kwlist[] = {"flags", "path", NULL};
106 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iz", (char**) kwlist,
111 flags = SD_JOURNAL_LOCAL_ONLY;
114 PyErr_SetString(PyExc_ValueError, "cannot use both flags and path");
118 Py_BEGIN_ALLOW_THREADS
120 r = sd_journal_open_directory(&self->j, path, 0);
122 r = sd_journal_open(&self->j, flags);
125 return set_error(r, path, "Invalid flags or path");
129 PyDoc_STRVAR(Reader_fileno__doc__,
130 "fileno() -> int\n\n"
131 "Get a file descriptor to poll for changes in the journal.\n"
132 "This method invokes sd_journal_get_fd().\n"
133 "See man:sd_journal_get_fd(3).");
134 static PyObject* Reader_fileno(Reader *self, PyObject *args)
136 int fd = sd_journal_get_fd(self->j);
137 set_error(fd, NULL, NULL);
140 return long_FromLong(fd);
144 PyDoc_STRVAR(Reader_reliable_fd__doc__,
145 "reliable_fd() -> bool\n\n"
146 "Returns True iff the journal can be polled reliably.\n"
147 "This method invokes sd_journal_reliable_fd().\n"
148 "See man:sd_journal_reliable_fd(3).");
149 static PyObject* Reader_reliable_fd(Reader *self, PyObject *args)
151 int r = sd_journal_reliable_fd(self->j);
152 set_error(r, NULL, NULL);
155 return PyBool_FromLong(r);
159 PyDoc_STRVAR(Reader_get_events__doc__,
160 "get_events() -> int\n\n"
161 "Returns a mask of poll() events to wait for on the file\n"
162 "descriptor returned by .fileno().\n\n"
163 "See man:sd_journal_get_events(3) for further discussion.");
164 static PyObject* Reader_get_events(Reader *self, PyObject *args)
166 int r = sd_journal_get_events(self->j);
167 set_error(r, NULL, NULL);
170 return long_FromLong(r);
174 PyDoc_STRVAR(Reader_get_timeout__doc__,
175 "get_timeout() -> int or None\n\n"
176 "Returns a timeout value for usage in poll(), the time since the\n"
177 "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
179 "The return value must be converted to a relative timeout in \n"
180 "milliseconds if it is to be used as an argument for poll().\n"
181 "See man:sd_journal_get_timeout(3) for further discussion.");
182 static PyObject* Reader_get_timeout(Reader *self, PyObject *args)
187 r = sd_journal_get_timeout(self->j, &t);
188 set_error(r, NULL, NULL);
192 if (t == (uint64_t) -1)
195 assert_cc(sizeof(unsigned long long) == sizeof(t));
196 return PyLong_FromUnsignedLongLong(t);
200 PyDoc_STRVAR(Reader_get_timeout_ms__doc__,
201 "get_timeout_ms() -> int\n\n"
202 "Returns a timeout value suitable for usage in poll(), the value\n"
203 "returned by .get_timeout() converted to relative ms, or -1 if\n"
204 "no timeout is necessary.");
205 static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args)
210 r = sd_journal_get_timeout(self->j, &t);
211 set_error(r, NULL, NULL);
215 if (t == (uint64_t) -1)
216 return PyLong_FromLong(-1);
222 clock_gettime(CLOCK_MONOTONIC, &ts);
223 n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
224 msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
226 return PyLong_FromLong(msec);
231 PyDoc_STRVAR(Reader_close__doc__,
232 "close() -> None\n\n"
233 "Free resources allocated by this Reader object.\n"
234 "This method invokes sd_journal_close().\n"
235 "See man:sd_journal_close(3).");
236 static PyObject* Reader_close(Reader *self, PyObject *args)
241 sd_journal_close(self->j);
247 PyDoc_STRVAR(Reader_get_usage__doc__,
248 "get_usage() -> int\n\n"
249 "Returns the total disk space currently used by journal\n"
250 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
251 "passed when opening the journal this value will only reflect\n"
252 "the size of journal files of the local host, otherwise\n"
254 "This method invokes sd_journal_get_usage().\n"
255 "See man:sd_journal_get_usage(3).");
256 static PyObject* Reader_get_usage(Reader *self, PyObject *args)
261 r = sd_journal_get_usage(self->j, &bytes);
262 if (set_error(r, NULL, NULL))
265 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
266 return PyLong_FromUnsignedLongLong(bytes);
270 PyDoc_STRVAR(Reader___enter____doc__,
271 "__enter__() -> self\n\n"
272 "Part of the context manager protocol.\n"
274 static PyObject* Reader___enter__(PyObject *self, PyObject *args)
283 PyDoc_STRVAR(Reader___exit____doc__,
284 "__exit__(type, value, traceback) -> None\n\n"
285 "Part of the context manager protocol.\n"
286 "Closes the journal.\n");
287 static PyObject* Reader___exit__(Reader *self, PyObject *args)
291 sd_journal_close(self->j);
297 PyDoc_STRVAR(Reader_next__doc__,
298 "next([skip]) -> bool\n\n"
299 "Go to the next log entry. Optional skip value means to go to\n"
300 "the `skip`\\-th log entry.\n"
301 "Returns False if at end of file, True otherwise.");
302 static PyObject* Reader_next(Reader *self, PyObject *args)
307 if (!PyArg_ParseTuple(args, "|L:next", &skip))
311 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
315 Py_BEGIN_ALLOW_THREADS
317 r = sd_journal_next(self->j);
318 else if (skip == -1LL)
319 r = sd_journal_previous(self->j);
321 r = sd_journal_next_skip(self->j, skip);
322 else if (skip < -1LL)
323 r = sd_journal_previous_skip(self->j, -skip);
325 assert_not_reached("should not be here");
328 set_error(r, NULL, NULL);
331 return PyBool_FromLong(r);
335 static int extract(const char* msg, size_t msg_len,
336 PyObject **key, PyObject **value) {
337 PyObject *k = NULL, *v;
338 const char *delim_ptr;
340 delim_ptr = memchr(msg, '=', msg_len);
342 PyErr_SetString(PyExc_OSError,
343 "journal gave us a field without '='");
348 k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
354 v = PyBytes_FromStringAndSize(delim_ptr + 1,
355 (const char*) msg + msg_len - (delim_ptr + 1));
370 PyDoc_STRVAR(Reader_get__doc__,
371 "get(str) -> str\n\n"
372 "Return data associated with this key in current log entry.\n"
373 "Throws KeyError is the data is not available.");
374 static PyObject* Reader_get(Reader *self, PyObject *args)
385 if (!PyArg_ParseTuple(args, "s:get", &field))
388 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
390 PyErr_SetString(PyExc_KeyError, field);
392 } else if (set_error(r, NULL, "field name is not valid"))
395 r = extract(msg, msg_len, NULL, &value);
402 PyDoc_STRVAR(Reader_get_next__doc__,
403 "get_next([skip]) -> dict\n\n"
404 "Return dictionary of the next log entry. Optional skip value will\n"
405 "return the `skip`\\-th log entry. Returns an empty dict on EOF.");
406 static PyObject* Reader_get_next(Reader *self, PyObject *args)
408 PyObject _cleanup_Py_DECREF_ *tmp = NULL;
414 tmp = Reader_next(self, args);
417 if (tmp == Py_False) /* EOF */
424 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
425 PyObject _cleanup_Py_DECREF_ *key = NULL, *value = NULL;
427 r = extract(msg, msg_len, &key, &value);
431 if (PyDict_Contains(dict, key)) {
432 PyObject *cur_value = PyDict_GetItem(dict, key);
434 if (PyList_CheckExact(cur_value)) {
435 r = PyList_Append(cur_value, value);
439 PyObject _cleanup_Py_DECREF_ *tmp_list = PyList_New(0);
443 r = PyList_Append(tmp_list, cur_value);
447 r = PyList_Append(tmp_list, value);
451 r = PyDict_SetItem(dict, key, tmp_list);
456 r = PyDict_SetItem(dict, key, value);
470 PyDoc_STRVAR(Reader_get_realtime__doc__,
471 "get_realtime() -> int\n\n"
472 "Return the realtime timestamp for the current journal entry\n"
473 "in microseconds.\n\n"
474 "Wraps sd_journal_get_realtime_usec().\n"
475 "See man:sd_journal_get_realtime_usec(3).");
476 static PyObject* Reader_get_realtime(Reader *self, PyObject *args)
484 r = sd_journal_get_realtime_usec(self->j, ×tamp);
485 if (set_error(r, NULL, NULL))
488 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
489 return PyLong_FromUnsignedLongLong(timestamp);
493 PyDoc_STRVAR(Reader_get_monotonic__doc__,
494 "get_monotonic() -> (timestamp, bootid)\n\n"
495 "Return the monotonic timestamp for the current journal entry\n"
496 "as a tuple of time in microseconds and bootid.\n\n"
497 "Wraps sd_journal_get_monotonic_usec().\n"
498 "See man:sd_journal_get_monotonic_usec(3).");
499 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args)
503 PyObject *monotonic, *bootid, *tuple;
509 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
510 if (set_error(r, NULL, NULL))
513 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
514 monotonic = PyLong_FromUnsignedLongLong(timestamp);
515 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
516 #if PY_MAJOR_VERSION >= 3
517 tuple = PyStructSequence_New(&MonotonicType);
519 tuple = PyTuple_New(2);
521 if (!monotonic || !bootid || !tuple) {
522 Py_XDECREF(monotonic);
528 #if PY_MAJOR_VERSION >= 3
529 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
530 PyStructSequence_SET_ITEM(tuple, 1, bootid);
532 PyTuple_SET_ITEM(tuple, 0, monotonic);
533 PyTuple_SET_ITEM(tuple, 1, bootid);
540 PyDoc_STRVAR(Reader_get_previous__doc__,
541 "get_previous([skip]) -> dict\n\n"
542 "Return dictionary of the previous log entry. Optional skip value\n"
543 "will return the -`skip`\\-th log entry. Equivalent to get_next(-skip).");
544 static PyObject* Reader_get_previous(Reader *self, PyObject *args)
547 if (!PyArg_ParseTuple(args, "|L:get_previous", &skip))
550 return PyObject_CallMethod((PyObject *)self, (char*) "get_next",
555 PyDoc_STRVAR(Reader_add_match__doc__,
556 "add_match(match) -> None\n\n"
557 "Add a match to filter journal log entries. All matches of different\n"
558 "fields are combined with logical AND, and matches of the same field\n"
559 "are automatically combined with logical OR.\n"
560 "Match is a string of the form \"FIELD=value\".");
561 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
565 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
568 r = sd_journal_add_match(self->j, match, match_len);
569 set_error(r, NULL, "Invalid match");
577 PyDoc_STRVAR(Reader_add_disjunction__doc__,
578 "add_disjunction() -> None\n\n"
579 "Inserts a logical OR between matches added before and afterwards.");
580 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
583 r = sd_journal_add_disjunction(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 char _cleanup_free_ *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);
810 static PyObject* Reader_iter(PyObject *self)
816 static PyObject* Reader_iternext(PyObject *self)
819 Py_ssize_t dict_size;
821 dict = PyObject_CallMethod(self, (char*) "get_next", (char*) "");
822 if (PyErr_Occurred())
824 dict_size = PyDict_Size(dict);
825 if ((int64_t) dict_size > 0LL) {
829 PyErr_SetNone(PyExc_StopIteration);
835 PyDoc_STRVAR(Reader_query_unique__doc__,
836 "query_unique(field) -> a set of values\n\n"
837 "Return a set of unique values appearing in journal for the\n"
838 "given `field`. Note this does not respect any journal matches.");
839 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
845 PyObject *value_set, *key, *value;
847 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
850 Py_BEGIN_ALLOW_THREADS
851 r = sd_journal_query_unique(self->j, query);
853 if (set_error(r, NULL, "Invalid field name"))
856 value_set = PySet_New(0);
857 key = unicode_FromString(query);
859 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
860 const char *delim_ptr;
862 delim_ptr = memchr(uniq, '=', uniq_len);
863 value = PyBytes_FromStringAndSize(
865 (const char*) uniq + uniq_len - (delim_ptr + 1));
866 PySet_Add(value_set, value);
874 PyDoc_STRVAR(Reader_get_catalog__doc__,
875 "get_catalog() -> str\n\n"
876 "Retrieve a message catalog entry for the current journal entry.\n"
877 "Will throw IndexError if the entry has no MESSAGE_ID\n"
878 "and KeyError is the id is specified, but hasn't been found\n"
879 "in the catalog.\n\n"
880 "Wraps man:sd_journal_get_catalog(3).");
881 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
884 char _cleanup_free_ *msg = NULL;
889 Py_BEGIN_ALLOW_THREADS
890 r = sd_journal_get_catalog(self->j, &msg);
896 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
898 const int l = sizeof("MESSAGE_ID");
900 PyErr_Format(PyExc_KeyError, "%.*s", (int) mid_len - l,
901 (const char*) mid + l);
902 } else if (r == -ENOENT)
903 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
905 set_error(r, NULL, NULL);
907 } else if (set_error(r, NULL, NULL))
910 return unicode_FromString(msg);
914 PyDoc_STRVAR(get_catalog__doc__,
915 "get_catalog(id128) -> str\n\n"
916 "Retrieve a message catalog entry for the given id.\n"
917 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
918 static PyObject* get_catalog(PyObject *self, PyObject *args)
923 char _cleanup_free_ *msg = NULL;
928 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
931 r = sd_id128_from_string(id_, &id);
932 if (set_error(r, NULL, "Invalid id128"))
935 Py_BEGIN_ALLOW_THREADS
936 r = sd_journal_get_catalog_for_message_id(id, &msg);
938 if (set_error(r, NULL, NULL))
941 return unicode_FromString(msg);
945 PyDoc_STRVAR(data_threshold__doc__,
946 "Threshold for field size truncation in bytes.\n\n"
947 "Fields longer than this will be truncated to the threshold size.\n"
948 "Defaults to 64Kb.");
950 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
955 r = sd_journal_get_data_threshold(self->j, &cvalue);
956 if (set_error(r, NULL, NULL))
959 return long_FromSize_t(cvalue);
962 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
966 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
969 if (!long_Check(value)){
970 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
973 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
974 return set_error(r, NULL, NULL);
978 PyDoc_STRVAR(closed__doc__,
979 "True iff journal is closed");
980 static PyObject* Reader_get_closed(Reader *self, void *closure)
982 return PyBool_FromLong(self->j == NULL);
986 static PyGetSetDef Reader_getsetters[] = {
987 {(char*) "data_threshold",
988 (getter) Reader_get_data_threshold,
989 (setter) Reader_set_data_threshold,
990 (char*) data_threshold__doc__,
993 (getter) Reader_get_closed,
995 (char*) closed__doc__,
1000 static PyMethodDef Reader_methods[] = {
1001 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
1002 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
1003 {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__},
1004 {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__},
1005 {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__},
1006 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
1007 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
1008 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
1009 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
1010 {"next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
1011 {"get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
1012 {"get_next", (PyCFunction) Reader_get_next, METH_VARARGS, Reader_get_next__doc__},
1013 {"get_previous", (PyCFunction) Reader_get_previous, METH_VARARGS, Reader_get_previous__doc__},
1014 {"get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
1015 {"get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
1016 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
1017 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
1018 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
1019 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
1020 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
1021 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
1022 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
1023 {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__},
1024 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
1025 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
1026 {"get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
1027 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
1028 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
1029 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
1033 static PyTypeObject ReaderType = {
1034 PyVarObject_HEAD_INIT(NULL, 0)
1035 "_reader._Reader", /*tp_name*/
1036 sizeof(Reader), /*tp_basicsize*/
1038 (destructor)Reader_dealloc, /*tp_dealloc*/
1045 0, /*tp_as_sequence*/
1046 0, /*tp_as_mapping*/
1053 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1054 Reader__doc__, /* tp_doc */
1055 0, /* tp_traverse */
1057 0, /* tp_richcompare */
1058 0, /* tp_weaklistoffset */
1059 Reader_iter, /* tp_iter */
1060 Reader_iternext, /* tp_iternext */
1061 Reader_methods, /* tp_methods */
1063 Reader_getsetters, /* tp_getset */
1066 0, /* tp_descr_get */
1067 0, /* tp_descr_set */
1068 0, /* tp_dictoffset */
1069 (initproc) Reader_init, /* tp_init */
1071 PyType_GenericNew, /* tp_new */
1074 static PyMethodDef methods[] = {
1075 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
1076 { NULL, NULL, 0, NULL } /* Sentinel */
1079 #if PY_MAJOR_VERSION >= 3
1080 static PyModuleDef module = {
1081 PyModuleDef_HEAD_INIT,
1086 NULL, NULL, NULL, NULL
1090 #if PY_MAJOR_VERSION >= 3
1091 static bool initialized = false;
1094 #pragma GCC diagnostic push
1095 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
1098 #if PY_MAJOR_VERSION >= 3
1099 PyInit__reader(void)
1108 if (PyType_Ready(&ReaderType) < 0)
1109 #if PY_MAJOR_VERSION >= 3
1115 #if PY_MAJOR_VERSION >= 3
1116 m = PyModule_Create(&module);
1121 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1125 m = Py_InitModule3("_reader", methods, module__doc__);
1130 Py_INCREF(&ReaderType);
1131 #if PY_MAJOR_VERSION >= 3
1132 Py_INCREF(&MonotonicType);
1134 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1135 #if PY_MAJOR_VERSION >= 3
1136 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1138 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1139 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1140 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1141 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1142 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1143 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY)) {
1144 #if PY_MAJOR_VERSION >= 3
1150 #if PY_MAJOR_VERSION >= 3
1155 #pragma GCC diagnostic pop