1 /*-*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Steven Hiscocks, Zbigniew Jędrzejewski-Szmek
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <structmember.h>
28 #include <systemd/sd-journal.h>
40 static PyTypeObject ReaderType;
43 PyDoc_STRVAR(module__doc__,
44 "Class to reads the systemd journal similar to journalctl.");
47 #if PY_MAJOR_VERSION >= 3
48 static PyTypeObject MonotonicType;
50 PyDoc_STRVAR(MonotonicType__doc__,
51 "A tuple of (timestamp, bootid) for holding monotonic timestamps");
53 static PyStructSequence_Field MonotonicType_fields[] = {
54 {(char*) "timestamp", (char*) "Time"},
55 {(char*) "bootid", (char*) "Unique identifier of the boot"},
59 static PyStructSequence_Desc Monotonic_desc = {
60 (char*) "journal.Monotonic",
67 static int strv_converter(PyObject* obj, void *_result) {
68 char ***result = _result;
76 if (!PySequence_Check(obj))
79 len = PySequence_Length(obj);
80 *result = new0(char*, len + 1);
82 for (i = 0; i < len; i++) {
84 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
90 item = PySequence_ITEM(obj, i);
91 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
92 r = PyUnicode_FSConverter(item, &bytes);
96 s = PyBytes_AsString(bytes);
98 s = PyString_AsString(item);
119 static void Reader_dealloc(Reader* self)
121 sd_journal_close(self->j);
122 Py_TYPE(self)->tp_free((PyObject*)self);
125 PyDoc_STRVAR(Reader__doc__,
126 "_Reader([flags | path | files]) -> ...\n\n"
127 "_Reader allows filtering and retrieval of Journal entries.\n"
128 "Note: this is a low-level interface, and probably not what you\n"
129 "want, use systemd.journal.Reader instead.\n\n"
130 "Argument `flags` sets open flags of the journal, which can be one\n"
131 "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n"
132 "journal on local machine only; RUNTIME_ONLY opens only\n"
133 "volatile journal files; and SYSTEM opens journal files of\n"
134 "system services and the kernel, and CURRENT_USER opens files\n"
135 "of the current user.\n\n"
136 "Argument `path` is the directory of journal files.\n"
137 "Argument `files` is a list of files. Note that\n"
138 "`flags`, `path`, and `files` are exclusive.\n\n"
139 "_Reader implements the context manager protocol: the journal\n"
140 "will be closed when exiting the block.");
141 static int Reader_init(Reader *self, PyObject *args, PyObject *keywds)
147 static const char* const kwlist[] = {"flags", "path", "files", NULL};
148 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izO&", (char**) kwlist,
149 &flags, &path, strv_converter, &files))
152 if (!!flags + !!path + !!files > 1) {
153 PyErr_SetString(PyExc_ValueError, "cannot use more than one of flags, path, and files");
158 flags = SD_JOURNAL_LOCAL_ONLY;
160 Py_BEGIN_ALLOW_THREADS
162 r = sd_journal_open_directory(&self->j, path, 0);
164 r = sd_journal_open_files(&self->j, (const char**) files, 0);
166 r = sd_journal_open(&self->j, flags);
169 return set_error(r, path, "Invalid flags or path");
173 PyDoc_STRVAR(Reader_fileno__doc__,
174 "fileno() -> int\n\n"
175 "Get a file descriptor to poll for changes in the journal.\n"
176 "This method invokes sd_journal_get_fd().\n"
177 "See man:sd_journal_get_fd(3).");
178 static PyObject* Reader_fileno(Reader *self, PyObject *args)
180 int fd = sd_journal_get_fd(self->j);
181 set_error(fd, NULL, NULL);
184 return long_FromLong(fd);
188 PyDoc_STRVAR(Reader_reliable_fd__doc__,
189 "reliable_fd() -> bool\n\n"
190 "Returns True iff the journal can be polled reliably.\n"
191 "This method invokes sd_journal_reliable_fd().\n"
192 "See man:sd_journal_reliable_fd(3).");
193 static PyObject* Reader_reliable_fd(Reader *self, PyObject *args)
195 int r = sd_journal_reliable_fd(self->j);
196 set_error(r, NULL, NULL);
199 return PyBool_FromLong(r);
203 PyDoc_STRVAR(Reader_get_events__doc__,
204 "get_events() -> int\n\n"
205 "Returns a mask of poll() events to wait for on the file\n"
206 "descriptor returned by .fileno().\n\n"
207 "See man:sd_journal_get_events(3) for further discussion.");
208 static PyObject* Reader_get_events(Reader *self, PyObject *args)
210 int r = sd_journal_get_events(self->j);
211 set_error(r, NULL, NULL);
214 return long_FromLong(r);
218 PyDoc_STRVAR(Reader_get_timeout__doc__,
219 "get_timeout() -> int or None\n\n"
220 "Returns a timeout value for usage in poll(), the time since the\n"
221 "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
223 "The return value must be converted to a relative timeout in\n"
224 "milliseconds if it is to be used as an argument for poll().\n"
225 "See man:sd_journal_get_timeout(3) for further discussion.");
226 static PyObject* Reader_get_timeout(Reader *self, PyObject *args)
231 r = sd_journal_get_timeout(self->j, &t);
232 set_error(r, NULL, NULL);
236 if (t == (uint64_t) -1)
239 assert_cc(sizeof(unsigned long long) == sizeof(t));
240 return PyLong_FromUnsignedLongLong(t);
244 PyDoc_STRVAR(Reader_get_timeout_ms__doc__,
245 "get_timeout_ms() -> int\n\n"
246 "Returns a timeout value suitable for usage in poll(), the value\n"
247 "returned by .get_timeout() converted to relative ms, or -1 if\n"
248 "no timeout is necessary.");
249 static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args)
254 r = sd_journal_get_timeout(self->j, &t);
255 set_error(r, NULL, NULL);
259 return absolute_timeout(t);
263 PyDoc_STRVAR(Reader_close__doc__,
264 "close() -> None\n\n"
265 "Free resources allocated by this Reader object.\n"
266 "This method invokes sd_journal_close().\n"
267 "See man:sd_journal_close(3).");
268 static PyObject* Reader_close(Reader *self, PyObject *args)
273 sd_journal_close(self->j);
279 PyDoc_STRVAR(Reader_get_usage__doc__,
280 "get_usage() -> int\n\n"
281 "Returns the total disk space currently used by journal\n"
282 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
283 "passed when opening the journal this value will only reflect\n"
284 "the size of journal files of the local host, otherwise\n"
286 "This method invokes sd_journal_get_usage().\n"
287 "See man:sd_journal_get_usage(3).");
288 static PyObject* Reader_get_usage(Reader *self, PyObject *args)
293 r = sd_journal_get_usage(self->j, &bytes);
294 if (set_error(r, NULL, NULL))
297 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
298 return PyLong_FromUnsignedLongLong(bytes);
302 PyDoc_STRVAR(Reader___enter____doc__,
303 "__enter__() -> self\n\n"
304 "Part of the context manager protocol.\n"
306 static PyObject* Reader___enter__(PyObject *self, PyObject *args)
315 PyDoc_STRVAR(Reader___exit____doc__,
316 "__exit__(type, value, traceback) -> None\n\n"
317 "Part of the context manager protocol.\n"
318 "Closes the journal.\n");
319 static PyObject* Reader___exit__(Reader *self, PyObject *args)
321 return Reader_close(self, args);
325 PyDoc_STRVAR(Reader_next__doc__,
326 "next([skip]) -> bool\n\n"
327 "Go to the next log entry. Optional skip value means to go to\n"
328 "the `skip`\\-th log entry.\n"
329 "Returns False if at end of file, True otherwise.");
330 static PyObject* Reader_next(Reader *self, PyObject *args)
335 if (!PyArg_ParseTuple(args, "|L:next", &skip))
339 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
343 Py_BEGIN_ALLOW_THREADS
345 r = sd_journal_next(self->j);
346 else if (skip == -1LL)
347 r = sd_journal_previous(self->j);
349 r = sd_journal_next_skip(self->j, skip);
350 else if (skip < -1LL)
351 r = sd_journal_previous_skip(self->j, -skip);
353 assert_not_reached("should not be here");
356 set_error(r, NULL, NULL);
359 return PyBool_FromLong(r);
362 PyDoc_STRVAR(Reader_previous__doc__,
363 "previous([skip]) -> bool\n\n"
364 "Go to the previous log entry. Optional skip value means to \n"
365 "go to the `skip`\\-th previous log entry.\n"
366 "Returns False if at start of file, True otherwise.");
367 static PyObject* Reader_previous(Reader *self, PyObject *args)
370 if (!PyArg_ParseTuple(args, "|L:previous", &skip))
373 return PyObject_CallMethod((PyObject *)self, (char*) "_next",
378 static int extract(const char* msg, size_t msg_len,
379 PyObject **key, PyObject **value) {
380 PyObject *k = NULL, *v;
381 const char *delim_ptr;
383 delim_ptr = memchr(msg, '=', msg_len);
385 PyErr_SetString(PyExc_OSError,
386 "journal gave us a field without '='");
391 k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
397 v = PyBytes_FromStringAndSize(delim_ptr + 1,
398 (const char*) msg + msg_len - (delim_ptr + 1));
413 PyDoc_STRVAR(Reader_get__doc__,
414 "get(str) -> str\n\n"
415 "Return data associated with this key in current log entry.\n"
416 "Throws KeyError is the data is not available.");
417 static PyObject* Reader_get(Reader *self, PyObject *args)
428 if (!PyArg_ParseTuple(args, "s:get", &field))
431 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
433 PyErr_SetString(PyExc_KeyError, field);
435 } else if (set_error(r, NULL, "field name is not valid"))
438 r = extract(msg, msg_len, NULL, &value);
445 PyDoc_STRVAR(Reader_get_all__doc__,
446 "_get_all() -> dict\n\n"
447 "Return dictionary of the current log entry.");
448 static PyObject* Reader_get_all(Reader *self, PyObject *args)
459 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
460 _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL;
462 r = extract(msg, msg_len, &key, &value);
466 if (PyDict_Contains(dict, key)) {
467 PyObject *cur_value = PyDict_GetItem(dict, key);
469 if (PyList_CheckExact(cur_value)) {
470 r = PyList_Append(cur_value, value);
474 _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0);
478 r = PyList_Append(tmp_list, cur_value);
482 r = PyList_Append(tmp_list, value);
486 r = PyDict_SetItem(dict, key, tmp_list);
491 r = PyDict_SetItem(dict, key, value);
505 PyDoc_STRVAR(Reader_get_realtime__doc__,
506 "get_realtime() -> int\n\n"
507 "Return the realtime timestamp for the current journal entry\n"
508 "in microseconds.\n\n"
509 "Wraps sd_journal_get_realtime_usec().\n"
510 "See man:sd_journal_get_realtime_usec(3).");
511 static PyObject* Reader_get_realtime(Reader *self, PyObject *args)
519 r = sd_journal_get_realtime_usec(self->j, ×tamp);
520 if (set_error(r, NULL, NULL))
523 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
524 return PyLong_FromUnsignedLongLong(timestamp);
528 PyDoc_STRVAR(Reader_get_monotonic__doc__,
529 "get_monotonic() -> (timestamp, bootid)\n\n"
530 "Return the monotonic timestamp for the current journal entry\n"
531 "as a tuple of time in microseconds and bootid.\n\n"
532 "Wraps sd_journal_get_monotonic_usec().\n"
533 "See man:sd_journal_get_monotonic_usec(3).");
534 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args)
538 PyObject *monotonic, *bootid, *tuple;
544 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
545 if (set_error(r, NULL, NULL))
548 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
549 monotonic = PyLong_FromUnsignedLongLong(timestamp);
550 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
551 #if PY_MAJOR_VERSION >= 3
552 tuple = PyStructSequence_New(&MonotonicType);
554 tuple = PyTuple_New(2);
556 if (!monotonic || !bootid || !tuple) {
557 Py_XDECREF(monotonic);
563 #if PY_MAJOR_VERSION >= 3
564 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
565 PyStructSequence_SET_ITEM(tuple, 1, bootid);
567 PyTuple_SET_ITEM(tuple, 0, monotonic);
568 PyTuple_SET_ITEM(tuple, 1, bootid);
574 PyDoc_STRVAR(Reader_add_match__doc__,
575 "add_match(match) -> None\n\n"
576 "Add a match to filter journal log entries. All matches of different\n"
577 "fields are combined with logical AND, and matches of the same field\n"
578 "are automatically combined with logical OR.\n"
579 "Match is a string of the form \"FIELD=value\".");
580 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
584 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
587 r = sd_journal_add_match(self->j, match, match_len);
588 set_error(r, NULL, "Invalid match");
596 PyDoc_STRVAR(Reader_add_disjunction__doc__,
597 "add_disjunction() -> None\n\n"
598 "Inserts a logical OR between matches added since previous\n"
599 "add_disjunction() or add_conjunction() and the next\n"
600 "add_disjunction() or add_conjunction().\n\n"
601 "See man:sd_journal_add_disjunction(3) for explanation.");
602 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
605 r = sd_journal_add_disjunction(self->j);
606 set_error(r, NULL, NULL);
613 PyDoc_STRVAR(Reader_add_conjunction__doc__,
614 "add_conjunction() -> None\n\n"
615 "Inserts a logical AND between matches added since previous\n"
616 "add_disjunction() or add_conjunction() and the next\n"
617 "add_disjunction() or add_conjunction().\n\n"
618 "See man:sd_journal_add_disjunction(3) for explanation.");
619 static PyObject* Reader_add_conjunction(Reader *self, PyObject *args)
622 r = sd_journal_add_conjunction(self->j);
623 set_error(r, NULL, NULL);
630 PyDoc_STRVAR(Reader_flush_matches__doc__,
631 "flush_matches() -> None\n\n"
632 "Clear all current match filters.");
633 static PyObject* Reader_flush_matches(Reader *self, PyObject *args)
635 sd_journal_flush_matches(self->j);
640 PyDoc_STRVAR(Reader_seek_head__doc__,
641 "seek_head() -> None\n\n"
642 "Jump to the beginning of the journal.\n"
643 "This method invokes sd_journal_seek_head().\n"
644 "See man:sd_journal_seek_head(3).");
645 static PyObject* Reader_seek_head(Reader *self, PyObject *args)
648 Py_BEGIN_ALLOW_THREADS
649 r = sd_journal_seek_head(self->j);
651 if (set_error(r, NULL, NULL))
657 PyDoc_STRVAR(Reader_seek_tail__doc__,
658 "seek_tail() -> None\n\n"
659 "Jump to the end of the journal.\n"
660 "This method invokes sd_journal_seek_tail().\n"
661 "See man:sd_journal_seek_tail(3).");
662 static PyObject* Reader_seek_tail(Reader *self, PyObject *args)
665 Py_BEGIN_ALLOW_THREADS
666 r = sd_journal_seek_tail(self->j);
668 if (set_error(r, NULL, NULL))
674 PyDoc_STRVAR(Reader_seek_realtime__doc__,
675 "seek_realtime(realtime) -> None\n\n"
676 "Seek to nearest matching journal entry to `realtime`. Argument\n"
677 "`realtime` in specified in seconds.");
678 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args)
683 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
686 Py_BEGIN_ALLOW_THREADS
687 r = sd_journal_seek_realtime_usec(self->j, timestamp);
689 if (set_error(r, NULL, NULL))
695 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
696 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
697 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
698 "`monotonic` is an timestamp from boot in microseconds.\n"
699 "Argument `bootid` is a string representing which boot the\n"
700 "monotonic time is reference to. Defaults to current bootid.");
701 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args)
708 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
712 r = sd_id128_from_string(bootid, &id);
713 if (set_error(r, NULL, "Invalid bootid"))
716 Py_BEGIN_ALLOW_THREADS
717 r = sd_id128_get_boot(&id);
719 if (set_error(r, NULL, NULL))
723 Py_BEGIN_ALLOW_THREADS
724 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
726 if (set_error(r, NULL, NULL))
733 PyDoc_STRVAR(Reader_process__doc__,
734 "process() -> state change (integer)\n\n"
735 "Process events and reset the readable state of the file\n"
736 "descriptor returned by .fileno().\n\n"
737 "Will return constants: NOP if no change; APPEND if new\n"
738 "entries have been added to the end of the journal; and\n"
739 "INVALIDATE if journal files have been added or removed.\n\n"
740 "See man:sd_journal_process(3) for further discussion.");
741 static PyObject* Reader_process(Reader *self, PyObject *args)
747 Py_BEGIN_ALLOW_THREADS
748 r = sd_journal_process(self->j);
750 if (set_error(r, NULL, NULL) < 0)
753 return long_FromLong(r);
757 PyDoc_STRVAR(Reader_wait__doc__,
758 "wait([timeout]) -> state change (integer)\n\n"
759 "Wait for a change in the journal. Argument `timeout` specifies\n"
760 "the maximum number of microseconds to wait before returning\n"
761 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
762 "then block forever.\n\n"
763 "Will return constants: NOP if no change; APPEND if new\n"
764 "entries have been added to the end of the journal; and\n"
765 "INVALIDATE if journal files have been added or removed.\n\n"
766 "See man:sd_journal_wait(3) for further discussion.");
767 static PyObject* Reader_wait(Reader *self, PyObject *args)
772 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
775 Py_BEGIN_ALLOW_THREADS
776 r = sd_journal_wait(self->j, timeout);
778 if (set_error(r, NULL, NULL) < 0)
781 return long_FromLong(r);
785 PyDoc_STRVAR(Reader_seek_cursor__doc__,
786 "seek_cursor(cursor) -> None\n\n"
787 "Seek to journal entry by given unique reference `cursor`.");
788 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
793 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
796 Py_BEGIN_ALLOW_THREADS
797 r = sd_journal_seek_cursor(self->j, cursor);
799 if (set_error(r, NULL, "Invalid cursor"))
805 PyDoc_STRVAR(Reader_get_cursor__doc__,
806 "get_cursor() -> str\n\n"
807 "Return a cursor string for the current journal entry.\n\n"
808 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
809 static PyObject* Reader_get_cursor(Reader *self, PyObject *args)
811 _cleanup_free_ char *cursor = NULL;
817 r = sd_journal_get_cursor(self->j, &cursor);
818 if (set_error(r, NULL, NULL))
821 return unicode_FromString(cursor);
825 PyDoc_STRVAR(Reader_test_cursor__doc__,
826 "test_cursor(str) -> bool\n\n"
827 "Test whether the cursor string matches current journal entry.\n\n"
828 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
829 static PyObject* Reader_test_cursor(Reader *self, PyObject *args)
837 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
840 r = sd_journal_test_cursor(self->j, cursor);
841 set_error(r, NULL, NULL);
845 return PyBool_FromLong(r);
848 PyDoc_STRVAR(Reader_query_unique__doc__,
849 "query_unique(field) -> a set of values\n\n"
850 "Return a set of unique values appearing in journal for the\n"
851 "given `field`. Note this does not respect any journal matches.");
852 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
858 PyObject *value_set, *key, *value;
860 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
863 Py_BEGIN_ALLOW_THREADS
864 r = sd_journal_query_unique(self->j, query);
866 if (set_error(r, NULL, "Invalid field name"))
869 value_set = PySet_New(0);
870 key = unicode_FromString(query);
872 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
873 const char *delim_ptr;
875 delim_ptr = memchr(uniq, '=', uniq_len);
876 value = PyBytes_FromStringAndSize(
878 (const char*) uniq + uniq_len - (delim_ptr + 1));
879 PySet_Add(value_set, value);
887 PyDoc_STRVAR(Reader_get_catalog__doc__,
888 "get_catalog() -> str\n\n"
889 "Retrieve a message catalog entry for the current journal entry.\n"
890 "Will throw IndexError if the entry has no MESSAGE_ID\n"
891 "and KeyError is the id is specified, but hasn't been found\n"
892 "in the catalog.\n\n"
893 "Wraps man:sd_journal_get_catalog(3).");
894 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
897 _cleanup_free_ char *msg = NULL;
902 Py_BEGIN_ALLOW_THREADS
903 r = sd_journal_get_catalog(self->j, &msg);
909 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
911 const size_t l = sizeof("MESSAGE_ID");
913 PyErr_Format(PyExc_KeyError, "%.*s", (int) (mid_len - l),
914 (const char*) mid + l);
915 } else if (r == -ENOENT)
916 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
918 set_error(r, NULL, NULL);
920 } else if (set_error(r, NULL, NULL))
923 return unicode_FromString(msg);
927 PyDoc_STRVAR(get_catalog__doc__,
928 "get_catalog(id128) -> str\n\n"
929 "Retrieve a message catalog entry for the given id.\n"
930 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
931 static PyObject* get_catalog(PyObject *self, PyObject *args)
936 _cleanup_free_ char *msg = NULL;
941 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
944 r = sd_id128_from_string(id_, &id);
945 if (set_error(r, NULL, "Invalid id128"))
948 Py_BEGIN_ALLOW_THREADS
949 r = sd_journal_get_catalog_for_message_id(id, &msg);
951 if (set_error(r, NULL, NULL))
954 return unicode_FromString(msg);
958 PyDoc_STRVAR(data_threshold__doc__,
959 "Threshold for field size truncation in bytes.\n\n"
960 "Fields longer than this will be truncated to the threshold size.\n"
961 "Defaults to 64Kb.");
963 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
968 r = sd_journal_get_data_threshold(self->j, &cvalue);
969 if (set_error(r, NULL, NULL))
972 return long_FromSize_t(cvalue);
975 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
979 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
982 if (!long_Check(value)){
983 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
986 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
987 return set_error(r, NULL, NULL);
991 PyDoc_STRVAR(closed__doc__,
992 "True iff journal is closed");
993 static PyObject* Reader_get_closed(Reader *self, void *closure)
995 return PyBool_FromLong(self->j == NULL);
999 static PyGetSetDef Reader_getsetters[] = {
1000 {(char*) "data_threshold",
1001 (getter) Reader_get_data_threshold,
1002 (setter) Reader_set_data_threshold,
1003 (char*) data_threshold__doc__,
1006 (getter) Reader_get_closed,
1008 (char*) closed__doc__,
1013 static PyMethodDef Reader_methods[] = {
1014 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
1015 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
1016 {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__},
1017 {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__},
1018 {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__},
1019 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
1020 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
1021 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
1022 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
1023 {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
1024 {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__},
1025 {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
1026 {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__},
1027 {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
1028 {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
1029 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
1030 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
1031 {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__},
1032 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
1033 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
1034 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
1035 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
1036 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
1037 {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__},
1038 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
1039 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
1040 {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
1041 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
1042 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
1043 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
1047 static PyTypeObject ReaderType = {
1048 PyVarObject_HEAD_INIT(NULL, 0)
1049 .tp_name = "_reader._Reader",
1050 .tp_basicsize = sizeof(Reader),
1051 .tp_dealloc = (destructor) Reader_dealloc,
1052 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1053 .tp_doc = Reader__doc__,
1054 .tp_methods = Reader_methods,
1055 .tp_getset = Reader_getsetters,
1056 .tp_init = (initproc) Reader_init,
1057 .tp_new = PyType_GenericNew,
1060 static PyMethodDef methods[] = {
1061 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
1065 #if PY_MAJOR_VERSION >= 3
1066 static PyModuleDef module = {
1067 PyModuleDef_HEAD_INIT,
1075 #if PY_MAJOR_VERSION >= 3
1076 static bool initialized = false;
1079 #pragma GCC diagnostic push
1080 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
1083 #if PY_MAJOR_VERSION >= 3
1084 PyInit__reader(void)
1093 if (PyType_Ready(&ReaderType) < 0)
1094 #if PY_MAJOR_VERSION >= 3
1100 #if PY_MAJOR_VERSION >= 3
1101 m = PyModule_Create(&module);
1106 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1110 m = Py_InitModule3("_reader", methods, module__doc__);
1115 Py_INCREF(&ReaderType);
1116 #if PY_MAJOR_VERSION >= 3
1117 Py_INCREF(&MonotonicType);
1119 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1120 #if PY_MAJOR_VERSION >= 3
1121 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1123 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1124 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1125 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1126 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1127 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1128 PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) ||
1129 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) ||
1130 PyModule_AddIntConstant(m, "CURRENT_USER", SD_JOURNAL_CURRENT_USER) ||
1131 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
1132 #if PY_MAJOR_VERSION >= 3
1138 #if PY_MAJOR_VERSION >= 3
1143 #pragma GCC diagnostic pop