systemd wrapper in Cython
=========================
.. image:: https://img.shields.io/pypi/v/cysystemd.svg
:target: https://pypi.python.org/pypi/cysystemd/
:alt: Latest Version
.. image:: https://img.shields.io/pypi/wheel/cysystemd.svg
:target: https://pypi.python.org/pypi/cysystemd/
.. image:: https://img.shields.io/pypi/pyversions/cysystemd.svg
:target: https://pypi.python.org/pypi/cysystemd/
.. image:: https://img.shields.io/pypi/l/cysystemd.svg
:target: https://pypi.python.org/pypi/cysystemd/
Python systemd wrapper using Cython
.. contents:: Table of contents
Installation
------------
All packages available on
`github releases <https://github.com/mosquito/cysystemd/releases>`_.
Installation from binary wheels
+++++++++++++++++++++++++++++++
* wheels is now available for Python 3.7, 3.8, 3.9, 3.10, 3.11
for `x86_64` and `arm64`
.. code-block:: bash
pythonn3.9 -m pip install \
https://github.com/mosquito/cysystemd/releases/download/1.4.8/cysystemd-1.4.8-cp39-cp39-manylinux2014_x86_64.whl
Installation from sources
+++++++++++++++++++++++++
You **must** install **systemd headers**
For Debian/Ubuntu users:
.. code-block:: bash
apt install build-essential libsystemd-dev
On older versions of Debian/Ubuntu, you might also need to install:
.. code-block:: bash
apt install libsystemd-daemon-dev libsystemd-journal-dev
For CentOS/RHEL
.. code-block:: bash
yum install gcc systemd-devel
And install it from pypi
.. code-block:: bash
pip install cysystemd
Usage examples
--------------
Writing to journald
+++++++++++++++++++
Logging handler for python logger
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: python
from cysystemd import journal
import logging
import uuid
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger()
logger.addHandler(journal.JournaldLogHandler())
try:
logger.info("Trying to do something")
raise Exception('foo')
except:
logger.exception("Test Exception %s", 1)
systemd daemon notification
~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: python
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
.. code-block:: python
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',
)
Reading journald
++++++++++++++++
Reading all systemd records
~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: python
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'])
Read only cron logs
~~~~~~~~~~~~~~~~~~~
.. _read-only-cron-logs:
.. code-block:: python
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'])
Polling records
~~~~~~~~~~~~~~~
.. code-block:: python
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'])
journald open modes
~~~~~~~~~~~~~~~~~~~
* CURRENT_USER
* LOCAL_ONLY
* RUNTIME_ONLY
* SYSTEM
* SYSTEM_ONLY
.. code-block:: python
from cysystemd.reader import JournalReader, JournalOpenMode
reader = JournalReader()
reader.open(JournalOpenMode.CURRENT_USER)
journald entry
~~~~~~~~~~~~~~
JournalEntry class has some special properties and methods:
* ``data`` - journal entry content (``dict``)
* ``date`` - entry timestamp (``datetime`` instance)
* ``cursor`` - systemd identification bytes for this entry
* ``boot_id()`` - returns bootid
* ``get_realtime_sec()`` - entry epoch (``float``)
* ``get_realtime_usec()`` - entry epoch (``int`` microseconds)
* ``get_monotonic_sec()`` - entry monotonic time (``float``)
* ``get_monotonic_usec()`` - entry monotonic time (``int`` microseconds)
* ``__getitem__(key)`` - shoutcut for ``entry.data[key]``
journald reader
~~~~~~~~~~~~~~~
JournalReader class has some special properties and methods:
* ``open(flags=JournalOpenMode.CURRENT_USER)`` - opening journald
with selected mode
* ``open_directory(path)`` - opening journald from path
* ``open_files(*filename)`` - opening journald from files
* ``data_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 closed
* ``locked`` - returns True when journal reader locked
* ``idle`` - returns True when journal reader opened
* ``seek_head`` - move reader pointer to the first entry
* ``seek_tail`` - move reader pointer to the last entry
* ``seek_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
(see ``JournalEntry.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__`` - calls ``next()`` or raise ``StopIteration``
* ``next(skip=0)`` - returns the next ``JournalEntry``. The ``skip``
parameter skips some entries.
* ``previous(skip=0)`` - returns the previous ``JournalEntry``.
The ``skip`` parameter 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 filters
* ``fd`` - returns a special file descriptor
* ``events`` - returns ``EPOLL`` events
* ``timeout`` - returns internal timeout
* ``process_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 to
``get_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.
Asyncio support
+++++++++++++++
Initial ``asyncio`` support for reading journal asynchronously.
AsyncJournalReader
~~~~~~~~~~~~~~~~~~
Blocking methods were wrapped by threads.
Method ``wait()`` use epoll on journald file descriptor.
.. code-block:: python
import asyncio
import json
from cysystemd.reader import JournalOpenMode
from cysystemd.async_reader import AsyncJournalReader
async def main():
reader = AsyncJournalReader()
await reader.open(JournalOpenMode.SYSTEM)
await reader.seek_tail()
while await reader.wait():
async for record in reader:
print(
json.dumps(
record.data,
indent=1,
sort_keys=True
)
)
if __name__ == '__main__':
asyncio.run(main())
Raw data
{
"_id": null,
"home_page": "http://github.com/mosquito/cysystemd",
"name": "cysystemd",
"maintainer": "",
"docs_url": null,
"requires_python": ">3.6, <4",
"maintainer_email": "",
"keywords": "systemd,python,daemon,sd_notify,cython",
"author": "Dmitry Orlov <me@mosquito.su>",
"author_email": "me@mosquito.su",
"download_url": "https://files.pythonhosted.org/packages/02/53/352dd6725329b2ed58ec20525e765d273e2ad6b2af76c0a7684b0c03b5d8/cysystemd-1.6.0.tar.gz",
"platform": "POSIX",
"description": "systemd wrapper in Cython\n=========================\n\n.. image:: https://img.shields.io/pypi/v/cysystemd.svg\n :target: https://pypi.python.org/pypi/cysystemd/\n :alt: Latest Version\n\n.. image:: https://img.shields.io/pypi/wheel/cysystemd.svg\n :target: https://pypi.python.org/pypi/cysystemd/\n\n.. image:: https://img.shields.io/pypi/pyversions/cysystemd.svg\n :target: https://pypi.python.org/pypi/cysystemd/\n\n.. image:: https://img.shields.io/pypi/l/cysystemd.svg\n :target: https://pypi.python.org/pypi/cysystemd/\n\n\nPython systemd wrapper using Cython\n\n\n.. contents:: Table of contents\n\n\nInstallation\n------------\n\nAll packages available on\n`github releases <https://github.com/mosquito/cysystemd/releases>`_.\n\nInstallation from binary wheels\n+++++++++++++++++++++++++++++++\n\n* wheels is now available for Python 3.7, 3.8, 3.9, 3.10, 3.11\n for `x86_64` and `arm64`\n\n.. code-block:: bash\n\n pythonn3.9 -m pip install \\\n https://github.com/mosquito/cysystemd/releases/download/1.4.8/cysystemd-1.4.8-cp39-cp39-manylinux2014_x86_64.whl\n\nInstallation from sources\n+++++++++++++++++++++++++\n\nYou **must** install **systemd headers**\n\nFor Debian/Ubuntu users:\n\n.. code-block:: bash\n\n apt install build-essential libsystemd-dev\n\nOn older versions of Debian/Ubuntu, you might also need to install:\n\n.. code-block:: bash\n\n apt install libsystemd-daemon-dev libsystemd-journal-dev\n\nFor CentOS/RHEL\n\n.. code-block:: bash\n\n yum install gcc systemd-devel\n\n\nAnd install it from pypi\n\n.. code-block:: bash\n\n pip install cysystemd\n\n\nUsage examples\n--------------\n\nWriting to journald\n+++++++++++++++++++\n\nLogging handler for python logger\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n from cysystemd import journal\n import logging\n import uuid\n\n logging.basicConfig(level=logging.DEBUG)\n logger = logging.getLogger()\n logger.addHandler(journal.JournaldLogHandler())\n\n try:\n logger.info(\"Trying to do something\")\n raise Exception('foo')\n except:\n logger.exception(\"Test Exception %s\", 1)\n\n\nsystemd daemon notification\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\n.. code-block:: python\n\n from cysystemd.daemon import notify, Notification\n\n # Send READY=1\n notify(Notification.READY)\n\n # Send status\n notify(Notification.STATUS, \"I'm fine.\")\n\n # Send stopping\n notify(Notification.STOPPING)\n\n\nWrite message into systemd journal\n\n\n.. code-block:: python\n\n from cysystemd import journal\n\n\n journal.write(\"Hello Lennart\")\n\n # Or send structured data\n journal.send(\n message=\"Hello Lennart\",\n priority=journal.Priority.INFO,\n some_field='some value',\n )\n\n\nReading journald\n++++++++++++++++\n\nReading all systemd records\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n from cysystemd.reader import JournalReader, JournalOpenMode\n\n journal_reader = JournalReader()\n journal_reader.open(JournalOpenMode.SYSTEM)\n journal_reader.seek_head()\n\n for record in journal_reader:\n print(record.data['MESSAGE'])\n\n\nRead only cron logs\n~~~~~~~~~~~~~~~~~~~\n\n.. _read-only-cron-logs:\n\n.. code-block:: python\n\n from cysystemd.reader import JournalReader, JournalOpenMode, Rule\n\n\n rules = (\n Rule(\"SYSLOG_IDENTIFIER\", \"CRON\") &\n Rule(\"_SYSTEMD_UNIT\", \"crond.service\") |\n Rule(\"_SYSTEMD_UNIT\", \"cron.service\")\n )\n\n cron_reader = JournalReader()\n cron_reader.open(JournalOpenMode.SYSTEM)\n cron_reader.seek_head()\n cron_reader.add_filter(rules)\n\n for record in cron_reader:\n print(record.data['MESSAGE'])\n\n\nPolling records\n~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n from cysystemd.reader import JournalReader, JournalOpenMode\n\n\n reader = JournalReader()\n reader.open(JournalOpenMode.SYSTEM)\n reader.seek_tail()\n\n poll_timeout = 255\n\n while True:\n reader.wait(poll_timeout)\n\n for record in reader:\n print(record.data['MESSAGE'])\n\n\njournald open modes\n~~~~~~~~~~~~~~~~~~~\n\n* CURRENT_USER\n* LOCAL_ONLY\n* RUNTIME_ONLY\n* SYSTEM\n* SYSTEM_ONLY\n\n\n.. code-block:: python\n\n from cysystemd.reader import JournalReader, JournalOpenMode\n\n reader = JournalReader()\n reader.open(JournalOpenMode.CURRENT_USER)\n\n\njournald entry\n~~~~~~~~~~~~~~\n\nJournalEntry class has some special properties and methods:\n\n* ``data`` - journal entry content (``dict``)\n* ``date`` - entry timestamp (``datetime`` instance)\n* ``cursor`` - systemd identification bytes for this entry\n* ``boot_id()`` - returns bootid\n* ``get_realtime_sec()`` - entry epoch (``float``)\n* ``get_realtime_usec()`` - entry epoch (``int`` microseconds)\n* ``get_monotonic_sec()`` - entry monotonic time (``float``)\n* ``get_monotonic_usec()`` - entry monotonic time (``int`` microseconds)\n* ``__getitem__(key)`` - shoutcut for ``entry.data[key]``\n\n\njournald reader\n~~~~~~~~~~~~~~~\n\nJournalReader class has some special properties and methods:\n\n* ``open(flags=JournalOpenMode.CURRENT_USER)`` - opening journald\n with selected mode\n* ``open_directory(path)`` - opening journald from path\n* ``open_files(*filename)`` - opening journald from files\n* ``data_threshold`` - may be used to get or set the data field size threshold\n for data returned by fething entry data.\n* ``closed`` - returns True when journal reader closed\n* ``locked`` - returns True when journal reader locked\n* ``idle`` - returns True when journal reader opened\n* ``seek_head`` - move reader pointer to the first entry\n* ``seek_tail`` - move reader pointer to the last entry\n* ``seek_monotonic_usec`` - seeks to the entry with the specified monotonic\n timestamp, i.e. CLOCK_MONOTONIC. Since monotonic time restarts on every\n reboot a boot ID needs to be specified as well.\n* ``seek_realtime_usec`` - seeks to the entry with the specified realtime\n (wallclock) timestamp, i.e. CLOCK_REALTIME. Note that the realtime clock\n is not necessarily monotonic. If a realtime timestamp is ambiguous, it is\n not defined which position is sought to.\n* ``seek_cursor`` - seeks to the entry located at the specified cursor\n (see ``JournalEntry.cursor``).\n* ``wait(timeout)`` - It will synchronously wait until the journal gets\n changed. The maximum time this call sleeps may be controlled with the\n timeout_usec parameter.\n* ``__iter__`` - returns JournalReader object\n* ``__next__`` - calls ``next()`` or raise ``StopIteration``\n* ``next(skip=0)`` - returns the next ``JournalEntry``. The ``skip``\n parameter skips some entries.\n* ``previous(skip=0)`` - returns the previous ``JournalEntry``.\n The ``skip`` parameter skips some entries.\n* ``skip_next(skip)`` - skips next entries.\n* ``skip_previous(skip)`` - skips next entries.\n* ``add_filter(rule)`` - adding filter rule.\n See `read-only-cron-logs`_ as example.\n* ``clear_filter`` - reset all filters\n* ``fd`` - returns a special file descriptor\n* ``events`` - returns ``EPOLL`` events\n* ``timeout`` - returns internal timeout\n* ``process_events()`` - After each poll() wake-up process_events() needs\n to be called to process events. This call will also indicate what kind of\n change has been detected.\n* ``get_catalog()`` - retrieves a message catalog entry for the current\n journal entry. This will look up an entry in the message catalog by using\n the \"MESSAGE_ID=\" field of the current journal entry. Before returning\n the entry all journal field names in the catalog entry text enclosed in\n \"@\" will be replaced by the respective field values of the current entry.\n If a field name referenced in the message catalog entry does not exist,\n in the current journal entry, the \"@\" will be removed, but the field name\n otherwise left untouched.\n* ``get_catalog_for_message_id(message_id: UUID)`` - works similar to\n ``get_catalog()`` but the entry is looked up by the specified\n message ID (no open journal context is necessary for this),\n and no field substitution is performed.\n\n\nAsyncio support\n+++++++++++++++\n\nInitial ``asyncio`` support for reading journal asynchronously.\n\nAsyncJournalReader\n~~~~~~~~~~~~~~~~~~\n\nBlocking methods were wrapped by threads.\nMethod ``wait()`` use epoll on journald file descriptor.\n\n.. code-block:: python\n\n import asyncio\n import json\n\n from cysystemd.reader import JournalOpenMode\n from cysystemd.async_reader import AsyncJournalReader\n\n\n async def main():\n reader = AsyncJournalReader()\n await reader.open(JournalOpenMode.SYSTEM)\n await reader.seek_tail()\n\n while await reader.wait():\n async for record in reader:\n print(\n json.dumps(\n record.data,\n indent=1,\n sort_keys=True\n )\n )\n\n if __name__ == '__main__':\n asyncio.run(main())\n\n\n",
"bugtrack_url": null,
"license": "Apache",
"summary": "systemd wrapper in Cython",
"version": "1.6.0",
"project_urls": {
"Homepage": "http://github.com/mosquito/cysystemd"
},
"split_keywords": [
"systemd",
"python",
"daemon",
"sd_notify",
"cython"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "0253352dd6725329b2ed58ec20525e765d273e2ad6b2af76c0a7684b0c03b5d8",
"md5": "0c60a93210541e86dd79487f7cd994f9",
"sha256": "5224dd8fee146de08528bbf685edb177568246c7728bbb548b2257c9a44a2454"
},
"downloads": -1,
"filename": "cysystemd-1.6.0.tar.gz",
"has_sig": false,
"md5_digest": "0c60a93210541e86dd79487f7cd994f9",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">3.6, <4",
"size": 296041,
"upload_time": "2023-12-04T14:28:11",
"upload_time_iso_8601": "2023-12-04T14:28:11.916206Z",
"url": "https://files.pythonhosted.org/packages/02/53/352dd6725329b2ed58ec20525e765d273e2ad6b2af76c0a7684b0c03b5d8/cysystemd-1.6.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-04 14:28:11",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "mosquito",
"github_project": "cysystemd",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "cysystemd"
}