Python systemd wrapper using Cython
Table of contents
All packages available on github releases.
Install repository key
wget -qO - 'https://bintray.com/user/downloadSubjectPublicKey?username=bintray' | \
apt-key add -Install the repository file
Debian Jessie:
echo "deb http://dl.bintray.com/mosquito/cysystemd jessie main" > /etc/apt/sources.list.d/cysystemd.list
apt-get update
apt-get install python-cysystemd python3-cysystemdUbuntu Xenial:
echo "deb http://dl.bintray.com/mosquito/cysystemd xenial main" > /etc/apt/sources.list.d/cysystemd.list
apt-get update
apt-get install python-cysystemd python3-cysystemdUbuntu Bionic:
echo "deb http://dl.bintray.com/mosquito/cysystemd bionic main" > /etc/apt/sources.list.d/cysystemd.list
apt-get update
apt-get install python-cysystemd python3-cysystemdyum localinstall \
https://github.com/mosquito/cysystemd/releases/download/0.17.1/python-cysystemd-0.17.1-1.centos7.x86_64.rpmYou should install systemd headers
For debian users:
apt-get install build-essential \
libsystemd-journal-dev \
libsystemd-daemon-dev \
libsystemd-devFor CentOS/RHEL
yum install gcc systemd-develAnd install it from pypi
pip install cysystemdfrom cysystemd import journal
import logging
import uuid
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger()
logger.addHandler(journal.JournaldLogHandler())
try:
log.info("Trying to do something")
raise Exception('foo')
except:
logger.exception("Test Exception %s", 1)from cysystemd.daemon import notify, Notification
# Send READY=1
notify(Notification.READY)
# Send status
notify(Notification.STATUS, "I'm fine.")
# Send stopping
notify(Notification.STOPPING)Write message into Systemd journal
from cysystemd import journal
journal.write("Hello Lennart")
# Or send structured data
journal.send(
message="Hello Lennart",
priority=journal.Priority.INFO,
some_field='some value',
)from cysystemd.reader import JournalReader, JournalOpenMode
journal_reader = JournalReader()
journal_reader.open(JournalOpenMode.SYSTEM)
journal_reader.seek_head()
for record in journal_reader:
print(record.data['MESSAGE'])from cysystemd.reader import JournalReader, JournalOpenMode, Rule
rules = (
Rule("SYSLOG_IDENTIFIER", "CRON") &
Rule("_SYSTEMD_UNIT", "crond.service") |
Rule("_SYSTEMD_UNIT", "cron.service")
)
cron_reader = JournalReader()
cron_reader.open(JournalOpenMode.SYSTEM)
cron_reader.seek_head()
cron_reader.add_filter(rules)
for record in cron_reader:
print(record.data['MESSAGE'])from cysystemd.reader import JournalReader, JournalOpenMode
reader = JournalReader()
reader.open(JournalOpenMode.SYSTEM)
reader.seek_tail()
poll_timeout = 255
while True:
reader.wait(poll_timeout)
for record in reader:
print(record.data['MESSAGE'])- CURRENT_USER
- LOCAL_ONLY
- RUNTIME_ONLY
- SYSTEM
- SYSTEM_ONLY
from cysystemd.reader import JournalReader, JournalOpenMode
reader = JournalReader()
reader.open(JournalOpenMode.CURRENT_USER)JournalEntry class has some special properties and methods:
data- journal entry content (dict)date- entry timestamp (datetimeinstance)cursor- systemd identification bytes for this entryboot_id()- returns bootidget_realtime_sec()- entry epoch (float)get_realtime_usec()- entry epoch (intmicroseconds)get_monotonic_sec()- entry monotonic time (float)get_monotonic_usec()- entry monotonic time (intmicroseconds)__getitem__(key)- shoutcut forentry.data[key]
JournalReader class has some special properties and methods:
open(flags=JournalOpenMode.CURRENT_USER)- opening journald with selected modeopen_directory(path)- opening journald from pathopen_files(*filename)- opening journald from filesdata_threshold- may be used to get or set the data field size threshold for data returned by fething entry data.closed- returns True when journal reader closedlocked- returns True when journal reader lockedidle- returns True when journal reader openedseek_head- move reader pointer to the first entryseek_tail- move reader pointer to the last entryseek_monotonic_usec- seeks to the entry with the specified monotonic timestamp, i.e. CLOCK_MONOTONIC. Since monotonic time restarts on every reboot a boot ID needs to be specified as well.seek_realtime_usec- seeks to the entry with the specified realtime (wallclock) timestamp, i.e. CLOCK_REALTIME. Note that the realtime clock is not necessarily monotonic. If a realtime timestamp is ambiguous, it is not defined which position is sought to.seek_cursor- seeks to the entry located at the specified cursor (seeJournalEntry.cursor).wait(timeout)- It will synchronously wait until the journal gets changed. The maximum time this call sleeps may be controlled with the timeout_usec parameter.__iter__- returns JournalReader object__next__- callsnext()or raiseStopIterationnext(skip=0)- returns the nextJournalEntry. Theskipparameter skips some entries.previous(skip=0)- returns the previousJournalEntry. Theskipparameter skips some entries.skip_next(skip)- skips next entries.skip_previous(skip)- skips next entries.add_filter(rule)- adding filter rule. See read-only-cron-logs as example.clear_filter- reset all filtersfd- returns a special file descriptorevents- returnsEPOLLeventstimeout- returns internal timeoutprocess_events()- After each poll() wake-up process_events() needs to be called to process events. This call will also indicate what kind of change has been detected.get_catalog()- retrieves a message catalog entry for the current journal entry. This will look up an entry in the message catalog by using the "MESSAGE_ID=" field of the current journal entry. Before returning the entry all journal field names in the catalog entry text enclosed in "@" will be replaced by the respective field values of the current entry. If a field name referenced in the message catalog entry does not exist, in the current journal entry, the "@" will be removed, but the field name otherwise left untouched.get_catalog_for_message_id(message_id: UUID)- works similar toget_catalog()but the entry is looked up by the specified message ID (no open journal context is necessary for this), and no field substitution is performed.