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",
68 * Convert a Python sequence object into a strv (char**), and
69 * None into a NULL pointer.
71 static int strv_converter(PyObject* obj, void *_result) {
72 char ***result = _result;
85 if (!PySequence_Check(obj))
88 len = PySequence_Length(obj);
89 *result = new0(char*, len + 1);
91 set_error(-ENOMEM, NULL, NULL);
95 for (i = 0; i < len; i++) {
97 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
103 item = PySequence_ITEM(obj, i);
104 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
105 r = PyUnicode_FSConverter(item, &bytes);
109 s = PyBytes_AsString(bytes);
111 s = PyString_AsString(item);
132 static void Reader_dealloc(Reader* self) {
133 sd_journal_close(self->j);
134 Py_TYPE(self)->tp_free((PyObject*)self);
137 PyDoc_STRVAR(Reader__doc__,
138 "_Reader([flags | path | files]) -> ...\n\n"
139 "_Reader allows filtering and retrieval of Journal entries.\n"
140 "Note: this is a low-level interface, and probably not what you\n"
141 "want, use systemd.journal.Reader instead.\n\n"
142 "Argument `flags` sets open flags of the journal, which can be one\n"
143 "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n"
144 "journal on local machine only; RUNTIME_ONLY opens only\n"
145 "volatile journal files; and SYSTEM opens journal files of\n"
146 "system services and the kernel, and CURRENT_USER opens files\n"
147 "of the current user.\n\n"
148 "Argument `path` is the directory of journal files.\n"
149 "Argument `files` is a list of files. Note that\n"
150 "`flags`, `path`, and `files` are exclusive.\n\n"
151 "_Reader implements the context manager protocol: the journal\n"
152 "will be closed when exiting the block.");
153 static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) {
158 static const char* const kwlist[] = {"flags", "path", "files", NULL};
159 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izO&:__init__", (char**) kwlist,
160 &flags, &path, strv_converter, &files))
163 if (!!flags + !!path + !!files > 1) {
164 PyErr_SetString(PyExc_ValueError, "cannot use more than one of flags, path, and files");
169 flags = SD_JOURNAL_LOCAL_ONLY;
171 Py_BEGIN_ALLOW_THREADS
173 r = sd_journal_open_directory(&self->j, path, 0);
175 r = sd_journal_open_files(&self->j, (const char**) files, 0);
177 r = sd_journal_open(&self->j, flags);
180 return set_error(r, path, "Invalid flags or path");
184 PyDoc_STRVAR(Reader_fileno__doc__,
185 "fileno() -> int\n\n"
186 "Get a file descriptor to poll for changes in the journal.\n"
187 "This method invokes sd_journal_get_fd().\n"
188 "See man:sd_journal_get_fd(3).");
189 static PyObject* Reader_fileno(Reader *self, PyObject *args) {
190 int fd = sd_journal_get_fd(self->j);
191 set_error(fd, NULL, NULL);
194 return long_FromLong(fd);
198 PyDoc_STRVAR(Reader_reliable_fd__doc__,
199 "reliable_fd() -> bool\n\n"
200 "Returns True iff the journal can be polled reliably.\n"
201 "This method invokes sd_journal_reliable_fd().\n"
202 "See man:sd_journal_reliable_fd(3).");
203 static PyObject* Reader_reliable_fd(Reader *self, PyObject *args) {
204 int r = sd_journal_reliable_fd(self->j);
205 set_error(r, NULL, NULL);
208 return PyBool_FromLong(r);
212 PyDoc_STRVAR(Reader_get_events__doc__,
213 "get_events() -> int\n\n"
214 "Returns a mask of poll() events to wait for on the file\n"
215 "descriptor returned by .fileno().\n\n"
216 "See man:sd_journal_get_events(3) for further discussion.");
217 static PyObject* Reader_get_events(Reader *self, PyObject *args) {
218 int r = sd_journal_get_events(self->j);
219 set_error(r, NULL, NULL);
222 return long_FromLong(r);
226 PyDoc_STRVAR(Reader_get_timeout__doc__,
227 "get_timeout() -> int or None\n\n"
228 "Returns a timeout value for usage in poll(), the time since the\n"
229 "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
231 "The return value must be converted to a relative timeout in\n"
232 "milliseconds if it is to be used as an argument for poll().\n"
233 "See man:sd_journal_get_timeout(3) for further discussion.");
234 static PyObject* Reader_get_timeout(Reader *self, PyObject *args) {
238 r = sd_journal_get_timeout(self->j, &t);
239 set_error(r, NULL, NULL);
243 if (t == (uint64_t) -1)
246 assert_cc(sizeof(unsigned long long) == sizeof(t));
247 return PyLong_FromUnsignedLongLong(t);
251 PyDoc_STRVAR(Reader_get_timeout_ms__doc__,
252 "get_timeout_ms() -> int\n\n"
253 "Returns a timeout value suitable for usage in poll(), the value\n"
254 "returned by .get_timeout() converted to relative ms, or -1 if\n"
255 "no timeout is necessary.");
256 static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args) {
260 r = sd_journal_get_timeout(self->j, &t);
261 set_error(r, NULL, NULL);
265 return absolute_timeout(t);
269 PyDoc_STRVAR(Reader_close__doc__,
270 "close() -> None\n\n"
271 "Free resources allocated by this Reader object.\n"
272 "This method invokes sd_journal_close().\n"
273 "See man:sd_journal_close(3).");
274 static PyObject* Reader_close(Reader *self, PyObject *args) {
278 sd_journal_close(self->j);
284 PyDoc_STRVAR(Reader_get_usage__doc__,
285 "get_usage() -> int\n\n"
286 "Returns the total disk space currently used by journal\n"
287 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
288 "passed when opening the journal this value will only reflect\n"
289 "the size of journal files of the local host, otherwise\n"
291 "This method invokes sd_journal_get_usage().\n"
292 "See man:sd_journal_get_usage(3).");
293 static PyObject* Reader_get_usage(Reader *self, PyObject *args) {
297 r = sd_journal_get_usage(self->j, &bytes);
298 if (set_error(r, NULL, NULL))
301 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
302 return PyLong_FromUnsignedLongLong(bytes);
306 PyDoc_STRVAR(Reader___enter____doc__,
307 "__enter__() -> self\n\n"
308 "Part of the context manager protocol.\n"
310 static PyObject* Reader___enter__(PyObject *self, PyObject *args) {
318 PyDoc_STRVAR(Reader___exit____doc__,
319 "__exit__(type, value, traceback) -> None\n\n"
320 "Part of the context manager protocol.\n"
321 "Closes the journal.\n");
322 static PyObject* Reader___exit__(Reader *self, PyObject *args) {
323 return Reader_close(self, args);
327 PyDoc_STRVAR(Reader_next__doc__,
328 "next([skip]) -> bool\n\n"
329 "Go to the next log entry. Optional skip value means to go to\n"
330 "the `skip`\\-th log entry.\n"
331 "Returns False if at end of file, True otherwise.");
332 static PyObject* Reader_next(Reader *self, PyObject *args) {
336 if (!PyArg_ParseTuple(args, "|L:next", &skip))
340 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
344 Py_BEGIN_ALLOW_THREADS
346 r = sd_journal_next(self->j);
347 else if (skip == -1LL)
348 r = sd_journal_previous(self->j);
350 r = sd_journal_next_skip(self->j, skip);
351 else if (skip < -1LL)
352 r = sd_journal_previous_skip(self->j, -skip);
354 assert_not_reached("should not be here");
357 set_error(r, NULL, NULL);
360 return PyBool_FromLong(r);
363 PyDoc_STRVAR(Reader_previous__doc__,
364 "previous([skip]) -> bool\n\n"
365 "Go to the previous log entry. Optional skip value means to \n"
366 "go to the `skip`\\-th previous log entry.\n"
367 "Returns False if at start of file, True otherwise.");
368 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) {
427 if (!PyArg_ParseTuple(args, "s:get", &field))
430 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
432 PyErr_SetString(PyExc_KeyError, field);
434 } else if (set_error(r, NULL, "field name is not valid"))
437 r = extract(msg, msg_len, NULL, &value);
444 PyDoc_STRVAR(Reader_get_all__doc__,
445 "_get_all() -> dict\n\n"
446 "Return dictionary of the current log entry.");
447 static PyObject* Reader_get_all(Reader *self, PyObject *args) {
457 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
458 _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL;
460 r = extract(msg, msg_len, &key, &value);
464 if (PyDict_Contains(dict, key)) {
465 PyObject *cur_value = PyDict_GetItem(dict, key);
467 if (PyList_CheckExact(cur_value)) {
468 r = PyList_Append(cur_value, value);
472 _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0);
476 r = PyList_Append(tmp_list, cur_value);
480 r = PyList_Append(tmp_list, value);
484 r = PyDict_SetItem(dict, key, tmp_list);
489 r = PyDict_SetItem(dict, key, value);
503 PyDoc_STRVAR(Reader_get_realtime__doc__,
504 "get_realtime() -> int\n\n"
505 "Return the realtime timestamp for the current journal entry\n"
506 "in microseconds.\n\n"
507 "Wraps sd_journal_get_realtime_usec().\n"
508 "See man:sd_journal_get_realtime_usec(3).");
509 static PyObject* Reader_get_realtime(Reader *self, PyObject *args) {
516 r = sd_journal_get_realtime_usec(self->j, ×tamp);
517 if (set_error(r, NULL, NULL))
520 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
521 return PyLong_FromUnsignedLongLong(timestamp);
525 PyDoc_STRVAR(Reader_get_monotonic__doc__,
526 "get_monotonic() -> (timestamp, bootid)\n\n"
527 "Return the monotonic timestamp for the current journal entry\n"
528 "as a tuple of time in microseconds and bootid.\n\n"
529 "Wraps sd_journal_get_monotonic_usec().\n"
530 "See man:sd_journal_get_monotonic_usec(3).");
531 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args) {
534 PyObject *monotonic, *bootid, *tuple;
540 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
541 if (set_error(r, NULL, NULL))
544 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
545 monotonic = PyLong_FromUnsignedLongLong(timestamp);
546 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
547 #if PY_MAJOR_VERSION >= 3
548 tuple = PyStructSequence_New(&MonotonicType);
550 tuple = PyTuple_New(2);
552 if (!monotonic || !bootid || !tuple) {
553 Py_XDECREF(monotonic);
559 #if PY_MAJOR_VERSION >= 3
560 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
561 PyStructSequence_SET_ITEM(tuple, 1, bootid);
563 PyTuple_SET_ITEM(tuple, 0, monotonic);
564 PyTuple_SET_ITEM(tuple, 1, bootid);
570 PyDoc_STRVAR(Reader_add_match__doc__,
571 "add_match(match) -> None\n\n"
572 "Add a match to filter journal log entries. All matches of different\n"
573 "fields are combined with logical AND, and matches of the same field\n"
574 "are automatically combined with logical OR.\n"
575 "Match is a string of the form \"FIELD=value\".");
576 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds) {
579 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
582 r = sd_journal_add_match(self->j, match, match_len);
583 set_error(r, NULL, "Invalid match");
591 PyDoc_STRVAR(Reader_add_disjunction__doc__,
592 "add_disjunction() -> None\n\n"
593 "Inserts a logical OR between matches added since previous\n"
594 "add_disjunction() or add_conjunction() and the next\n"
595 "add_disjunction() or add_conjunction().\n\n"
596 "See man:sd_journal_add_disjunction(3) for explanation.");
597 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args) {
599 r = sd_journal_add_disjunction(self->j);
600 set_error(r, NULL, NULL);
607 PyDoc_STRVAR(Reader_add_conjunction__doc__,
608 "add_conjunction() -> None\n\n"
609 "Inserts a logical AND between matches added since previous\n"
610 "add_disjunction() or add_conjunction() and the next\n"
611 "add_disjunction() or add_conjunction().\n\n"
612 "See man:sd_journal_add_disjunction(3) for explanation.");
613 static PyObject* Reader_add_conjunction(Reader *self, PyObject *args) {
615 r = sd_journal_add_conjunction(self->j);
616 set_error(r, NULL, NULL);
623 PyDoc_STRVAR(Reader_flush_matches__doc__,
624 "flush_matches() -> None\n\n"
625 "Clear all current match filters.");
626 static PyObject* Reader_flush_matches(Reader *self, PyObject *args) {
627 sd_journal_flush_matches(self->j);
632 PyDoc_STRVAR(Reader_seek_head__doc__,
633 "seek_head() -> None\n\n"
634 "Jump to the beginning of the journal.\n"
635 "This method invokes sd_journal_seek_head().\n"
636 "See man:sd_journal_seek_head(3).");
637 static PyObject* Reader_seek_head(Reader *self, PyObject *args) {
639 Py_BEGIN_ALLOW_THREADS
640 r = sd_journal_seek_head(self->j);
642 if (set_error(r, NULL, NULL))
648 PyDoc_STRVAR(Reader_seek_tail__doc__,
649 "seek_tail() -> None\n\n"
650 "Jump to the end of the journal.\n"
651 "This method invokes sd_journal_seek_tail().\n"
652 "See man:sd_journal_seek_tail(3).");
653 static PyObject* Reader_seek_tail(Reader *self, PyObject *args) {
655 Py_BEGIN_ALLOW_THREADS
656 r = sd_journal_seek_tail(self->j);
658 if (set_error(r, NULL, NULL))
664 PyDoc_STRVAR(Reader_seek_realtime__doc__,
665 "seek_realtime(realtime) -> None\n\n"
666 "Seek to nearest matching journal entry to `realtime`. Argument\n"
667 "`realtime` in specified in seconds.");
668 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args) {
672 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
675 Py_BEGIN_ALLOW_THREADS
676 r = sd_journal_seek_realtime_usec(self->j, timestamp);
678 if (set_error(r, NULL, NULL))
684 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
685 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
686 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
687 "`monotonic` is an timestamp from boot in microseconds.\n"
688 "Argument `bootid` is a string representing which boot the\n"
689 "monotonic time is reference to. Defaults to current bootid.");
690 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args) {
696 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
700 r = sd_id128_from_string(bootid, &id);
701 if (set_error(r, NULL, "Invalid bootid"))
704 Py_BEGIN_ALLOW_THREADS
705 r = sd_id128_get_boot(&id);
707 if (set_error(r, NULL, NULL))
711 Py_BEGIN_ALLOW_THREADS
712 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
714 if (set_error(r, NULL, NULL))
721 PyDoc_STRVAR(Reader_process__doc__,
722 "process() -> state change (integer)\n\n"
723 "Process events and reset the readable state of the file\n"
724 "descriptor returned by .fileno().\n\n"
725 "Will return constants: NOP if no change; APPEND if new\n"
726 "entries have been added to the end of the journal; and\n"
727 "INVALIDATE if journal files have been added or removed.\n\n"
728 "See man:sd_journal_process(3) for further discussion.");
729 static PyObject* Reader_process(Reader *self, PyObject *args) {
734 Py_BEGIN_ALLOW_THREADS
735 r = sd_journal_process(self->j);
737 if (set_error(r, NULL, NULL) < 0)
740 return long_FromLong(r);
744 PyDoc_STRVAR(Reader_wait__doc__,
745 "wait([timeout]) -> state change (integer)\n\n"
746 "Wait for a change in the journal. Argument `timeout` specifies\n"
747 "the maximum number of microseconds to wait before returning\n"
748 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
749 "then block forever.\n\n"
750 "Will return constants: NOP if no change; APPEND if new\n"
751 "entries have been added to the end of the journal; and\n"
752 "INVALIDATE if journal files have been added or removed.\n\n"
753 "See man:sd_journal_wait(3) for further discussion.");
754 static PyObject* Reader_wait(Reader *self, PyObject *args) {
758 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
761 Py_BEGIN_ALLOW_THREADS
762 r = sd_journal_wait(self->j, timeout);
764 if (set_error(r, NULL, NULL) < 0)
767 return long_FromLong(r);
771 PyDoc_STRVAR(Reader_seek_cursor__doc__,
772 "seek_cursor(cursor) -> None\n\n"
773 "Seek to journal entry by given unique reference `cursor`.");
774 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args) {
778 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
781 Py_BEGIN_ALLOW_THREADS
782 r = sd_journal_seek_cursor(self->j, cursor);
784 if (set_error(r, NULL, "Invalid cursor"))
790 PyDoc_STRVAR(Reader_get_cursor__doc__,
791 "get_cursor() -> str\n\n"
792 "Return a cursor string for the current journal entry.\n\n"
793 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
794 static PyObject* Reader_get_cursor(Reader *self, PyObject *args) {
795 _cleanup_free_ char *cursor = NULL;
801 r = sd_journal_get_cursor(self->j, &cursor);
802 if (set_error(r, NULL, NULL))
805 return unicode_FromString(cursor);
809 PyDoc_STRVAR(Reader_test_cursor__doc__,
810 "test_cursor(str) -> bool\n\n"
811 "Test whether the cursor string matches current journal entry.\n\n"
812 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
813 static PyObject* Reader_test_cursor(Reader *self, PyObject *args) {
820 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
823 r = sd_journal_test_cursor(self->j, cursor);
824 set_error(r, NULL, NULL);
828 return PyBool_FromLong(r);
831 PyDoc_STRVAR(Reader_query_unique__doc__,
832 "query_unique(field) -> a set of values\n\n"
833 "Return a set of unique values appearing in journal for the\n"
834 "given `field`. Note this does not respect any journal matches.");
835 static PyObject* Reader_query_unique(Reader *self, PyObject *args) {
840 PyObject *value_set, *key, *value;
842 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
845 Py_BEGIN_ALLOW_THREADS
846 r = sd_journal_query_unique(self->j, query);
848 if (set_error(r, NULL, "Invalid field name"))
851 value_set = PySet_New(0);
852 key = unicode_FromString(query);
854 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
855 const char *delim_ptr;
857 delim_ptr = memchr(uniq, '=', uniq_len);
858 value = PyBytes_FromStringAndSize(
860 (const char*) uniq + uniq_len - (delim_ptr + 1));
861 PySet_Add(value_set, value);
869 PyDoc_STRVAR(Reader_get_catalog__doc__,
870 "get_catalog() -> str\n\n"
871 "Retrieve a message catalog entry for the current journal entry.\n"
872 "Will throw IndexError if the entry has no MESSAGE_ID\n"
873 "and KeyError is the id is specified, but hasn't been found\n"
874 "in the catalog.\n\n"
875 "Wraps man:sd_journal_get_catalog(3).");
876 static PyObject* Reader_get_catalog(Reader *self, PyObject *args) {
878 _cleanup_free_ char *msg = NULL;
883 Py_BEGIN_ALLOW_THREADS
884 r = sd_journal_get_catalog(self->j, &msg);
890 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
892 const size_t l = sizeof("MESSAGE_ID");
894 PyErr_Format(PyExc_KeyError, "%.*s", (int) (mid_len - l),
895 (const char*) mid + l);
896 } else if (r == -ENOENT)
897 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
899 set_error(r, NULL, NULL);
901 } else if (set_error(r, NULL, NULL))
904 return unicode_FromString(msg);
908 PyDoc_STRVAR(get_catalog__doc__,
909 "get_catalog(id128) -> str\n\n"
910 "Retrieve a message catalog entry for the given id.\n"
911 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
912 static PyObject* get_catalog(PyObject *self, PyObject *args) {
916 _cleanup_free_ char *msg = NULL;
921 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
924 r = sd_id128_from_string(id_, &id);
925 if (set_error(r, NULL, "Invalid id128"))
928 Py_BEGIN_ALLOW_THREADS
929 r = sd_journal_get_catalog_for_message_id(id, &msg);
931 if (set_error(r, NULL, NULL))
934 return unicode_FromString(msg);
938 PyDoc_STRVAR(data_threshold__doc__,
939 "Threshold for field size truncation in bytes.\n\n"
940 "Fields longer than this will be truncated to the threshold size.\n"
941 "Defaults to 64Kb.");
943 static PyObject* Reader_get_data_threshold(Reader *self, void *closure) {
947 r = sd_journal_get_data_threshold(self->j, &cvalue);
948 if (set_error(r, NULL, NULL))
951 return long_FromSize_t(cvalue);
954 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure) {
957 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
960 if (!long_Check(value)){
961 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
964 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
965 return set_error(r, NULL, NULL);
969 PyDoc_STRVAR(closed__doc__,
970 "True iff journal is closed");
971 static PyObject* Reader_get_closed(Reader *self, void *closure) {
972 return PyBool_FromLong(self->j == NULL);
976 static PyGetSetDef Reader_getsetters[] = {
977 {(char*) "data_threshold",
978 (getter) Reader_get_data_threshold,
979 (setter) Reader_set_data_threshold,
980 (char*) data_threshold__doc__,
983 (getter) Reader_get_closed,
985 (char*) closed__doc__,
990 static PyMethodDef Reader_methods[] = {
991 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
992 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
993 {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__},
994 {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__},
995 {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__},
996 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
997 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
998 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
999 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
1000 {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
1001 {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__},
1002 {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
1003 {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__},
1004 {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
1005 {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
1006 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
1007 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
1008 {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__},
1009 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
1010 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
1011 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
1012 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
1013 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
1014 {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__},
1015 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
1016 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
1017 {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
1018 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
1019 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
1020 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
1024 static PyTypeObject ReaderType = {
1025 PyVarObject_HEAD_INIT(NULL, 0)
1026 .tp_name = "_reader._Reader",
1027 .tp_basicsize = sizeof(Reader),
1028 .tp_dealloc = (destructor) Reader_dealloc,
1029 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1030 .tp_doc = Reader__doc__,
1031 .tp_methods = Reader_methods,
1032 .tp_getset = Reader_getsetters,
1033 .tp_init = (initproc) Reader_init,
1034 .tp_new = PyType_GenericNew,
1037 static PyMethodDef methods[] = {
1038 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
1042 #if PY_MAJOR_VERSION >= 3
1043 static PyModuleDef module = {
1044 PyModuleDef_HEAD_INIT,
1052 #if PY_MAJOR_VERSION >= 3
1053 static bool initialized = false;
1056 #pragma GCC diagnostic push
1057 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
1060 #if PY_MAJOR_VERSION >= 3
1061 PyInit__reader(void)
1070 if (PyType_Ready(&ReaderType) < 0)
1071 #if PY_MAJOR_VERSION >= 3
1077 #if PY_MAJOR_VERSION >= 3
1078 m = PyModule_Create(&module);
1083 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1087 m = Py_InitModule3("_reader", methods, module__doc__);
1092 Py_INCREF(&ReaderType);
1093 #if PY_MAJOR_VERSION >= 3
1094 Py_INCREF(&MonotonicType);
1096 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1097 #if PY_MAJOR_VERSION >= 3
1098 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1100 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1101 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1102 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1103 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1104 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1105 PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) ||
1106 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) ||
1107 PyModule_AddIntConstant(m, "CURRENT_USER", SD_JOURNAL_CURRENT_USER) ||
1108 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
1109 #if PY_MAJOR_VERSION >= 3
1115 #if PY_MAJOR_VERSION >= 3
1120 #pragma GCC diagnostic pop