如何通过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
相关产品推荐
相关产品推荐

