1

I'm looking for a way to query the information provided by journalctl -b and journalctl --list-boots through python systemd module.

I've written a workaround which runs journalctl as a subprocess and parses the output. Maybe there's some more obvious way.

import datetime
import re
import subprocess
from systemd import journal

def parse_datetime_data(data):
    datetimedata_no_tz = data[0:data.rindex(" ")]
    datetimedata_tz = data[data.rindex(" ")+1:-1]

    datetimeValue = datetime.datetime.strptime(datetimedata_no_tz, 
                                               "%a %Y-%m-%d %X")
    return datetimeValue, datetimedata_tz

def get_bootlines():
    bootlinesRaw = subprocess.check_output(['journalctl', '--list-boots', 
                                            '--no-pager'],
                                           encoding="utf-8").splitlines()
    boots = {}

    for bootlineRaw in bootlinesRaw:
        if bootlineRaw:
            lt = re.findall('^ *(-?\d+) (\w+) ([\w -:]+).([\w -:]+)',
                            bootlineRaw)
            linedata = lt[0]

            startdata = linedata[2]
            bootstart,bootstart_tz = parse_datetime_data(startdata)

            enddata = linedata[3]
            bootend,bootend_tz = parse_datetime_data(enddata)

            boots[int(linedata[0])] = {"BOOT_ID":linedata[1],
                                 "start": bootstart, "start_tz": bootstart_tz,
                                 "end": bootstart, "end_tz": bootend_tz}

    return boots

boots = get_bootlines()

c.holtermann
  • 113
  • 1
  • 9
  • 1
    For future reference, see `subprocess.check_output()` – you don't need to poll and read a subprocess by hand just to get the output... – AKX Sep 08 '22 at 10:57
  • 1
    No need to decode by hand either. `check_output(..., encoding="utf-8").splitlines()` :) – AKX Sep 08 '22 at 11:10
  • 1
    (Also, if you don't want to bother with parsing timezones, set the `TZ=UTC` envvar when you call `journalctl` and it will output UTC times.) – AKX Sep 08 '22 at 11:21

1 Answers1

2

By the looks of it, neither systemd.journal or the underlying native module expose an API for listing boots.

(You can use the _BOOT_ID matcher for the journal reader API once you do have a boot id at hand though.)

Looking at the source for journalctl, what --list-boots does is it iterates over all known journal entries and keeps the unique boot IDs and their first and last timestamps, so you could do that in your Python code too.

As an aside, with systemd >= 251 you can just do

>>> import json
>>> import subprocess
>>> json.loads(subprocess.check_output(["journalctl", "--output=json", "--list-boots"]))
[{'index': 0, 'boot_id': '5ab8a0b2e2624bcdba4d51d83a7a4fe2', 'first_entry': 1658396953303255, 'last_entry': 1662635352510679}]
AKX
  • 152,115
  • 15
  • 115
  • 172