#!/bin/bash # # Copyright (c) [2026] SUSE LLC # # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, contact SUSE LLC. # # To contact SUSE LLC about this file by physical or electronic mail, you may # find current contact information at www.suse.com. # Helper script which prints the messages from the systemd journal with # additional details like code location. # All script arguments are passed to journalctl, you can use it to filter the # displayed messages, e.g. filter by unit with '-u sshd.service', filter by time # with '--since "5 minutes ago"' or show only errors and higher priority with # '-p err'.. # The timestamps are printed in the local time, to print the UTC time # run with TZ=UTC. Hint: You can set any time zone, e.g. TZ=America/New_York. # It accepts special "--input-file " parameter to load the data from # previously saved journal in JSON format. # Use colors if the output goes to a terminal if [ -t 1 ]; then USE_COLORS="true" else USE_COLORS="false" fi SHOW_MICROSECONDS="false" INPUT_FILE="" JOURNAL_ARGS=() while [ $# -gt 0 ]; do case "$1" in # Allow using a JSON file as input --input-file) INPUT_FILE="$2" shift 2 ;; --microseconds) SHOW_MICROSECONDS="true" shift ;; *) JOURNAL_ARGS+=("$1") shift ;; esac done process_logs() { if [ -n "$INPUT_FILE" ]; then cat "$INPUT_FILE" else journalctl -o json "$@" fi | jq --unbuffered --arg use_colors "$USE_COLORS" --arg show_microseconds "$SHOW_MICROSECONDS" -r ' # Helper function to get color based on priority def get_color: { "0": "\u001b[1;91m", # Emergency - Bold Bright Red "1": "\u001b[1;91m", # Alert - Bold Bright Red "2": "\u001b[1;91m", # Critical - Bold Bright Red "3": "\u001b[1;31m", # Error - Bold Red "4": "\u001b[93m", # Warning - Bright Yellow "5": "\u001b[1m", # Notice - Bold white "6": "", # Informational - Default "7": "\u001b[90m" # Debug - Grey }[tostring] // ""; # Helper function to format timestamp def format_timestamp: # The journal time is in microseconds (tonumber / 1000000 | strflocaltime("%b %e %H:%M:%S")) + (if $show_microseconds == "true" then "." + (tostring | .[-6:]) else "" end); # Helper function to build the source code location string def format_location: [ (.CODE_FILE | select(. != null and . != "") | tostring), (.CODE_FUNC | select(. != null and . != "") | "(" + tostring + ")"), (.CODE_LINE | select(. != null and . != "") | ":" + tostring + ":") ] | join("") | select(. != ""); # Helper function to combine syslog identifier and PID def format_syslog_pid: [ (.SYSLOG_IDENTIFIER | select(. != null and . != "")), (._PID | select(. != null and . != "") | "[" + tostring + "]:") ] | join("") | select(. != ""); # Join the requested fields into a single line (.PRIORITY | get_color) as $color | [ (.__REALTIME_TIMESTAMP | select(. != null and . != "") | format_timestamp), (.PRIORITY | select(. != null and . != "") | "<" + tostring + ">"), format_syslog_pid, format_location, (.ZYPP_GROUP | select(. != null and . != "") | "[" + tostring + "]"), (.MESSAGE | select(. != null and . != "") | tostring | if $use_colors == "true" and $color != "" then $color + . + "\u001b[0m" else . end) ] # Remove any missing/empty values and join them with a space | map(select(. != null and . != "")) | join(" ") ' } if [ "$USE_COLORS" = "true" ] && [ -n "$PAGER" ]; then process_logs "${JOURNAL_ARGS[@]}" | $PAGER else process_logs "${JOURNAL_ARGS[@]}" fi