Patrick Williams | b8c5eae | 2022-12-05 14:35:02 -0600 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Andrew Geissler | 19672b6 | 2018-02-07 12:33:02 -0600 | [diff] [blame] | 2 | |
| 3 | r""" |
Nagaraju Goruganti | c1a00af | 2018-11-07 00:52:11 -0600 | [diff] [blame] | 4 | BMC FFDC will at times include the journal in json format |
Andrew Geissler | 19672b6 | 2018-02-07 12:33:02 -0600 | [diff] [blame] | 5 | (journalctl -o json-pretty ). This is a quick and dirty script which |
| 6 | will convert that json output into the standard journalctl output |
| 7 | """ |
| 8 | |
Manojkiran Eda | c17b438 | 2025-06-10 11:22:04 +0530 | [diff] [blame^] | 9 | import datetime |
Andrew Geissler | 19672b6 | 2018-02-07 12:33:02 -0600 | [diff] [blame] | 10 | import json |
| 11 | import re |
Andrew Geissler | 19672b6 | 2018-02-07 12:33:02 -0600 | [diff] [blame] | 12 | from argparse import ArgumentParser |
Manojkiran Eda | c17b438 | 2025-06-10 11:22:04 +0530 | [diff] [blame^] | 13 | from datetime import timezone |
Andrew Geissler | 19672b6 | 2018-02-07 12:33:02 -0600 | [diff] [blame] | 14 | |
Andrew Geissler | 964ae7b | 2018-11-14 12:30:01 -0600 | [diff] [blame] | 15 | |
Andrew Geissler | 19672b6 | 2018-02-07 12:33:02 -0600 | [diff] [blame] | 16 | def jpretty_to_python(buf): |
| 17 | entries = [] |
| 18 | |
Patrick Williams | b8c5eae | 2022-12-05 14:35:02 -0600 | [diff] [blame] | 19 | for entry in re.findall("^{$(.+?)^}$", buf, re.DOTALL | re.MULTILINE): |
| 20 | entries += [json.loads("{{{}}}".format(entry))] |
Andrew Geissler | 19672b6 | 2018-02-07 12:33:02 -0600 | [diff] [blame] | 21 | |
| 22 | return entries |
| 23 | |
Andrew Geissler | 964ae7b | 2018-11-14 12:30:01 -0600 | [diff] [blame] | 24 | |
Manojkiran Eda | c17b438 | 2025-06-10 11:22:04 +0530 | [diff] [blame^] | 25 | def format_timestamp_utc(us_timestamp, use_utc=False): |
| 26 | """Convert microseconds since epoch to formatted timestamp (with microseconds).""" |
| 27 | ts = float(us_timestamp) / 1000000 |
| 28 | tz = timezone.utc if use_utc else None |
| 29 | dt = datetime.datetime.fromtimestamp(ts, tz) |
| 30 | return dt.strftime("%b %d %H:%M:%S.%f") |
| 31 | |
| 32 | |
Patrick Williams | b8c5eae | 2022-12-05 14:35:02 -0600 | [diff] [blame] | 33 | if __name__ == "__main__": |
Andrew Geissler | 19672b6 | 2018-02-07 12:33:02 -0600 | [diff] [blame] | 34 | parser = ArgumentParser() |
| 35 | parser.add_argument( |
Patrick Williams | b8c5eae | 2022-12-05 14:35:02 -0600 | [diff] [blame] | 36 | "journalfile", metavar="FILE", help="the file to parse" |
| 37 | ) |
Manojkiran Eda | c17b438 | 2025-06-10 11:22:04 +0530 | [diff] [blame^] | 38 | parser.add_argument( |
| 39 | "--localtime", |
| 40 | action="store_true", |
| 41 | help="Display timestamps in local time (default is UTC)", |
| 42 | ) |
Andrew Geissler | 19672b6 | 2018-02-07 12:33:02 -0600 | [diff] [blame] | 43 | args = parser.parse_args() |
| 44 | |
| 45 | with open(args.journalfile) as fd: |
| 46 | entries = jpretty_to_python(fd.read()) |
Patrick Williams | b8c5eae | 2022-12-05 14:35:02 -0600 | [diff] [blame] | 47 | entries = sorted(entries, key=lambda k: k["__REALTIME_TIMESTAMP"]) |
Andrew Geissler | 19672b6 | 2018-02-07 12:33:02 -0600 | [diff] [blame] | 48 | |
| 49 | for e in entries: |
Manojkiran Eda | c17b438 | 2025-06-10 11:22:04 +0530 | [diff] [blame^] | 50 | e["ts"] = format_timestamp_utc( |
| 51 | e["__REALTIME_TIMESTAMP"], use_utc=not args.localtime |
| 52 | ) |
Andrew Geissler | 964ae7b | 2018-11-14 12:30:01 -0600 | [diff] [blame] | 53 | try: |
Patrick Williams | b8c5eae | 2022-12-05 14:35:02 -0600 | [diff] [blame] | 54 | print( |
| 55 | f'{e["ts"]} {e["_HOSTNAME"]} {e["SYSLOG_IDENTIFIER"]}:' |
| 56 | f' {e["MESSAGE"]}' |
| 57 | ) |
| 58 | except Exception: |
| 59 | print("Unable to parse msg: " + str(e)) |
Andrew Geissler | 964ae7b | 2018-11-14 12:30:01 -0600 | [diff] [blame] | 60 | continue |