38

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')

vvvvv
  • 25,404
  • 19
  • 49
  • 81
guettli
  • 25,042
  • 81
  • 346
  • 663

4 Answers4

48

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")
martineg
  • 1,269
  • 13
  • 14
  • 1
    Could you help take a look at this: http://stackoverflow.com/questions/40748156/python3-journal-logging-does-not-show-log-level? – user180574 Nov 22 '16 at 17:44
  • 1
    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()) – alireza Feb 04 '18 at 13:43
  • 1
    Is there no way to set the **unit**? This is a very serious limitation. – Federico Jul 10 '19 at 16:30
  • 3
    @Federico I can't find a way to set the unit, but you can do `JournalHandler(SYSLOG_IDENTIFIER=)`, and then `` 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](https://github.com/systemd/python-systemd/blob/a402d08da41413507a4ebebf18de897f7ddf1dd2/systemd/journal.py#L562-L563)). However, this doesn't create a `` unit, so `journalctl -u ` doesn't produce any output. But you can filter the `` msgs with `journalctl SYSLOG_IDENTIFIER=`. – ntc2 Jun 06 '20 at 05:10
  • 1
    Note that confusingly, the package name on pypi is actually [systemd-python](https://pypi.org/project/systemd-python/) not python-systemd – Eskander Bejaoui Jun 13 '21 at 19:14
  • JournalHandler has been renamed to JournaldLogHandler, like in the other answer – Romain Nov 09 '21 at 08:36
13

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")
bschlueter
  • 3,817
  • 1
  • 30
  • 48
  • @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: https://gist.github.com/schlueter/ce1f2e32ef350bfa21e1b8b8605711b6. – bschlueter Jun 18 '18 at 03:13
  • I'm having trouble finding additional logging options, other than `log.info(message)`. Are there equivalent methods, like `log.warning(message)`? – charliesneath Mar 14 '19 at 11:35
  • @charliesneath 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 https://docs.python.org/3.7/library/logging.html. – bschlueter Mar 15 '19 at 05:22
  • The official package is widely available and recommended. – Federico Feb 13 '21 at 00:39
  • @Federico I stated no opinion on whether to use this, it's just an option which I encountered. – bschlueter Feb 16 '21 at 20:16
  • @bschlueter to clarify: it's recommended by systemd. – Federico Feb 18 '21 at 02:32
  • @Federico 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. – bschlueter Feb 18 '21 at 21:12
  • On my system `journal.write()` does not exist but `journal.send("Hello Lennart")` works! – carloslockward Mar 21 '22 at 22:52
5

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')
Joe
  • 6,758
  • 2
  • 26
  • 47
  • Messages also show up in journald with the default `sys.stderr` stream for me. – Dominik Nov 28 '21 at 16:18
  • I like vanilla solutions :)) – Nacho R Feb 16 '22 at 18:09
  • cannot confirm that, neither by using stderr not stdout – ataraxis Oct 11 '22 at 22:50
  • 1
    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. – Osman-pasha Jul 06 '23 at 09:32
  • Yes, that's correct. It depends on the context the code is running in. – Joe Jul 06 '23 at 09:51
-1

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()
```
Livio
  • 53
  • 1
  • 3