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 if (set_error(r, NULL, NULL) < 0)
207 return PyBool_FromLong(r);
211 PyDoc_STRVAR(Reader_get_events__doc__,
212 "get_events() -> int\n\n"
213 "Returns a mask of poll() events to wait for on the file\n"
214 "descriptor returned by .fileno().\n\n"
215 "See man:sd_journal_get_events(3) for further discussion.");
216 static PyObject* Reader_get_events(Reader *self, PyObject *args) {
217 int r = sd_journal_get_events(self->j);
218 if (set_error(r, NULL, NULL) < 0)
220 return long_FromLong(r);
224 PyDoc_STRVAR(Reader_get_timeout__doc__,
225 "get_timeout() -> int or None\n\n"
226 "Returns a timeout value for usage in poll(), the time since the\n"
227 "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
229 "The return value must be converted to a relative timeout in\n"
230 "milliseconds if it is to be used as an argument for poll().\n"
231 "See man:sd_journal_get_timeout(3) for further discussion.");
232 static PyObject* Reader_get_timeout(Reader *self, PyObject *args) {
236 r = sd_journal_get_timeout(self->j, &t);
237 if (set_error(r, NULL, NULL) < 0)
240 if (t == (uint64_t) -1)
243 assert_cc(sizeof(unsigned long long) == sizeof(t));
244 return PyLong_FromUnsignedLongLong(t);
248 PyDoc_STRVAR(Reader_get_timeout_ms__doc__,
249 "get_timeout_ms() -> int\n\n"
250 "Returns a timeout value suitable for usage in poll(), the value\n"
251 "returned by .get_timeout() converted to relative ms, or -1 if\n"
252 "no timeout is necessary.");
253 static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args) {
257 r = sd_journal_get_timeout(self->j, &t);
258 if (set_error(r, NULL, NULL) < 0)
261 return absolute_timeout(t);
265 PyDoc_STRVAR(Reader_close__doc__,
266 "close() -> None\n\n"
267 "Free resources allocated by this Reader object.\n"
268 "This method invokes sd_journal_close().\n"
269 "See man:sd_journal_close(3).");
270 static PyObject* Reader_close(Reader *self, PyObject *args) {
274 sd_journal_close(self->j);
280 PyDoc_STRVAR(Reader_get_usage__doc__,
281 "get_usage() -> int\n\n"
282 "Returns the total disk space currently used by journal\n"
283 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
284 "passed when opening the journal this value will only reflect\n"
285 "the size of journal files of the local host, otherwise\n"
287 "This method invokes sd_journal_get_usage().\n"
288 "See man:sd_journal_get_usage(3).");
289 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) < 0)
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) {
314 PyDoc_STRVAR(Reader___exit____doc__,
315 "__exit__(type, value, traceback) -> None\n\n"
316 "Part of the context manager protocol.\n"
317 "Closes the journal.\n");
318 static PyObject* Reader___exit__(Reader *self, PyObject *args) {
319 return Reader_close(self, args);
323 PyDoc_STRVAR(Reader_next__doc__,
324 "next([skip]) -> bool\n\n"
325 "Go to the next log entry. Optional skip value means to go to\n"
326 "the `skip`\\-th log entry.\n"
327 "Returns False if at end of file, True otherwise.");
328 static PyObject* Reader_next(Reader *self, PyObject *args) {
332 if (!PyArg_ParseTuple(args, "|L:next", &skip))
336 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
340 Py_BEGIN_ALLOW_THREADS
342 r = sd_journal_next(self->j);
343 else if (skip == -1LL)
344 r = sd_journal_previous(self->j);
346 r = sd_journal_next_skip(self->j, skip);
347 else if (skip < -1LL)
348 r = sd_journal_previous_skip(self->j, -skip);
350 assert_not_reached("should not be here");
353 if (set_error(r, NULL, NULL) < 0)
355 return PyBool_FromLong(r);
358 PyDoc_STRVAR(Reader_previous__doc__,
359 "previous([skip]) -> bool\n\n"
360 "Go to the previous log entry. Optional skip value means to \n"
361 "go to the `skip`\\-th previous log entry.\n"
362 "Returns False if at start of file, True otherwise.");
363 static PyObject* Reader_previous(Reader *self, PyObject *args) {
365 if (!PyArg_ParseTuple(args, "|L:previous", &skip))
368 return PyObject_CallMethod((PyObject *)self, (char*) "_next",
373 static int extract(const char* msg, size_t msg_len,
374 PyObject **key, PyObject **value) {
375 PyObject *k = NULL, *v;
376 const char *delim_ptr;
378 delim_ptr = memchr(msg, '=', msg_len);
380 PyErr_SetString(PyExc_OSError,
381 "journal gave us a field without '='");
386 k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
392 v = PyBytes_FromStringAndSize(delim_ptr + 1,
393 (const char*) msg + msg_len - (delim_ptr + 1));
408 PyDoc_STRVAR(Reader_get__doc__,
409 "get(str) -> str\n\n"
410 "Return data associated with this key in current log entry.\n"
411 "Throws KeyError is the data is not available.");
412 static PyObject* Reader_get(Reader *self, PyObject *args) {
422 if (!PyArg_ParseTuple(args, "s:get", &field))
425 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
427 PyErr_SetString(PyExc_KeyError, field);
430 if (set_error(r, NULL, "field name is not valid") < 0)
433 r = extract(msg, msg_len, NULL, &value);
440 PyDoc_STRVAR(Reader_get_all__doc__,
441 "_get_all() -> dict\n\n"
442 "Return dictionary of the current log entry.");
443 static PyObject* Reader_get_all(Reader *self, PyObject *args) {
453 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
454 _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL;
456 r = extract(msg, msg_len, &key, &value);
460 if (PyDict_Contains(dict, key)) {
461 PyObject *cur_value = PyDict_GetItem(dict, key);
463 if (PyList_CheckExact(cur_value)) {
464 r = PyList_Append(cur_value, value);
468 _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0);
472 r = PyList_Append(tmp_list, cur_value);
476 r = PyList_Append(tmp_list, value);
480 r = PyDict_SetItem(dict, key, tmp_list);
485 r = PyDict_SetItem(dict, key, value);
499 PyDoc_STRVAR(Reader_get_realtime__doc__,
500 "get_realtime() -> int\n\n"
501 "Return the realtime timestamp for the current journal entry\n"
502 "in microseconds.\n\n"
503 "Wraps sd_journal_get_realtime_usec().\n"
504 "See man:sd_journal_get_realtime_usec(3).");
505 static PyObject* Reader_get_realtime(Reader *self, PyObject *args) {
512 r = sd_journal_get_realtime_usec(self->j, ×tamp);
513 if (set_error(r, NULL, NULL) < 0)
516 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
517 return PyLong_FromUnsignedLongLong(timestamp);
521 PyDoc_STRVAR(Reader_get_monotonic__doc__,
522 "get_monotonic() -> (timestamp, bootid)\n\n"
523 "Return the monotonic timestamp for the current journal entry\n"
524 "as a tuple of time in microseconds and bootid.\n\n"
525 "Wraps sd_journal_get_monotonic_usec().\n"
526 "See man:sd_journal_get_monotonic_usec(3).");
527 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args) {
530 PyObject *monotonic, *bootid, *tuple;
536 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
537 if (set_error(r, NULL, NULL) < 0)
540 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
541 monotonic = PyLong_FromUnsignedLongLong(timestamp);
542 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
543 #if PY_MAJOR_VERSION >= 3
544 tuple = PyStructSequence_New(&MonotonicType);
546 tuple = PyTuple_New(2);
548 if (!monotonic || !bootid || !tuple) {
549 Py_XDECREF(monotonic);
555 #if PY_MAJOR_VERSION >= 3
556 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
557 PyStructSequence_SET_ITEM(tuple, 1, bootid);
559 PyTuple_SET_ITEM(tuple, 0, monotonic);
560 PyTuple_SET_ITEM(tuple, 1, bootid);
566 PyDoc_STRVAR(Reader_add_match__doc__,
567 "add_match(match) -> None\n\n"
568 "Add a match to filter journal log entries. All matches of different\n"
569 "fields are combined with logical AND, and matches of the same field\n"
570 "are automatically combined with logical OR.\n"
571 "Match is a string of the form \"FIELD=value\".");
572 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds) {
575 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
578 r = sd_journal_add_match(self->j, match, match_len);
579 if (set_error(r, NULL, "Invalid match") < 0)
586 PyDoc_STRVAR(Reader_add_disjunction__doc__,
587 "add_disjunction() -> None\n\n"
588 "Inserts a logical OR 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_disjunction(Reader *self, PyObject *args) {
594 r = sd_journal_add_disjunction(self->j);
595 if (set_error(r, NULL, NULL) < 0)
601 PyDoc_STRVAR(Reader_add_conjunction__doc__,
602 "add_conjunction() -> None\n\n"
603 "Inserts a logical AND between matches added since previous\n"
604 "add_disjunction() or add_conjunction() and the next\n"
605 "add_disjunction() or add_conjunction().\n\n"
606 "See man:sd_journal_add_disjunction(3) for explanation.");
607 static PyObject* Reader_add_conjunction(Reader *self, PyObject *args) {
609 r = sd_journal_add_conjunction(self->j);
610 if (set_error(r, NULL, NULL) < 0)
616 PyDoc_STRVAR(Reader_flush_matches__doc__,
617 "flush_matches() -> None\n\n"
618 "Clear all current match filters.");
619 static PyObject* Reader_flush_matches(Reader *self, PyObject *args) {
620 sd_journal_flush_matches(self->j);
625 PyDoc_STRVAR(Reader_seek_head__doc__,
626 "seek_head() -> None\n\n"
627 "Jump to the beginning of the journal.\n"
628 "This method invokes sd_journal_seek_head().\n"
629 "See man:sd_journal_seek_head(3).");
630 static PyObject* Reader_seek_head(Reader *self, PyObject *args) {
632 Py_BEGIN_ALLOW_THREADS
633 r = sd_journal_seek_head(self->j);
635 if (set_error(r, NULL, NULL) < 0)
641 PyDoc_STRVAR(Reader_seek_tail__doc__,
642 "seek_tail() -> None\n\n"
643 "Jump to the end of the journal.\n"
644 "This method invokes sd_journal_seek_tail().\n"
645 "See man:sd_journal_seek_tail(3).");
646 static PyObject* Reader_seek_tail(Reader *self, PyObject *args) {
648 Py_BEGIN_ALLOW_THREADS
649 r = sd_journal_seek_tail(self->j);
651 if (set_error(r, NULL, NULL) < 0)
657 PyDoc_STRVAR(Reader_seek_realtime__doc__,
658 "seek_realtime(realtime) -> None\n\n"
659 "Seek to nearest matching journal entry to `realtime`. Argument\n"
660 "`realtime` in specified in seconds.");
661 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args) {
665 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
668 Py_BEGIN_ALLOW_THREADS
669 r = sd_journal_seek_realtime_usec(self->j, timestamp);
671 if (set_error(r, NULL, NULL) < 0)
677 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
678 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
679 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
680 "`monotonic` is an timestamp from boot in microseconds.\n"
681 "Argument `bootid` is a string representing which boot the\n"
682 "monotonic time is reference to. Defaults to current bootid.");
683 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args) {
689 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
693 r = sd_id128_from_string(bootid, &id);
694 if (set_error(r, NULL, "Invalid bootid") < 0)
697 Py_BEGIN_ALLOW_THREADS
698 r = sd_id128_get_boot(&id);
700 if (set_error(r, NULL, NULL) < 0)
704 Py_BEGIN_ALLOW_THREADS
705 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
707 if (set_error(r, NULL, NULL) < 0)
714 PyDoc_STRVAR(Reader_process__doc__,
715 "process() -> state change (integer)\n\n"
716 "Process events and reset the readable state of the file\n"
717 "descriptor returned by .fileno().\n\n"
718 "Will return constants: NOP if no change; APPEND if new\n"
719 "entries have been added to the end of the journal; and\n"
720 "INVALIDATE if journal files have been added or removed.\n\n"
721 "See man:sd_journal_process(3) for further discussion.");
722 static PyObject* Reader_process(Reader *self, PyObject *args) {
727 Py_BEGIN_ALLOW_THREADS
728 r = sd_journal_process(self->j);
730 if (set_error(r, NULL, NULL) < 0)
733 return long_FromLong(r);
737 PyDoc_STRVAR(Reader_wait__doc__,
738 "wait([timeout]) -> state change (integer)\n\n"
739 "Wait for a change in the journal. Argument `timeout` specifies\n"
740 "the maximum number of microseconds to wait before returning\n"
741 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
742 "then block forever.\n\n"
743 "Will return constants: NOP if no change; APPEND if new\n"
744 "entries have been added to the end of the journal; and\n"
745 "INVALIDATE if journal files have been added or removed.\n\n"
746 "See man:sd_journal_wait(3) for further discussion.");
747 static PyObject* Reader_wait(Reader *self, PyObject *args) {
751 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
754 Py_BEGIN_ALLOW_THREADS
755 r = sd_journal_wait(self->j, timeout);
757 if (set_error(r, NULL, NULL) < 0)
760 return long_FromLong(r);
764 PyDoc_STRVAR(Reader_seek_cursor__doc__,
765 "seek_cursor(cursor) -> None\n\n"
766 "Seek to journal entry by given unique reference `cursor`.");
767 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args) {
771 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
774 Py_BEGIN_ALLOW_THREADS
775 r = sd_journal_seek_cursor(self->j, cursor);
777 if (set_error(r, NULL, "Invalid cursor") < 0)
783 PyDoc_STRVAR(Reader_get_cursor__doc__,
784 "get_cursor() -> str\n\n"
785 "Return a cursor string for the current journal entry.\n\n"
786 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
787 static PyObject* Reader_get_cursor(Reader *self, PyObject *args) {
788 _cleanup_free_ char *cursor = NULL;
794 r = sd_journal_get_cursor(self->j, &cursor);
795 if (set_error(r, NULL, NULL) < 0)
798 return unicode_FromString(cursor);
802 PyDoc_STRVAR(Reader_test_cursor__doc__,
803 "test_cursor(str) -> bool\n\n"
804 "Test whether the cursor string matches current journal entry.\n\n"
805 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
806 static PyObject* Reader_test_cursor(Reader *self, PyObject *args) {
813 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
816 r = sd_journal_test_cursor(self->j, cursor);
817 if (set_error(r, NULL, NULL) < 0)
820 return PyBool_FromLong(r);
823 PyDoc_STRVAR(Reader_query_unique__doc__,
824 "query_unique(field) -> a set of values\n\n"
825 "Return a set of unique values appearing in journal for the\n"
826 "given `field`. Note this does not respect any journal matches.");
827 static PyObject* Reader_query_unique(Reader *self, PyObject *args) {
832 PyObject *value_set, *key, *value;
834 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
837 Py_BEGIN_ALLOW_THREADS
838 r = sd_journal_query_unique(self->j, query);
840 if (set_error(r, NULL, "Invalid field name") < 0)
843 value_set = PySet_New(0);
844 key = unicode_FromString(query);
846 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
847 const char *delim_ptr;
849 delim_ptr = memchr(uniq, '=', uniq_len);
850 value = PyBytes_FromStringAndSize(
852 (const char*) uniq + uniq_len - (delim_ptr + 1));
853 PySet_Add(value_set, value);
861 PyDoc_STRVAR(Reader_get_catalog__doc__,
862 "get_catalog() -> str\n\n"
863 "Retrieve a message catalog entry for the current journal entry.\n"
864 "Will throw IndexError if the entry has no MESSAGE_ID\n"
865 "and KeyError is the id is specified, but hasn't been found\n"
866 "in the catalog.\n\n"
867 "Wraps man:sd_journal_get_catalog(3).");
868 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 size_t 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);
894 if (set_error(r, NULL, NULL) < 0)
897 return unicode_FromString(msg);
901 PyDoc_STRVAR(get_catalog__doc__,
902 "get_catalog(id128) -> str\n\n"
903 "Retrieve a message catalog entry for the given id.\n"
904 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
905 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") < 0)
921 Py_BEGIN_ALLOW_THREADS
922 r = sd_journal_get_catalog_for_message_id(id, &msg);
924 if (set_error(r, NULL, NULL) < 0)
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) {
940 r = sd_journal_get_data_threshold(self->j, &cvalue);
941 if (set_error(r, NULL, NULL) < 0)
944 return long_FromSize_t(cvalue);
947 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure) {
950 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
953 if (!long_Check(value)){
954 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
957 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
958 return set_error(r, NULL, NULL);
962 PyDoc_STRVAR(closed__doc__,
963 "True iff journal is closed");
964 static PyObject* Reader_get_closed(Reader *self, void *closure) {
965 return PyBool_FromLong(self->j == NULL);
969 static PyGetSetDef Reader_getsetters[] = {
970 {(char*) "data_threshold",
971 (getter) Reader_get_data_threshold,
972 (setter) Reader_set_data_threshold,
973 (char*) data_threshold__doc__,
976 (getter) Reader_get_closed,
978 (char*) closed__doc__,
983 static PyMethodDef Reader_methods[] = {
984 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
985 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
986 {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__},
987 {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__},
988 {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__},
989 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
990 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
991 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
992 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
993 {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
994 {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__},
995 {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
996 {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__},
997 {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
998 {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
999 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
1000 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
1001 {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__},
1002 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
1003 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
1004 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
1005 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
1006 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
1007 {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__},
1008 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
1009 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
1010 {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
1011 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
1012 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
1013 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
1017 static PyTypeObject ReaderType = {
1018 PyVarObject_HEAD_INIT(NULL, 0)
1019 .tp_name = "_reader._Reader",
1020 .tp_basicsize = sizeof(Reader),
1021 .tp_dealloc = (destructor) Reader_dealloc,
1022 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1023 .tp_doc = Reader__doc__,
1024 .tp_methods = Reader_methods,
1025 .tp_getset = Reader_getsetters,
1026 .tp_init = (initproc) Reader_init,
1027 .tp_new = PyType_GenericNew,
1030 static PyMethodDef methods[] = {
1031 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
1035 #if PY_MAJOR_VERSION >= 3
1036 static PyModuleDef module = {
1037 PyModuleDef_HEAD_INIT,
1045 #if PY_MAJOR_VERSION >= 3
1046 static bool initialized = false;
1049 #pragma GCC diagnostic push
1050 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
1053 #if PY_MAJOR_VERSION >= 3
1054 PyInit__reader(void)
1063 if (PyType_Ready(&ReaderType) < 0)
1064 #if PY_MAJOR_VERSION >= 3
1070 #if PY_MAJOR_VERSION >= 3
1071 m = PyModule_Create(&module);
1076 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1080 m = Py_InitModule3("_reader", methods, module__doc__);
1085 Py_INCREF(&ReaderType);
1086 #if PY_MAJOR_VERSION >= 3
1087 Py_INCREF(&MonotonicType);
1089 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1090 #if PY_MAJOR_VERSION >= 3
1091 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1093 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1094 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1095 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1096 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1097 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1098 PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) ||
1099 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) ||
1100 PyModule_AddIntConstant(m, "CURRENT_USER", SD_JOURNAL_CURRENT_USER) ||
1101 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
1102 #if PY_MAJOR_VERSION >= 3
1108 #if PY_MAJOR_VERSION >= 3
1113 #pragma GCC diagnostic pop