You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Python systemd模块实现journalctl -b与--list-boots功能?

使用Python的systemd模块直接获取journalctl启动信息

你完全可以跳过子进程调用和文本解析,直接通过systemd.journal模块与journald交互,获取journalctl --list-boots和journalctl -b的结构化数据,这种方式更可靠、高效,还能避免正则解析依赖输出格式的脆弱性。

替代方案代码

1. 获取所有启动记录(对应journalctl --list-boots)

import datetime
from systemd import journal

def get_boot_info():
    boots = {}
    j = journal.Journal()
    # 获取所有唯一的启动ID
    boot_ids = j.get_unique('_BOOT_ID')
    
    # 反转顺序,匹配journalctl --list-boots的索引规则:0是最新启动,-1是上一次,以此类推
    for idx, boot_id in enumerate(reversed(boot_ids)):
        boot_idx = -(len(boot_ids) - 1 - idx) if idx != len(boot_ids)-1 else 0
        
        # 查询该启动的最早日志(启动时间)
        j.seek_head()
        j.add_match(_BOOT_ID=boot_id)
        j.move_next()
        start_ts = j.get_current_entry()['__REALTIME_TIMESTAMP'] / 1e6
        start_time = datetime.datetime.fromtimestamp(start_ts).astimezone()
        
        # 查询该启动的最晚日志(结束时间,当前启动则为最新日志时间)
        j.seek_tail()
        j.add_match(_BOOT_ID=boot_id)
        j.move_previous()
        end_ts = j.get_current_entry()['__REALTIME_TIMESTAMP'] / 1e6
        end_time = datetime.datetime.fromtimestamp(end_ts).astimezone()
        
        boots[boot_idx] = {
            "BOOT_ID": boot_id,
            "start": start_time,
            "start_tz": start_time.tzname(),
            "end": end_time,
            "end_tz": end_time.tzname()
        }
    return boots

# 使用示例
boot_list = get_boot_info()
for idx, info in boot_list.items():
    print(f"启动 {idx}:")
    print(f"  BOOT_ID: {info['BOOT_ID']}")
    print(f"  启动时间: {info['start']}")
    print(f"  结束时间: {info['end']}")

2. 获取指定启动的日志(对应journalctl -b <启动索引>)

def get_boot_journal(boot_idx=0):
    boot_info = get_boot_info()
    target_boot_id = boot_info[boot_idx]['BOOT_ID']
    
    j = journal.Journal()
    j.add_match(_BOOT_ID=target_boot_id)
    
    # 遍历并收集日志条目
    journal_entries = []
    for entry in j:
        journal_entries.append({
            "timestamp": datetime.datetime.fromtimestamp(entry['__REALTIME_TIMESTAMP']/1e6).astimezone(),
            "unit": entry.get('UNIT', '未知单元'),
            "message": entry.get('MESSAGE', '')
        })
    return journal_entries

# 使用示例:获取当前启动的日志
current_boot_logs = get_boot_journal(0)

方案优势

  • 可靠性更高:无需依赖journalctl的文本输出格式,避免版本更新导致解析失效
  • 结构化数据:直接获取日志条目字段,无需手动拆分字符串、解析时间
  • 性能更优:直接与journald进程通信,省去子进程启动和输出传输的开销

原代码小问题说明

你的代码中有一处笔误:"end": bootstart应该改为"end": bootend,否则结束时间会错误复用启动时间。

内容的提问来源于stack exchange,提问作者c.holtermann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 04:35:25