# Copyright (c) 2014 SUSE LLC. # All Rights Reserved. # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 or 3 of the GNU General # Public License as published by the Free Software Foundation. # 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 about this file by physical or electronic mail, # you may find current contact information at www.suse.com require "y2journal/journalctl_exception" require "shellwords" module Y2Journal # Wrapper for journalctl invocation class Journalctl # Agent used internally BASH_SCR_PATH = Yast::Path.new(".target.bash_output") # Format understood by journalctl options TIME_FORMAT = "%Y-%m-%d %H:%M:%S".freeze # Ordered list of priority values supported by journalctl PRIORITIES = ["emerg", "alert", "crit", "err", "warning", "notice", "info", "debug"].freeze attr_reader :options, :matches # @param options [Hash] The keys are options of the journalctl command like # "boot" or "no-pager" (the long option name should be used). The values # are the corresponding values for the option and can be: # # * nil for options without an expected value # * a scalar value (numbers and times/dates would be converted to the # format expected by the journalctl command) # * an array of escalars for options that can be specified multiple times # # @param matches [Array] list of journalctl matches # # @example Kernel messages in the last minute for a given device and units # Journalctl.new( # { # "since" => Time.now - 60, # "unit" => ["local-fs.target", "swap.target"], # "dmesg" => nil # }, # ["/dev/sda"] # ) def initialize(options = {}, matches = []) @options = options @matches = matches end # Full journalctl command def command "SYSTEMD_COLORS='' LANG=C /usr/bin/journalctl #{options_string} #{matches_string}".strip.squeeze(" ") end # Output resulting of executing the command def output cmd_result = Yast::SCR.Execute(BASH_SCR_PATH, command) if cmd_result["exit"].zero? cmd_result["stdout"] elsif cmd_result["stderr"] =~ /^Failed to .* timestamp:/ # Most likely, journalctl bug when an empty list is found "" else raise JournalctlException, cmd_result["stderr"] end end private def options_string return @options_string if @option_string strings = [] @options.each_pair do |option, value| if value.nil? strings << "--#{option.to_s.shellescape}" else # In order to handle options with multiple values, make sure it's an # array and remove nils (they make no sense with multiple values) values = [value].flatten.compact values.each do |v| v = v.strftime(TIME_FORMAT) if v.respond_to?(:strftime) strings << "--#{option.to_s.shellescape}=#{v.to_s.shellescape}" end end end @options_string = strings.join(" ") end def matches_string @matches_string ||= @matches.map(&:shellescape).join(" ") end end end