2013-02-20 07:22:03 +04:00
/*-*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
2013-02-16 21:32:05 +04:00
/***
This file is part of systemd .
Copyright 2013 Steven Hiscocks , Zbigniew Jędrzejewski - Szmek
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2013-02-08 23:41:21 +04:00
# include <Python.h>
# include <structmember.h>
# include <datetime.h>
2013-04-15 02:37:03 +04:00
# include <time.h>
2013-02-22 16:33:06 +04:00
# include <stdio.h>
# include <systemd/sd-journal.h>
# include "pyutil.h"
# include "macro.h"
# include "util.h"
2013-07-17 20:50:13 +04:00
# include "strv.h"
2013-05-09 05:08:14 +04:00
# include "build.h"
2013-02-08 23:41:21 +04:00
typedef struct {
PyObject_HEAD
sd_journal * j ;
2013-03-01 04:32:31 +04:00
} Reader ;
static PyTypeObject ReaderType ;
2013-02-08 23:41:21 +04:00
2013-03-16 02:10:51 +04:00
PyDoc_STRVAR ( module__doc__ ,
" Class to reads the systemd journal similar to journalctl. " ) ;
2013-02-23 04:11:36 +04:00
# if PY_MAJOR_VERSION >= 3
static PyTypeObject MonotonicType ;
PyDoc_STRVAR ( MonotonicType__doc__ ,
" A tuple of (timestamp, bootid) for holding monotonic timestamps " ) ;
static PyStructSequence_Field MonotonicType_fields [ ] = {
{ ( char * ) " timestamp " , ( char * ) " Time " } ,
{ ( char * ) " bootid " , ( char * ) " Unique identifier of the boot " } ,
2013-03-25 03:59:00 +04:00
{ } /* Sentinel */
2013-02-23 04:11:36 +04:00
} ;
static PyStructSequence_Desc Monotonic_desc = {
( char * ) " journal.Monotonic " ,
MonotonicType__doc__ ,
MonotonicType_fields ,
2 ,
} ;
# endif
2013-08-15 20:50:32 +04:00
/**
* Convert a Python sequence object into a strv ( char * * ) , and
* None into a NULL pointer .
*/
2013-07-17 20:50:13 +04:00
static int strv_converter ( PyObject * obj , void * _result ) {
char * * * result = _result ;
Py_ssize_t i , len ;
assert ( result ) ;
if ( ! obj )
2013-08-15 20:51:20 +04:00
return 0 ;
2013-07-17 20:50:13 +04:00
2013-08-15 20:50:32 +04:00
if ( obj = = Py_None ) {
* result = NULL ;
return 1 ;
}
2013-07-17 20:50:13 +04:00
if ( ! PySequence_Check ( obj ) )
return 0 ;
len = PySequence_Length ( obj ) ;
* result = new0 ( char * , len + 1 ) ;
2013-08-15 20:51:20 +04:00
if ( ! * result ) {
set_error ( - ENOMEM , NULL , NULL ) ;
return 0 ;
}
2013-07-17 20:50:13 +04:00
for ( i = 0 ; i < len ; i + + ) {
PyObject * item ;
# if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
int r ;
PyObject * bytes ;
# endif
char * s , * s2 ;
item = PySequence_ITEM ( obj , i ) ;
# if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
r = PyUnicode_FSConverter ( item , & bytes ) ;
if ( r = = 0 )
goto cleanup ;
s = PyBytes_AsString ( bytes ) ;
# else
s = PyString_AsString ( item ) ;
# endif
if ( ! s )
goto cleanup ;
s2 = strdup ( s ) ;
if ( ! s2 )
log_oom ( ) ;
( * result ) [ i ] = s2 ;
}
return 1 ;
cleanup :
strv_free ( * result ) ;
* result = NULL ;
return 0 ;
}
2013-03-16 02:10:51 +04:00
2013-12-04 01:27:45 +04:00
static void Reader_dealloc ( Reader * self ) {
2013-02-08 23:41:21 +04:00
sd_journal_close ( self - > j ) ;
Py_TYPE ( self ) - > tp_free ( ( PyObject * ) self ) ;
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader__doc__ ,
2013-07-17 20:50:13 +04:00
" _Reader([flags | path | files]) -> ... \n \n "
2013-03-21 03:12:27 +04:00
" _Reader allows filtering and retrieval of Journal entries. \n "
2013-03-07 20:28:44 +04:00
" Note: this is a low-level interface, and probably not what you \n "
" want, use systemd.journal.Reader instead. \n \n "
2013-02-20 07:22:03 +04:00
" Argument `flags` sets open flags of the journal, which can be one \n "
" of, or ORed combination of constants: LOCAL_ONLY (default) opens \n "
" journal on local machine only; RUNTIME_ONLY opens only \n "
2013-07-17 20:50:13 +04:00
" volatile journal files; and SYSTEM opens journal files of \n "
" system services and the kernel, and CURRENT_USER opens files \n "
" of the current user. \n \n "
" Argument `path` is the directory of journal files. \n "
" Argument `files` is a list of files. Note that \n "
" `flags`, `path`, and `files` are exclusive. \n \n "
2013-03-21 03:12:27 +04:00
" _Reader implements the context manager protocol: the journal \n "
" will be closed when exiting the block. " ) ;
2013-12-04 01:27:45 +04:00
static int Reader_init ( Reader * self , PyObject * args , PyObject * keywds ) {
2013-03-07 20:28:44 +04:00
int flags = 0 , r ;
2013-02-20 06:58:54 +04:00
char * path = NULL ;
2013-07-17 20:50:13 +04:00
char * * files = NULL ;
2013-02-08 23:41:21 +04:00
2013-07-17 20:50:13 +04:00
static const char * const kwlist [ ] = { " flags " , " path " , " files " , NULL } ;
2013-08-15 20:51:20 +04:00
if ( ! PyArg_ParseTupleAndKeywords ( args , keywds , " |izO&:__init__ " , ( char * * ) kwlist ,
2013-07-17 20:50:13 +04:00
& flags , & path , strv_converter , & files ) )
2013-03-07 20:28:44 +04:00
return - 1 ;
2013-07-17 20:50:13 +04:00
if ( ! ! flags + ! ! path + ! ! files > 1 ) {
PyErr_SetString ( PyExc_ValueError , " cannot use more than one of flags, path, and files " ) ;
return - 1 ;
}
2013-03-07 20:28:44 +04:00
if ( ! flags )
flags = SD_JOURNAL_LOCAL_ONLY ;
2013-02-08 23:41:21 +04:00
2013-02-16 21:29:57 +04:00
Py_BEGIN_ALLOW_THREADS
2013-02-20 07:11:02 +04:00
if ( path )
2013-02-08 23:41:21 +04:00
r = sd_journal_open_directory ( & self - > j , path , 0 ) ;
2013-07-17 20:50:13 +04:00
else if ( files )
r = sd_journal_open_files ( & self - > j , ( const char * * ) files , 0 ) ;
2013-02-20 07:11:02 +04:00
else
2013-02-08 23:41:21 +04:00
r = sd_journal_open ( & self - > j , flags ) ;
2013-02-16 21:29:57 +04:00
Py_END_ALLOW_THREADS
2013-02-08 23:41:21 +04:00
2013-02-17 20:26:10 +04:00
return set_error ( r , path , " Invalid flags or path " ) ;
2013-02-08 23:41:21 +04:00
}
2013-03-16 02:10:51 +04:00
2013-03-07 09:35:28 +04:00
PyDoc_STRVAR ( Reader_fileno__doc__ ,
" fileno() -> int \n \n "
" Get a file descriptor to poll for changes in the journal. \n "
" This method invokes sd_journal_get_fd(). \n "
" See man:sd_journal_get_fd(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_fileno ( Reader * self , PyObject * args ) {
2013-04-15 02:37:03 +04:00
int fd = sd_journal_get_fd ( self - > j ) ;
2013-03-21 02:30:10 +04:00
set_error ( fd , NULL , NULL ) ;
if ( fd < 0 )
2013-03-07 09:35:28 +04:00
return NULL ;
2013-03-21 02:30:10 +04:00
return long_FromLong ( fd ) ;
2013-03-07 09:35:28 +04:00
}
2013-03-16 02:10:51 +04:00
2013-03-07 09:35:28 +04:00
PyDoc_STRVAR ( Reader_reliable_fd__doc__ ,
" reliable_fd() -> bool \n \n "
" Returns True iff the journal can be polled reliably. \n "
" This method invokes sd_journal_reliable_fd(). \n "
" See man:sd_journal_reliable_fd(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_reliable_fd ( Reader * self , PyObject * args ) {
2013-04-15 02:37:03 +04:00
int r = sd_journal_reliable_fd ( self - > j ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-03-07 09:35:28 +04:00
return NULL ;
return PyBool_FromLong ( r ) ;
}
2013-03-16 02:10:51 +04:00
2013-04-15 02:37:03 +04:00
PyDoc_STRVAR ( Reader_get_events__doc__ ,
" get_events() -> int \n \n "
" Returns a mask of poll() events to wait for on the file \n "
" descriptor returned by .fileno(). \n \n "
" See man:sd_journal_get_events(3) for further discussion. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_events ( Reader * self , PyObject * args ) {
2013-04-15 02:37:03 +04:00
int r = sd_journal_get_events ( self - > j ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-04-15 02:37:03 +04:00
return NULL ;
return long_FromLong ( r ) ;
}
PyDoc_STRVAR ( Reader_get_timeout__doc__ ,
" get_timeout() -> int or None \n \n "
" Returns a timeout value for usage in poll(), the time since the \n "
" epoch of clock_gettime(2) in microseconds, or None if no timeout \n "
" is necessary. \n \n "
2013-05-10 02:10:30 +04:00
" The return value must be converted to a relative timeout in \n "
2013-04-15 02:37:03 +04:00
" milliseconds if it is to be used as an argument for poll(). \n "
" See man:sd_journal_get_timeout(3) for further discussion. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_timeout ( Reader * self , PyObject * args ) {
2013-04-15 02:37:03 +04:00
int r ;
uint64_t t ;
r = sd_journal_get_timeout ( self - > j , & t ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-04-15 02:37:03 +04:00
return NULL ;
if ( t = = ( uint64_t ) - 1 )
Py_RETURN_NONE ;
assert_cc ( sizeof ( unsigned long long ) = = sizeof ( t ) ) ;
return PyLong_FromUnsignedLongLong ( t ) ;
}
PyDoc_STRVAR ( Reader_get_timeout_ms__doc__ ,
" get_timeout_ms() -> int \n \n "
" Returns a timeout value suitable for usage in poll(), the value \n "
" returned by .get_timeout() converted to relative ms, or -1 if \n "
" no timeout is necessary. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_timeout_ms ( Reader * self , PyObject * args ) {
2013-04-15 02:37:03 +04:00
int r ;
uint64_t t ;
r = sd_journal_get_timeout ( self - > j , & t ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-04-15 02:37:03 +04:00
return NULL ;
2013-05-09 03:46:49 +04:00
return absolute_timeout ( t ) ;
2013-04-15 02:37:03 +04:00
}
2013-03-07 09:35:28 +04:00
PyDoc_STRVAR ( Reader_close__doc__ ,
2013-03-08 00:27:30 +04:00
" close() -> None \n \n "
2013-03-07 09:35:28 +04:00
" Free resources allocated by this Reader object. \n "
" This method invokes sd_journal_close(). \n "
" See man:sd_journal_close(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_close ( Reader * self , PyObject * args ) {
2013-03-18 09:12:25 +04:00
assert ( self ) ;
assert ( ! args ) ;
sd_journal_close ( self - > j ) ;
self - > j = NULL ;
Py_RETURN_NONE ;
}
2013-03-16 02:10:51 +04:00
2013-03-21 02:30:10 +04:00
PyDoc_STRVAR ( Reader_get_usage__doc__ ,
" get_usage() -> int \n \n "
2013-04-15 02:37:38 +04:00
" Returns the total disk space currently used by journal \n "
" files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was \n "
" passed when opening the journal this value will only reflect \n "
" the size of journal files of the local host, otherwise \n "
2013-03-21 02:30:10 +04:00
" of all hosts. \n \n "
" This method invokes sd_journal_get_usage(). \n "
" See man:sd_journal_get_usage(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_usage ( Reader * self , PyObject * args ) {
2013-03-21 02:30:10 +04:00
int r ;
uint64_t bytes ;
r = sd_journal_get_usage ( self - > j , & bytes ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-03-21 02:30:10 +04:00
return NULL ;
assert_cc ( sizeof ( unsigned long long ) = = sizeof ( bytes ) ) ;
return PyLong_FromUnsignedLongLong ( bytes ) ;
}
2013-03-18 09:12:25 +04:00
PyDoc_STRVAR ( Reader___enter____doc__ ,
" __enter__() -> self \n \n "
" Part of the context manager protocol. \n "
" Returns self. \n " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader___enter__ ( PyObject * self , PyObject * args ) {
2013-03-18 09:12:25 +04:00
assert ( self ) ;
assert ( ! args ) ;
Py_INCREF ( self ) ;
return self ;
}
PyDoc_STRVAR ( Reader___exit____doc__ ,
" __exit__(type, value, traceback) -> None \n \n "
" Part of the context manager protocol. \n "
" Closes the journal. \n " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader___exit__ ( Reader * self , PyObject * args ) {
2013-05-10 02:10:30 +04:00
return Reader_close ( self , args ) ;
2013-03-07 09:35:28 +04:00
}
2013-03-16 02:10:51 +04:00
2013-03-21 03:12:27 +04:00
PyDoc_STRVAR ( Reader_next__doc__ ,
" next([skip]) -> bool \n \n "
" Go to the next log entry. Optional skip value means to go to \n "
" the `skip` \\ -th log entry. \n "
" Returns False if at end of file, True otherwise. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_next ( Reader * self , PyObject * args ) {
2013-02-22 16:33:06 +04:00
int64_t skip = 1LL ;
int r ;
2013-02-20 07:11:02 +04:00
2013-03-21 03:12:27 +04:00
if ( ! PyArg_ParseTuple ( args , " |L:next " , & skip ) )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-16 21:29:57 +04:00
if ( skip = = 0LL ) {
2013-02-20 07:11:02 +04:00
PyErr_SetString ( PyExc_ValueError , " skip must be nonzero " ) ;
2013-02-16 21:29:57 +04:00
return NULL ;
}
Py_BEGIN_ALLOW_THREADS
2013-02-20 07:11:02 +04:00
if ( skip = = 1LL )
2013-02-08 23:41:21 +04:00
r = sd_journal_next ( self - > j ) ;
2013-02-20 07:11:02 +04:00
else if ( skip = = - 1LL )
2013-02-08 23:41:21 +04:00
r = sd_journal_previous ( self - > j ) ;
2013-02-20 07:11:02 +04:00
else if ( skip > 1LL )
2013-02-08 23:41:21 +04:00
r = sd_journal_next_skip ( self - > j , skip ) ;
2013-02-20 07:11:02 +04:00
else if ( skip < - 1LL )
2013-02-08 23:41:21 +04:00
r = sd_journal_previous_skip ( self - > j , - skip ) ;
2013-02-22 16:33:06 +04:00
else
assert_not_reached ( " should not be here " ) ;
2013-02-16 21:29:57 +04:00
Py_END_ALLOW_THREADS
2013-02-08 23:41:21 +04:00
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-03-21 03:12:27 +04:00
return PyBool_FromLong ( r ) ;
}
python-systemd: Reader return special fields and _Reader changes
Changes to _Reader make it match closer to C API, by removing `get_next`
and `get_previous`. A `get_all` method added, which returns dictionary
of fields using C API SD_JOURNAL_FOREACH_DATA macro, which can be used
in conjunction with `next`.
_Reader `get`, `next`, `get_{realtime,monotonic,cursor}` and new
`previous` methods are made private. This is so the traversal and
getting of journal fields can be made transparent in the python
interface.
Reader now solely implements `get_next` and `get_previous`, returning a
standard dictionary (future: other mapping types?) with all standard and
special fields through the converters. This makes the output the same as
journalctl json/export format output.
Iterator methods also moved to Reader, as they do not function as intend
with changes to _Reader.
These changes also mean that more optimised journal interfaces can be
made more easily from _Reader, by avoiding getting of unrequired fields
by using the `_get` method, and avoiding field conversions.
2013-04-14 23:55:08 +04:00
PyDoc_STRVAR ( Reader_previous__doc__ ,
" previous([skip]) -> bool \n \n "
" Go to the previous log entry. Optional skip value means to \n "
" go to the `skip` \\ -th previous log entry. \n "
" Returns False if at start of file, True otherwise. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_previous ( Reader * self , PyObject * args ) {
python-systemd: Reader return special fields and _Reader changes
Changes to _Reader make it match closer to C API, by removing `get_next`
and `get_previous`. A `get_all` method added, which returns dictionary
of fields using C API SD_JOURNAL_FOREACH_DATA macro, which can be used
in conjunction with `next`.
_Reader `get`, `next`, `get_{realtime,monotonic,cursor}` and new
`previous` methods are made private. This is so the traversal and
getting of journal fields can be made transparent in the python
interface.
Reader now solely implements `get_next` and `get_previous`, returning a
standard dictionary (future: other mapping types?) with all standard and
special fields through the converters. This makes the output the same as
journalctl json/export format output.
Iterator methods also moved to Reader, as they do not function as intend
with changes to _Reader.
These changes also mean that more optimised journal interfaces can be
made more easily from _Reader, by avoiding getting of unrequired fields
by using the `_get` method, and avoiding field conversions.
2013-04-14 23:55:08 +04:00
int64_t skip = 1LL ;
if ( ! PyArg_ParseTuple ( args , " |L:previous " , & skip ) )
return NULL ;
return PyObject_CallMethod ( ( PyObject * ) self , ( char * ) " _next " ,
( char * ) " L " , - skip ) ;
}
2013-03-21 03:12:27 +04:00
2013-03-21 07:01:32 +04:00
static int extract ( const char * msg , size_t msg_len ,
PyObject * * key , PyObject * * value ) {
PyObject * k = NULL , * v ;
const char * delim_ptr ;
delim_ptr = memchr ( msg , ' = ' , msg_len ) ;
if ( ! delim_ptr ) {
PyErr_SetString ( PyExc_OSError ,
" journal gave us a field without '=' " ) ;
return - 1 ;
}
if ( key ) {
k = unicode_FromStringAndSize ( msg , delim_ptr - ( const char * ) msg ) ;
if ( ! k )
return - 1 ;
}
if ( value ) {
v = PyBytes_FromStringAndSize ( delim_ptr + 1 ,
( const char * ) msg + msg_len - ( delim_ptr + 1 ) ) ;
if ( ! v ) {
Py_XDECREF ( k ) ;
return - 1 ;
}
* value = v ;
}
if ( key )
* key = k ;
return 0 ;
}
PyDoc_STRVAR ( Reader_get__doc__ ,
" get(str) -> str \n \n "
" Return data associated with this key in current log entry. \n "
" Throws KeyError is the data is not available. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get ( Reader * self , PyObject * args ) {
2013-03-21 07:01:32 +04:00
const char * field ;
const void * msg ;
size_t msg_len ;
PyObject * value ;
int r ;
assert ( self ) ;
assert ( args ) ;
if ( ! PyArg_ParseTuple ( args , " s:get " , & field ) )
return NULL ;
r = sd_journal_get_data ( self - > j , field , & msg , & msg_len ) ;
if ( r = = - ENOENT ) {
PyErr_SetString ( PyExc_KeyError , field ) ;
return NULL ;
2013-12-30 08:39:28 +04:00
}
if ( set_error ( r , NULL , " field name is not valid " ) < 0 )
2013-03-21 07:01:32 +04:00
return NULL ;
r = extract ( msg , msg_len , NULL , & value ) ;
if ( r < 0 )
return NULL ;
return value ;
}
python-systemd: Reader return special fields and _Reader changes
Changes to _Reader make it match closer to C API, by removing `get_next`
and `get_previous`. A `get_all` method added, which returns dictionary
of fields using C API SD_JOURNAL_FOREACH_DATA macro, which can be used
in conjunction with `next`.
_Reader `get`, `next`, `get_{realtime,monotonic,cursor}` and new
`previous` methods are made private. This is so the traversal and
getting of journal fields can be made transparent in the python
interface.
Reader now solely implements `get_next` and `get_previous`, returning a
standard dictionary (future: other mapping types?) with all standard and
special fields through the converters. This makes the output the same as
journalctl json/export format output.
Iterator methods also moved to Reader, as they do not function as intend
with changes to _Reader.
These changes also mean that more optimised journal interfaces can be
made more easily from _Reader, by avoiding getting of unrequired fields
by using the `_get` method, and avoiding field conversions.
2013-04-14 23:55:08 +04:00
PyDoc_STRVAR ( Reader_get_all__doc__ ,
" _get_all() -> dict \n \n "
" Return dictionary of the current log entry. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_all ( Reader * self , PyObject * args ) {
2013-03-21 03:12:27 +04:00
PyObject * dict ;
const void * msg ;
size_t msg_len ;
int r ;
2013-02-08 23:41:21 +04:00
dict = PyDict_New ( ) ;
2013-02-22 16:33:06 +04:00
if ( ! dict )
return NULL ;
2013-02-08 23:41:21 +04:00
SD_JOURNAL_FOREACH_DATA ( self - > j , msg , msg_len ) {
2013-04-18 11:11:22 +04:00
_cleanup_Py_DECREF_ PyObject * key = NULL , * value = NULL ;
2013-02-22 16:33:06 +04:00
2013-03-21 07:01:32 +04:00
r = extract ( msg , msg_len , & key , & value ) ;
if ( r < 0 )
2013-02-22 16:33:06 +04:00
goto error ;
2013-02-08 23:41:21 +04:00
if ( PyDict_Contains ( dict , key ) ) {
2013-02-22 16:33:06 +04:00
PyObject * cur_value = PyDict_GetItem ( dict , key ) ;
2013-02-15 20:59:50 +04:00
if ( PyList_CheckExact ( cur_value ) ) {
2013-02-22 16:33:06 +04:00
r = PyList_Append ( cur_value , value ) ;
if ( r < 0 )
goto error ;
} else {
2013-04-18 11:11:22 +04:00
_cleanup_Py_DECREF_ PyObject * tmp_list = PyList_New ( 0 ) ;
2013-02-22 16:33:06 +04:00
if ( ! tmp_list )
goto error ;
r = PyList_Append ( tmp_list , cur_value ) ;
if ( r < 0 )
goto error ;
r = PyList_Append ( tmp_list , value ) ;
if ( r < 0 )
goto error ;
2013-03-01 21:29:57 +04:00
r = PyDict_SetItem ( dict , key , tmp_list ) ;
2013-02-22 16:33:06 +04:00
if ( r < 0 )
goto error ;
2013-02-08 23:41:21 +04:00
}
2013-02-22 16:33:06 +04:00
} else {
r = PyDict_SetItem ( dict , key , value ) ;
if ( r < 0 )
goto error ;
2013-02-08 23:41:21 +04:00
}
}
2013-03-21 03:12:27 +04:00
return dict ;
2013-03-21 07:01:32 +04:00
2013-03-21 03:12:27 +04:00
error :
Py_DECREF ( dict ) ;
return NULL ;
}
2013-02-22 16:33:06 +04:00
2013-03-21 03:12:27 +04:00
PyDoc_STRVAR ( Reader_get_realtime__doc__ ,
" get_realtime() -> int \n \n "
" Return the realtime timestamp for the current journal entry \n "
" in microseconds. \n \n "
" Wraps sd_journal_get_realtime_usec(). \n "
" See man:sd_journal_get_realtime_usec(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_realtime ( Reader * self , PyObject * args ) {
2013-03-21 03:12:27 +04:00
uint64_t timestamp ;
int r ;
2013-02-22 16:33:06 +04:00
2013-03-21 03:12:27 +04:00
assert ( self ) ;
assert ( ! args ) ;
2013-02-22 16:33:06 +04:00
2013-03-21 03:12:27 +04:00
r = sd_journal_get_realtime_usec ( self - > j , & timestamp ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-03-21 03:12:27 +04:00
return NULL ;
2013-02-08 23:41:21 +04:00
2013-03-21 03:12:27 +04:00
assert_cc ( sizeof ( unsigned long long ) = = sizeof ( timestamp ) ) ;
return PyLong_FromUnsignedLongLong ( timestamp ) ;
}
2013-02-22 16:33:06 +04:00
2013-03-21 03:12:27 +04:00
PyDoc_STRVAR ( Reader_get_monotonic__doc__ ,
" get_monotonic() -> (timestamp, bootid) \n \n "
" Return the monotonic timestamp for the current journal entry \n "
" as a tuple of time in microseconds and bootid. \n \n "
" Wraps sd_journal_get_monotonic_usec(). \n "
" See man:sd_journal_get_monotonic_usec(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_monotonic ( Reader * self , PyObject * args ) {
2013-03-21 03:12:27 +04:00
uint64_t timestamp ;
sd_id128_t id ;
PyObject * monotonic , * bootid , * tuple ;
int r ;
assert ( self ) ;
assert ( ! args ) ;
r = sd_journal_get_monotonic_usec ( self - > j , & timestamp , & id ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-03-21 03:12:27 +04:00
return NULL ;
assert_cc ( sizeof ( unsigned long long ) = = sizeof ( timestamp ) ) ;
monotonic = PyLong_FromUnsignedLongLong ( timestamp ) ;
bootid = PyBytes_FromStringAndSize ( ( const char * ) & id . bytes , sizeof ( id . bytes ) ) ;
2013-02-23 04:11:36 +04:00
# if PY_MAJOR_VERSION >= 3
2013-03-21 03:12:27 +04:00
tuple = PyStructSequence_New ( & MonotonicType ) ;
2013-02-23 04:11:36 +04:00
# else
2013-03-21 03:12:27 +04:00
tuple = PyTuple_New ( 2 ) ;
2013-02-23 04:11:36 +04:00
# endif
2013-03-21 03:12:27 +04:00
if ( ! monotonic | | ! bootid | | ! tuple ) {
Py_XDECREF ( monotonic ) ;
Py_XDECREF ( bootid ) ;
Py_XDECREF ( tuple ) ;
return NULL ;
}
2013-02-23 04:11:36 +04:00
# if PY_MAJOR_VERSION >= 3
2013-03-21 03:12:27 +04:00
PyStructSequence_SET_ITEM ( tuple , 0 , monotonic ) ;
PyStructSequence_SET_ITEM ( tuple , 1 , bootid ) ;
2013-02-23 04:11:36 +04:00
# else
2013-03-21 03:12:27 +04:00
PyTuple_SET_ITEM ( tuple , 0 , monotonic ) ;
PyTuple_SET_ITEM ( tuple , 1 , bootid ) ;
2013-02-23 04:11:36 +04:00
# endif
2013-02-22 16:33:06 +04:00
2013-03-21 03:12:27 +04:00
return tuple ;
2013-02-08 23:41:21 +04:00
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_add_match__doc__ ,
2013-02-20 07:22:03 +04:00
" add_match(match) -> None \n \n "
" Add a match to filter journal log entries. All matches of different \n "
2013-02-20 08:03:32 +04:00
" fields are combined with logical AND, and matches of the same field \n "
" are automatically combined with logical OR. \n "
2013-02-20 07:22:03 +04:00
" Match is a string of the form \" FIELD=value \" . " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_add_match ( Reader * self , PyObject * args , PyObject * keywds ) {
2013-02-16 22:53:52 +04:00
char * match ;
2013-02-20 07:11:02 +04:00
int match_len , r ;
2013-03-21 03:12:27 +04:00
if ( ! PyArg_ParseTuple ( args , " s#:add_match " , & match , & match_len ) )
2013-02-16 22:53:52 +04:00
return NULL ;
r = sd_journal_add_match ( self - > j , match , match_len ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , " Invalid match " ) < 0 )
2013-02-17 20:26:10 +04:00
return NULL ;
2013-02-08 23:41:21 +04:00
Py_RETURN_NONE ;
}
2013-03-16 02:10:51 +04:00
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_add_disjunction__doc__ ,
2013-02-20 07:22:03 +04:00
" add_disjunction() -> None \n \n "
2013-04-19 03:37:26 +04:00
" Inserts a logical OR between matches added since previous \n "
" add_disjunction() or add_conjunction() and the next \n "
" add_disjunction() or add_conjunction(). \n \n "
" See man:sd_journal_add_disjunction(3) for explanation. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_add_disjunction ( Reader * self , PyObject * args ) {
2013-02-08 23:41:21 +04:00
int r ;
r = sd_journal_add_disjunction ( self - > j ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_RETURN_NONE ;
}
2013-03-16 02:10:51 +04:00
2013-04-19 03:37:26 +04:00
PyDoc_STRVAR ( Reader_add_conjunction__doc__ ,
" add_conjunction() -> None \n \n "
" Inserts a logical AND between matches added since previous \n "
" add_disjunction() or add_conjunction() and the next \n "
" add_disjunction() or add_conjunction(). \n \n "
" See man:sd_journal_add_disjunction(3) for explanation. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_add_conjunction ( Reader * self , PyObject * args ) {
2013-04-19 03:37:26 +04:00
int r ;
r = sd_journal_add_conjunction ( self - > j ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-04-19 03:37:26 +04:00
return NULL ;
Py_RETURN_NONE ;
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_flush_matches__doc__ ,
2013-02-20 07:22:03 +04:00
" flush_matches() -> None \n \n "
2013-02-20 08:03:32 +04:00
" Clear all current match filters. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_flush_matches ( Reader * self , PyObject * args ) {
2013-02-08 23:41:21 +04:00
sd_journal_flush_matches ( self - > j ) ;
Py_RETURN_NONE ;
}
2013-03-16 02:10:51 +04:00
2013-03-07 09:26:24 +04:00
PyDoc_STRVAR ( Reader_seek_head__doc__ ,
" seek_head() -> None \n \n "
" Jump to the beginning of the journal. \n "
" This method invokes sd_journal_seek_head(). \n "
" See man:sd_journal_seek_head(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_seek_head ( Reader * self , PyObject * args ) {
2013-03-07 09:26:24 +04:00
int r ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_seek_head ( self - > j ) ;
Py_END_ALLOW_THREADS
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-03-07 09:26:24 +04:00
Py_RETURN_NONE ;
}
2013-02-08 23:41:21 +04:00
2013-03-16 02:10:51 +04:00
2013-03-07 09:26:24 +04:00
PyDoc_STRVAR ( Reader_seek_tail__doc__ ,
" seek_tail() -> None \n \n "
2013-03-08 00:27:30 +04:00
" Jump to the end of the journal. \n "
2013-03-07 09:26:24 +04:00
" This method invokes sd_journal_seek_tail(). \n "
" See man:sd_journal_seek_tail(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_seek_tail ( Reader * self , PyObject * args ) {
2013-03-07 09:26:24 +04:00
int r ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_seek_tail ( self - > j ) ;
Py_END_ALLOW_THREADS
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-02-16 17:40:44 +04:00
return NULL ;
2013-02-08 23:41:21 +04:00
Py_RETURN_NONE ;
}
2013-03-16 02:10:51 +04:00
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_seek_realtime__doc__ ,
2013-02-20 07:22:03 +04:00
" seek_realtime(realtime) -> None \n \n "
" Seek to nearest matching journal entry to `realtime`. Argument \n "
2013-03-21 02:40:05 +04:00
" `realtime` in specified in seconds. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_seek_realtime ( Reader * self , PyObject * args ) {
2013-02-20 07:11:02 +04:00
uint64_t timestamp ;
int r ;
2013-03-21 02:40:05 +04:00
if ( ! PyArg_ParseTuple ( args , " K:seek_realtime " , & timestamp ) )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_seek_realtime_usec ( self - > j , timestamp ) ;
Py_END_ALLOW_THREADS
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_RETURN_NONE ;
}
2013-03-16 02:10:51 +04:00
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_seek_monotonic__doc__ ,
2013-02-20 07:22:03 +04:00
" seek_monotonic(monotonic[, bootid]) -> None \n \n "
" Seek to nearest matching journal entry to `monotonic`. Argument \n "
2013-03-21 02:40:05 +04:00
" `monotonic` is an timestamp from boot in microseconds. \n "
2013-02-20 07:22:03 +04:00
" Argument `bootid` is a string representing which boot the \n "
" monotonic time is reference to. Defaults to current bootid. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_seek_monotonic ( Reader * self , PyObject * args ) {
2013-02-20 07:22:03 +04:00
char * bootid = NULL ;
2013-02-20 07:11:02 +04:00
uint64_t timestamp ;
2013-02-23 04:11:36 +04:00
sd_id128_t id ;
2013-02-20 07:11:02 +04:00
int r ;
2013-03-21 02:40:05 +04:00
if ( ! PyArg_ParseTuple ( args , " K|z:seek_monotonic " , & timestamp , & bootid ) )
2013-02-08 23:41:21 +04:00
return NULL ;
if ( bootid ) {
2013-02-23 04:11:36 +04:00
r = sd_id128_from_string ( bootid , & id ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , " Invalid bootid " ) < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-17 20:26:10 +04:00
} else {
Py_BEGIN_ALLOW_THREADS
2013-02-23 04:11:36 +04:00
r = sd_id128_get_boot ( & id ) ;
2013-02-17 20:26:10 +04:00
Py_END_ALLOW_THREADS
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
}
Py_BEGIN_ALLOW_THREADS
2013-02-23 04:11:36 +04:00
r = sd_journal_seek_monotonic_usec ( self - > j , id , timestamp ) ;
2013-02-08 23:41:21 +04:00
Py_END_ALLOW_THREADS
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-03-21 02:40:05 +04:00
2013-02-08 23:41:21 +04:00
Py_RETURN_NONE ;
}
2013-02-17 20:26:10 +04:00
2013-03-16 02:10:51 +04:00
2013-04-15 02:37:03 +04:00
PyDoc_STRVAR ( Reader_process__doc__ ,
" process() -> state change (integer) \n \n "
" Process events and reset the readable state of the file \n "
" descriptor returned by .fileno(). \n \n "
" Will return constants: NOP if no change; APPEND if new \n "
" entries have been added to the end of the journal; and \n "
" INVALIDATE if journal files have been added or removed. \n \n "
" See man:sd_journal_process(3) for further discussion. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_process ( Reader * self , PyObject * args ) {
2013-04-15 02:37:03 +04:00
int r ;
assert ( ! args ) ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_process ( self - > j ) ;
Py_END_ALLOW_THREADS
if ( set_error ( r , NULL , NULL ) < 0 )
return NULL ;
return long_FromLong ( r ) ;
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_wait__doc__ ,
2013-02-20 08:03:32 +04:00
" wait([timeout]) -> state change (integer) \n \n "
" Wait for a change in the journal. Argument `timeout` specifies \n "
2013-03-21 02:40:05 +04:00
" the maximum number of microseconds to wait before returning \n "
" regardless of wheter the journal has changed. If `timeout` is -1, \n "
" then block forever. \n \n "
2013-02-20 07:22:03 +04:00
" Will return constants: NOP if no change; APPEND if new \n "
" entries have been added to the end of the journal; and \n "
2013-04-15 02:37:38 +04:00
" INVALIDATE if journal files have been added or removed. \n \n "
" See man:sd_journal_wait(3) for further discussion. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_wait ( Reader * self , PyObject * args ) {
2013-02-20 06:58:54 +04:00
int r ;
2013-03-21 02:40:05 +04:00
int64_t timeout ;
2013-02-20 06:58:54 +04:00
2013-03-21 02:40:05 +04:00
if ( ! PyArg_ParseTuple ( args , " |L:wait " , & timeout ) )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-16 21:29:57 +04:00
Py_BEGIN_ALLOW_THREADS
2013-03-21 02:40:05 +04:00
r = sd_journal_wait ( self - > j , timeout ) ;
2013-02-16 21:29:57 +04:00
Py_END_ALLOW_THREADS
2013-03-06 08:23:09 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-02-16 21:29:57 +04:00
return NULL ;
2013-02-17 20:26:10 +04:00
2013-02-17 06:54:09 +04:00
return long_FromLong ( r ) ;
2013-02-08 23:41:21 +04:00
}
2013-03-16 02:10:51 +04:00
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_seek_cursor__doc__ ,
2013-02-20 07:22:03 +04:00
" seek_cursor(cursor) -> None \n \n "
2013-02-20 08:03:32 +04:00
" Seek to journal entry by given unique reference `cursor`. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_seek_cursor ( Reader * self , PyObject * args ) {
2013-02-08 23:41:21 +04:00
const char * cursor ;
2013-02-20 07:11:02 +04:00
int r ;
2013-03-21 03:12:27 +04:00
if ( ! PyArg_ParseTuple ( args , " s:seek_cursor " , & cursor ) )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_seek_cursor ( self - > j , cursor ) ;
Py_END_ALLOW_THREADS
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , " Invalid cursor " ) < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_RETURN_NONE ;
}
2013-03-16 02:10:51 +04:00
2013-03-21 03:00:37 +04:00
PyDoc_STRVAR ( Reader_get_cursor__doc__ ,
" get_cursor() -> str \n \n "
" Return a cursor string for the current journal entry. \n \n "
" Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_cursor ( Reader * self , PyObject * args ) {
2013-04-18 11:11:22 +04:00
_cleanup_free_ char * cursor = NULL ;
2013-03-21 03:00:37 +04:00
int r ;
assert ( self ) ;
assert ( ! args ) ;
r = sd_journal_get_cursor ( self - > j , & cursor ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-03-21 03:00:37 +04:00
return NULL ;
return unicode_FromString ( cursor ) ;
}
PyDoc_STRVAR ( Reader_test_cursor__doc__ ,
" test_cursor(str) -> bool \n \n "
" Test whether the cursor string matches current journal entry. \n \n "
" Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_test_cursor ( Reader * self , PyObject * args ) {
2013-03-21 03:00:37 +04:00
const char * cursor ;
int r ;
assert ( self ) ;
assert ( args ) ;
2013-03-21 03:12:27 +04:00
if ( ! PyArg_ParseTuple ( args , " s:test_cursor " , & cursor ) )
2013-03-21 03:00:37 +04:00
return NULL ;
r = sd_journal_test_cursor ( self - > j , cursor ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-03-21 03:00:37 +04:00
return NULL ;
return PyBool_FromLong ( r ) ;
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_query_unique__doc__ ,
2013-02-20 07:22:03 +04:00
" query_unique(field) -> a set of values \n \n "
2013-02-20 08:03:32 +04:00
" Return a set of unique values appearing in journal for the \n "
" given `field`. Note this does not respect any journal matches. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_query_unique ( Reader * self , PyObject * args ) {
2013-02-08 23:41:21 +04:00
char * query ;
2013-02-20 07:11:02 +04:00
int r ;
const void * uniq ;
size_t uniq_len ;
PyObject * value_set , * key , * value ;
2013-03-21 03:12:27 +04:00
if ( ! PyArg_ParseTuple ( args , " s:query_unique " , & query ) )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_query_unique ( self - > j , query ) ;
Py_END_ALLOW_THREADS
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , " Invalid field name " ) < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
value_set = PySet_New ( 0 ) ;
2013-02-17 06:54:09 +04:00
key = unicode_FromString ( query ) ;
2013-02-08 23:41:21 +04:00
SD_JOURNAL_FOREACH_UNIQUE ( self - > j , uniq , uniq_len ) {
2013-02-20 07:11:02 +04:00
const char * delim_ptr ;
2013-02-08 23:41:21 +04:00
delim_ptr = memchr ( uniq , ' = ' , uniq_len ) ;
2013-02-22 16:33:06 +04:00
value = PyBytes_FromStringAndSize (
delim_ptr + 1 ,
( const char * ) uniq + uniq_len - ( delim_ptr + 1 ) ) ;
2013-02-08 23:41:21 +04:00
PySet_Add ( value_set , value ) ;
Py_DECREF ( value ) ;
}
Py_DECREF ( key ) ;
return value_set ;
}
2013-03-16 02:10:51 +04:00
PyDoc_STRVAR ( Reader_get_catalog__doc__ ,
" get_catalog() -> str \n \n "
" Retrieve a message catalog entry for the current journal entry. \n "
2013-03-21 07:01:32 +04:00
" Will throw IndexError if the entry has no MESSAGE_ID \n "
" and KeyError is the id is specified, but hasn't been found \n "
" in the catalog. \n \n "
2013-03-16 02:10:51 +04:00
" Wraps man:sd_journal_get_catalog(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_catalog ( Reader * self , PyObject * args ) {
2013-03-16 02:10:51 +04:00
int r ;
2013-04-18 11:11:22 +04:00
_cleanup_free_ char * msg = NULL ;
2013-03-16 02:10:51 +04:00
assert ( self ) ;
assert ( ! args ) ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_get_catalog ( self - > j , & msg ) ;
Py_END_ALLOW_THREADS
2013-03-21 07:01:32 +04:00
if ( r = = - ENOENT ) {
const void * mid ;
size_t mid_len ;
r = sd_journal_get_data ( self - > j , " MESSAGE_ID " , & mid , & mid_len ) ;
if ( r = = 0 ) {
2013-07-26 19:02:27 +04:00
const size_t l = sizeof ( " MESSAGE_ID " ) ;
2013-03-21 07:01:32 +04:00
assert ( mid_len > l ) ;
2013-07-26 19:02:27 +04:00
PyErr_Format ( PyExc_KeyError , " %.*s " , ( int ) ( mid_len - l ) ,
2013-03-21 07:01:32 +04:00
( const char * ) mid + l ) ;
} else if ( r = = - ENOENT )
PyErr_SetString ( PyExc_IndexError , " no MESSAGE_ID field " ) ;
else
set_error ( r , NULL , NULL ) ;
return NULL ;
2013-12-30 08:39:28 +04:00
}
if ( set_error ( r , NULL , NULL ) < 0 )
2013-03-16 02:10:51 +04:00
return NULL ;
return unicode_FromString ( msg ) ;
}
2013-03-16 02:10:51 +04:00
PyDoc_STRVAR ( get_catalog__doc__ ,
" get_catalog(id128) -> str \n \n "
" Retrieve a message catalog entry for the given id. \n "
" Wraps man:sd_journal_get_catalog_for_message_id(3). " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * get_catalog ( PyObject * self , PyObject * args ) {
2013-03-16 02:10:51 +04:00
int r ;
char * id_ = NULL ;
sd_id128_t id ;
2013-04-18 11:11:22 +04:00
_cleanup_free_ char * msg = NULL ;
2013-03-16 02:10:51 +04:00
assert ( ! self ) ;
assert ( args ) ;
2013-03-16 02:10:51 +04:00
if ( ! PyArg_ParseTuple ( args , " z:get_catalog " , & id_ ) )
2013-03-16 02:10:51 +04:00
return NULL ;
r = sd_id128_from_string ( id_ , & id ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , " Invalid id128 " ) < 0 )
2013-03-16 02:10:51 +04:00
return NULL ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_get_catalog_for_message_id ( id , & msg ) ;
Py_END_ALLOW_THREADS
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-03-16 02:10:51 +04:00
return NULL ;
return unicode_FromString ( msg ) ;
}
2013-02-20 08:03:32 +04:00
PyDoc_STRVAR ( data_threshold__doc__ ,
2013-02-22 16:33:06 +04:00
" Threshold for field size truncation in bytes. \n \n "
2013-02-20 08:03:32 +04:00
" Fields longer than this will be truncated to the threshold size. \n "
" Defaults to 64Kb. " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_data_threshold ( Reader * self , void * closure ) {
2013-02-08 23:41:21 +04:00
size_t cvalue ;
int r ;
r = sd_journal_get_data_threshold ( self - > j , & cvalue ) ;
2013-12-30 08:39:28 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-17 06:54:09 +04:00
return long_FromSize_t ( cvalue ) ;
2013-02-08 23:41:21 +04:00
}
2013-12-04 01:27:45 +04:00
static int Reader_set_data_threshold ( Reader * self , PyObject * value , void * closure ) {
2013-02-20 07:11:02 +04:00
int r ;
2013-02-08 23:41:21 +04:00
if ( value = = NULL ) {
2013-02-22 16:33:06 +04:00
PyErr_SetString ( PyExc_AttributeError , " Cannot delete data threshold " ) ;
2013-02-08 23:41:21 +04:00
return - 1 ;
}
2013-02-17 06:54:09 +04:00
if ( ! long_Check ( value ) ) {
2013-02-20 07:11:02 +04:00
PyErr_SetString ( PyExc_TypeError , " Data threshold must be an int " ) ;
2013-02-08 23:41:21 +04:00
return - 1 ;
}
2013-02-17 06:54:09 +04:00
r = sd_journal_set_data_threshold ( self - > j , ( size_t ) long_AsLong ( value ) ) ;
2013-02-17 20:26:10 +04:00
return set_error ( r , NULL , NULL ) ;
2013-02-08 23:41:21 +04:00
}
2013-03-16 02:10:51 +04:00
2013-03-16 02:10:51 +04:00
PyDoc_STRVAR ( closed__doc__ ,
" True iff journal is closed " ) ;
2013-12-04 01:27:45 +04:00
static PyObject * Reader_get_closed ( Reader * self , void * closure ) {
2013-03-16 02:10:51 +04:00
return PyBool_FromLong ( self - > j = = NULL ) ;
}
2013-03-16 02:10:51 +04:00
2013-03-16 02:10:51 +04:00
static PyGetSetDef Reader_getsetters [ ] = {
2013-02-20 06:58:54 +04:00
{ ( char * ) " data_threshold " ,
2013-03-01 04:32:31 +04:00
( getter ) Reader_get_data_threshold ,
( setter ) Reader_set_data_threshold ,
2013-02-20 08:03:32 +04:00
( char * ) data_threshold__doc__ ,
2013-02-20 06:58:54 +04:00
NULL } ,
2013-03-16 02:10:51 +04:00
{ ( char * ) " closed " ,
( getter ) Reader_get_closed ,
NULL ,
( char * ) closed__doc__ ,
NULL } ,
2013-03-25 03:59:00 +04:00
{ } /* Sentinel */
2013-02-08 23:41:21 +04:00
} ;
2013-03-01 04:32:31 +04:00
static PyMethodDef Reader_methods [ ] = {
2013-03-07 09:35:28 +04:00
{ " fileno " , ( PyCFunction ) Reader_fileno , METH_NOARGS , Reader_fileno__doc__ } ,
{ " reliable_fd " , ( PyCFunction ) Reader_reliable_fd , METH_NOARGS , Reader_reliable_fd__doc__ } ,
2013-04-15 02:37:03 +04:00
{ " get_events " , ( PyCFunction ) Reader_get_events , METH_NOARGS , Reader_get_events__doc__ } ,
{ " get_timeout " , ( PyCFunction ) Reader_get_timeout , METH_NOARGS , Reader_get_timeout__doc__ } ,
{ " get_timeout_ms " , ( PyCFunction ) Reader_get_timeout_ms , METH_NOARGS , Reader_get_timeout_ms__doc__ } ,
2013-03-07 09:35:28 +04:00
{ " close " , ( PyCFunction ) Reader_close , METH_NOARGS , Reader_close__doc__ } ,
2013-03-21 02:30:10 +04:00
{ " get_usage " , ( PyCFunction ) Reader_get_usage , METH_NOARGS , Reader_get_usage__doc__ } ,
2013-03-18 09:12:25 +04:00
{ " __enter__ " , ( PyCFunction ) Reader___enter__ , METH_NOARGS , Reader___enter____doc__ } ,
{ " __exit__ " , ( PyCFunction ) Reader___exit__ , METH_VARARGS , Reader___exit____doc__ } ,
python-systemd: Reader return special fields and _Reader changes
Changes to _Reader make it match closer to C API, by removing `get_next`
and `get_previous`. A `get_all` method added, which returns dictionary
of fields using C API SD_JOURNAL_FOREACH_DATA macro, which can be used
in conjunction with `next`.
_Reader `get`, `next`, `get_{realtime,monotonic,cursor}` and new
`previous` methods are made private. This is so the traversal and
getting of journal fields can be made transparent in the python
interface.
Reader now solely implements `get_next` and `get_previous`, returning a
standard dictionary (future: other mapping types?) with all standard and
special fields through the converters. This makes the output the same as
journalctl json/export format output.
Iterator methods also moved to Reader, as they do not function as intend
with changes to _Reader.
These changes also mean that more optimised journal interfaces can be
made more easily from _Reader, by avoiding getting of unrequired fields
by using the `_get` method, and avoiding field conversions.
2013-04-14 23:55:08 +04:00
{ " _next " , ( PyCFunction ) Reader_next , METH_VARARGS , Reader_next__doc__ } ,
{ " _previous " , ( PyCFunction ) Reader_previous , METH_VARARGS , Reader_previous__doc__ } ,
{ " _get " , ( PyCFunction ) Reader_get , METH_VARARGS , Reader_get__doc__ } ,
{ " _get_all " , ( PyCFunction ) Reader_get_all , METH_NOARGS , Reader_get_all__doc__ } ,
{ " _get_realtime " , ( PyCFunction ) Reader_get_realtime , METH_NOARGS , Reader_get_realtime__doc__ } ,
{ " _get_monotonic " , ( PyCFunction ) Reader_get_monotonic , METH_NOARGS , Reader_get_monotonic__doc__ } ,
2013-03-01 04:32:31 +04:00
{ " add_match " , ( PyCFunction ) Reader_add_match , METH_VARARGS | METH_KEYWORDS , Reader_add_match__doc__ } ,
{ " add_disjunction " , ( PyCFunction ) Reader_add_disjunction , METH_NOARGS , Reader_add_disjunction__doc__ } ,
2013-04-19 03:37:26 +04:00
{ " add_conjunction " , ( PyCFunction ) Reader_add_conjunction , METH_NOARGS , Reader_add_conjunction__doc__ } ,
2013-03-01 04:32:31 +04:00
{ " flush_matches " , ( PyCFunction ) Reader_flush_matches , METH_NOARGS , Reader_flush_matches__doc__ } ,
2013-03-07 09:26:24 +04:00
{ " seek_head " , ( PyCFunction ) Reader_seek_head , METH_NOARGS , Reader_seek_head__doc__ } ,
{ " seek_tail " , ( PyCFunction ) Reader_seek_tail , METH_NOARGS , Reader_seek_tail__doc__ } ,
2013-03-01 04:32:31 +04:00
{ " seek_realtime " , ( PyCFunction ) Reader_seek_realtime , METH_VARARGS , Reader_seek_realtime__doc__ } ,
{ " seek_monotonic " , ( PyCFunction ) Reader_seek_monotonic , METH_VARARGS , Reader_seek_monotonic__doc__ } ,
2013-04-15 02:37:03 +04:00
{ " process " , ( PyCFunction ) Reader_process , METH_NOARGS , Reader_process__doc__ } ,
2013-03-01 04:32:31 +04:00
{ " wait " , ( PyCFunction ) Reader_wait , METH_VARARGS , Reader_wait__doc__ } ,
{ " seek_cursor " , ( PyCFunction ) Reader_seek_cursor , METH_VARARGS , Reader_seek_cursor__doc__ } ,
python-systemd: Reader return special fields and _Reader changes
Changes to _Reader make it match closer to C API, by removing `get_next`
and `get_previous`. A `get_all` method added, which returns dictionary
of fields using C API SD_JOURNAL_FOREACH_DATA macro, which can be used
in conjunction with `next`.
_Reader `get`, `next`, `get_{realtime,monotonic,cursor}` and new
`previous` methods are made private. This is so the traversal and
getting of journal fields can be made transparent in the python
interface.
Reader now solely implements `get_next` and `get_previous`, returning a
standard dictionary (future: other mapping types?) with all standard and
special fields through the converters. This makes the output the same as
journalctl json/export format output.
Iterator methods also moved to Reader, as they do not function as intend
with changes to _Reader.
These changes also mean that more optimised journal interfaces can be
made more easily from _Reader, by avoiding getting of unrequired fields
by using the `_get` method, and avoiding field conversions.
2013-04-14 23:55:08 +04:00
{ " _get_cursor " , ( PyCFunction ) Reader_get_cursor , METH_NOARGS , Reader_get_cursor__doc__ } ,
2013-03-21 03:00:37 +04:00
{ " test_cursor " , ( PyCFunction ) Reader_test_cursor , METH_VARARGS , Reader_test_cursor__doc__ } ,
2013-03-01 04:32:31 +04:00
{ " query_unique " , ( PyCFunction ) Reader_query_unique , METH_VARARGS , Reader_query_unique__doc__ } ,
2013-03-16 02:10:51 +04:00
{ " get_catalog " , ( PyCFunction ) Reader_get_catalog , METH_NOARGS , Reader_get_catalog__doc__ } ,
2013-03-25 03:59:00 +04:00
{ } /* Sentinel */
2013-02-08 23:41:21 +04:00
} ;
2013-03-01 04:32:31 +04:00
static PyTypeObject ReaderType = {
2013-02-08 23:41:21 +04:00
PyVarObject_HEAD_INIT ( NULL , 0 )
2013-07-26 02:55:08 +04:00
. tp_name = " _reader._Reader " ,
. tp_basicsize = sizeof ( Reader ) ,
. tp_dealloc = ( destructor ) Reader_dealloc ,
. tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ,
. tp_doc = Reader__doc__ ,
. tp_methods = Reader_methods ,
. tp_getset = Reader_getsetters ,
. tp_init = ( initproc ) Reader_init ,
. tp_new = PyType_GenericNew ,
2013-02-08 23:41:21 +04:00
} ;
2013-03-16 02:10:51 +04:00
static PyMethodDef methods [ ] = {
2013-03-21 07:01:32 +04:00
{ " _get_catalog " , get_catalog , METH_VARARGS , get_catalog__doc__ } ,
2013-07-26 02:55:08 +04:00
{ } /* Sentinel */
2013-03-16 02:10:51 +04:00
} ;
2013-02-20 08:03:32 +04:00
2013-02-08 23:41:21 +04:00
# if PY_MAJOR_VERSION >= 3
2013-03-16 02:10:51 +04:00
static PyModuleDef module = {
2013-02-08 23:41:21 +04:00
PyModuleDef_HEAD_INIT ,
" _reader " ,
2013-03-16 02:10:51 +04:00
module__doc__ ,
2013-02-08 23:41:21 +04:00
- 1 ,
2013-03-16 02:10:51 +04:00
methods ,
2013-02-08 23:41:21 +04:00
} ;
# endif
2013-02-23 04:11:36 +04:00
# if PY_MAJOR_VERSION >= 3
static bool initialized = false ;
# endif
2013-02-20 06:58:54 +04:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-prototypes"
2013-02-08 23:41:21 +04:00
PyMODINIT_FUNC
# if PY_MAJOR_VERSION >= 3
PyInit__reader ( void )
# else
2013-02-20 06:58:54 +04:00
init_reader ( void )
2013-02-08 23:41:21 +04:00
# endif
{
PyObject * m ;
PyDateTime_IMPORT ;
2013-03-01 04:32:31 +04:00
if ( PyType_Ready ( & ReaderType ) < 0 )
2013-02-08 23:41:21 +04:00
# if PY_MAJOR_VERSION >= 3
return NULL ;
# else
return ;
# endif
# if PY_MAJOR_VERSION >= 3
2013-03-16 02:10:51 +04:00
m = PyModule_Create ( & module ) ;
2013-02-08 23:41:21 +04:00
if ( m = = NULL )
return NULL ;
2013-02-23 04:11:36 +04:00
if ( ! initialized ) {
PyStructSequence_InitType ( & MonotonicType , & Monotonic_desc ) ;
initialized = true ;
}
2013-02-08 23:41:21 +04:00
# else
2013-03-16 02:10:51 +04:00
m = Py_InitModule3 ( " _reader " , methods , module__doc__ ) ;
2013-02-08 23:41:21 +04:00
if ( m = = NULL )
return ;
# endif
2013-03-01 04:32:31 +04:00
Py_INCREF ( & ReaderType ) ;
2013-02-23 04:11:36 +04:00
# if PY_MAJOR_VERSION >= 3
Py_INCREF ( & MonotonicType ) ;
# endif
2013-03-01 04:32:31 +04:00
if ( PyModule_AddObject ( m , " _Reader " , ( PyObject * ) & ReaderType ) | |
2013-02-23 04:11:36 +04:00
# if PY_MAJOR_VERSION >= 3
PyModule_AddObject ( m , " Monotonic " , ( PyObject * ) & MonotonicType ) | |
# endif
2013-02-22 16:33:06 +04:00
PyModule_AddIntConstant ( m , " NOP " , SD_JOURNAL_NOP ) | |
PyModule_AddIntConstant ( m , " APPEND " , SD_JOURNAL_APPEND ) | |
PyModule_AddIntConstant ( m , " INVALIDATE " , SD_JOURNAL_INVALIDATE ) | |
PyModule_AddIntConstant ( m , " LOCAL_ONLY " , SD_JOURNAL_LOCAL_ONLY ) | |
PyModule_AddIntConstant ( m , " RUNTIME_ONLY " , SD_JOURNAL_RUNTIME_ONLY ) | |
2013-06-05 06:31:05 +04:00
PyModule_AddIntConstant ( m , " SYSTEM " , SD_JOURNAL_SYSTEM ) | |
2013-05-09 05:08:14 +04:00
PyModule_AddIntConstant ( m , " SYSTEM_ONLY " , SD_JOURNAL_SYSTEM_ONLY ) | |
2013-07-17 20:50:13 +04:00
PyModule_AddIntConstant ( m , " CURRENT_USER " , SD_JOURNAL_CURRENT_USER ) | |
2013-05-09 05:08:14 +04:00
PyModule_AddStringConstant ( m , " __version__ " , PACKAGE_VERSION ) ) {
2013-02-22 16:33:06 +04:00
# if PY_MAJOR_VERSION >= 3
Py_DECREF ( m ) ;
return NULL ;
# endif
}
2013-02-08 23:41:21 +04:00
# if PY_MAJOR_VERSION >= 3
return m ;
# endif
}
2013-02-20 06:58:54 +04:00
# pragma GCC diagnostic pop