How to log to journald (systemd) via Python?
Asked Answered
P

4

41

I would like logging.info() to go to journald (systemd).

Up to now I only found python modules which read journald (not what I want) or modules which work like this: journal.send('Hello world')

Petree answered 4/1, 2016 at 9:51 Comment(0)
E
54

python-systemd has a JournalHandler you can use with the logging framework.

From the documentation:

import logging
from systemd.journal import JournalHandler

log = logging.getLogger('demo')
log.addHandler(JournalHandler())
log.setLevel(logging.INFO)
log.info("sent to journal")
Emma answered 4/1, 2016 at 10:33 Comment(6)
Could you help take a look at this: #40748656?Venetic
from systemd.journal import JournalHandler has error, instead : from systemd import journal import logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger() logger.addHandler(journal.JournaldLogHandler())Abydos
Is there no way to set the unit? This is a very serious limitation.Subsolar
@Subsolar I can't find a way to set the unit, but you can do JournalHandler(SYSLOG_IDENTIFIER=<id>), and then <id> is used for the unit/id field in the corresponding log entries (if you don't set this, then the file name is used by default; see the source). However, this doesn't create a <id> unit, so journalctl -u <id> doesn't produce any output. But you can filter the <id> msgs with journalctl SYSLOG_IDENTIFIER=<id>.Desexualize
Note that confusingly, the package name on pypi is actually systemd-python not python-systemdPortend
JournalHandler has been renamed to JournaldLogHandler, like in the other answerVeliavelick
C
15

An alternative to the official package, the systemd package works with python 3.6. Its source is also on github.

The implementation is a mirror of the official lib, with some minor changes:

import logging
from systemd import journal

log = logging.getLogger('demo')
log.addHandler(journal.JournaldLogHandler())
log.setLevel(logging.INFO)
log.info("sent to journal")

or for an even shorter method:

from systemd import journal

journal.write("Hello Lennart")
Cumber answered 5/3, 2017 at 4:2 Comment(8)
@Rob I'm not sure what's up with your system, but this definitely works. I created a simple example Vagrantfile which will start a system with python 3.5, install the systemd package, and execute the example: gist.github.com/schlueter/ce1f2e32ef350bfa21e1b8b8605711b6.Cumber
I'm having trouble finding additional logging options, other than log.info(message). Are there equivalent methods, like log.warning(message)?Roller
@Roller The logger class is unrelated to the systemd package except that it is the interface by which the systemd package is used. See its documentation at docs.python.org/3.7/library/logging.html.Cumber
The official package is widely available and recommended.Subsolar
@Subsolar I stated no opinion on whether to use this, it's just an option which I encountered.Cumber
@bschlueter to clarify: it's recommended by systemd.Subsolar
@Subsolar Cool. Not everyone can just use the libraries recommended by the organizations which maintain the tools they use. Sometimes they can't because those libraries are missing a feature they need. This is one of the advantages of open source software that you can always make your own version of something or something new entirely. Or you can use library recommended by some entity. Your choice.Cumber
On my system journal.write() does not exist but journal.send("Hello Lennart") works!Chastise
M
4

This is a solution without third party modules. It works fine for me and the messages show up in journald.

import logging
import sys

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# this is just to make the output look nice
formatter = logging.Formatter(fmt="%(asctime)s %(name)s.%(levelname)s: %(message)s", datefmt="%Y.%m.%d %H:%M:%S")

# this logs to stdout and I think it is flushed immediately
handler = logging.StreamHandler(stream=sys.stdout)
handler.setFormatter(formatter)
logger.addHandler(handler)

logger.info('test')
Macy answered 26/11, 2021 at 17:53 Comment(5)
Messages also show up in journald with the default sys.stderr stream for me.Spense
I like vanilla solutions :))Yecies
cannot confirm that, neither by using stderr not stdoutTommi
this code does nothing related to journald. You are probably forgetting to mention that you run a script as a systemd service, and in that case systemd will collect stdout and stderr from a program and pass it to journald anyway, so you can even use print and it will still end up in journald.Hatbox
Yes, that's correct. It depends on the context the code is running in.Macy
M
-2

This is an alternative solution without third party modules

import subprocess

data = "sent to journal"
echoCmd = ["echo", data]
sysdCat = ["systemd-cat", "-p", "info"]

echoResult = subprocess.Popen(echoCmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
sysdCatResult = subprocess.Popen(sysdCat, stdin=echoResult.stdout)
sysdCatResult.communicate()
```
Meadowlark answered 18/1, 2023 at 20:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.