Skip to content

Commit

Permalink
added Y2Logger - Ruby Logger for writing logs using the Yast format
Browse files Browse the repository at this point in the history
- can be used by external libraries for logging into y2log
- 3.1.18
  • Loading branch information
lslezak committed Feb 2, 2014
1 parent 66de35c commit 66a9294
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 5 deletions.
4 changes: 2 additions & 2 deletions library/log/Makefile.am
@@ -1,3 +1,3 @@
#
# Makefile.am for yast2/sequencer
SUBDIRS = doc src
# Makefile.am for library/log
SUBDIRS = doc src test
8 changes: 6 additions & 2 deletions library/log/src/Makefile.am
Expand Up @@ -5,6 +5,10 @@ module_DATA = \
modules/LogView.rb \
modules/LogViewCore.rb

EXTRA_DIST = $(module_DATA)
ylibdir = @ylibdir@/log
ylib_DATA = \
lib/log/y2logger.rb

include $(top_srcdir)/Makefile.am.common
EXTRA_DIST = $(module_DATA) $(ylib_DATA)

include $(top_srcdir)/Makefile.am.common
101 changes: 101 additions & 0 deletions library/log/src/lib/log/y2logger.rb
@@ -0,0 +1,101 @@
# encoding: utf-8

require 'logger'
require 'singleton'
require 'socket'

module Yast

# A Ruby Logger which logs in usual Yast y2log formatting
class Y2Logger < ::Logger

SEVERITY_MAPPING = {
DEBUG => 0,
INFO => 1,
WARN => 2,
ERROR => 3,
FATAL => 3,
UNKNOWN => 5
}

# redefine the format to the y2log format
def format_message(severity, timestamp, progname, msg)
# remove the function name from the caller location
location = caller(3).first.gsub(/:in `.*'$/, "")
"#{timestamp.strftime(datetime_format)} #{severity} #{Socket.gethostname}(#{Process.pid}) #{progname} #{location} #{msg}\n"
end

def initialize(*args)
super
self.datetime_format = "%Y-%m-%d %H:%M:%S"
self.progname = "[Ruby]"
# TODO: it does not support changing the level at runtime,
# e.g. via Shift-F7 magic key
self.level = ENV["Y2DEBUG"] == "1" ? ::Logger::DEBUG : ::Logger::INFO
end

private

# redefine severity formatting
def format_severity(severity)
"<#{SEVERITY_MAPPING[severity] || 5}>"
end
end

# Provides the global shared Y2logger instance writing to /var/log/YaST2/y2log
# (or ~/.y2log if the file is not writable).
#
# It can be used for logging external Ruby code into y2log
#
# @example Allow external code to log into y2log
# # this depends on the target library, see it's documentation how to set the logger
# FooBar::Logger.instance.log = YastLogger.instance.log
# Baz.set_logger(YastLogger.instance.log)
class YastLogger
include Singleton

Y2LOGFILE = "/var/log/YaST2/y2log"

attr_accessor :log

def initialize
# Yast compatibility - log to home if not running as root
# (of if the file is not writable)
if File.exist?(Y2LOGFILE)
log_file = File.writable?(Y2LOGFILE) ? Y2LOGFILE : "#{ENV['HOME']}/.y2log"
else
log_file = File.writable?(File.dirname(Y2LOGFILE)) ? Y2LOGFILE : "#{ENV['HOME']}/.y2log"
end

# when creating the log file make sure it is readable only by the user
# (it might contain sensitive data like passwords, registration code, etc.)
File.write(log_file, "", { :perm => 0600 }) unless File.exist?(log_file)

@log = Yast::Y2Logger.new(log_file)
end
end

# This module provides access to Yast specific logging
#
# @example Use YastLogger in an easy way
# require "log/y2logger"
# class Foo
# include Yast::Logger
#
# def foo
# # this will be logged into y2log using the usual y2log format
# log.debug "debug"
# log.error "error"
# end
# end
module Logger
def log
YastLogger.instance.log
end

def self.included(base)
base.extend self
end
end

end
8 changes: 8 additions & 0 deletions library/log/test/Makefile.am
@@ -0,0 +1,8 @@
TESTS = \
y2logger_test.rb

TEST_EXTENSIONS = .rb
RB_LOG_COMPILER = rspec
VERBOSE = 1

EXTRA_DIST = $(TESTS)
126 changes: 126 additions & 0 deletions library/log/test/y2logger_test.rb
@@ -0,0 +1,126 @@
#!/usr/bin/env rspec

require_relative "../src/lib/log/y2logger.rb"

# for logging into a string instead of a file
require "stringio"
# gethostname
require "socket"

module Yast
describe Y2Logger do
before do
# log into a string to easily test the result
@log = StringIO.new
@test_logger = Y2Logger.new(@log)
end

it "logs the passed message" do
@test_logger.info "@@@ Testing @@@"
expect(log).to match "@@@ Testing @@@"
end

it "logs with [Ruby] component" do
@test_logger.info "Testing"
expect(log).to match "[Ruby]"
end

it "logs info messages with '<1>' level" do
@test_logger.info "Testing"
expect(log).to match "<1>"
end

it "logs warnings with '<2>' level" do
@test_logger.warn "Testing"
expect(log).to match "<2>"
end

it "logs errors with '<3>' level" do
@test_logger.error "Testing"
expect(log).to match "<3>"
end

it "logs fatal errors with '<3>' level" do
@test_logger.fatal "Testing"
expect(log).to match "<3>"
end

it "logs the hostname" do
@test_logger.info "Testing"
expect(log).to match Socket.gethostname
end

it "logs the process ID (PID)" do
@test_logger.info "Testing"
expect(log).to match "(#{Process.pid})"
end

it "logs the file location into the log" do
@test_logger.info "Testing"
expect(log).to match "#{__FILE__}:#{__LINE__ - 1}"
end

it "logs in y2log compatible format" do
@test_logger.info "Testing"
expect(log).to match /\A\d+-\d+-\d+ \d+:\d+:\d+ <1> #{Socket.gethostname}\(#{Process.pid}\) \[Ruby\] #{__FILE__}:\d+ Testing$/
end

context "when Y2DEBUG is not set" do
before do
ENV.stub(:[]).with("Y2DEBUG").and_return(nil)
@test_logger = Y2Logger.new(@log)
end

it "does not log debug messages" do
@test_logger.debug "Testing"
expect(log).to eq ""
end

it "logs info messages with '<1>' level" do
@test_logger.info "Testing"
expect(log).to match "<1>"
end
end

context "when Y2DEBUG is set" do
before do
ENV.stub(:[]).with("Y2DEBUG").and_return("1")
@test_logger = Y2Logger.new(@log)
end

it "logs debug messages with '<0>' level" do
@test_logger.debug "Testing"
expect(log).to match "<0>"
end

it "logs info messages with '<1>' level" do
@test_logger.info "Testing"
expect(log).to match "<1>"
end
end

# helper method to read the logged value
def log
# read the created log from string
@log.rewind
@log.read
end
end

describe YastLogger do
it "returns a Logger class instance" do
expect(YastLogger.instance.log).to be_kind_of(::Logger)
end
end

describe Yast::Logger do
it "module adds log() method for accessing the Logger" do
class Test
include Yast::Logger
end
expect(Test.log).to be_kind_of(::Logger)
expect(Test.new.log).to be_kind_of(::Logger)
end
end

end
7 changes: 7 additions & 0 deletions package/yast2.changes
@@ -1,3 +1,10 @@
-------------------------------------------------------------------
Fri Jan 31 21:12:49 UTC 2014 - lslezak@suse.cz

- added Y2Logger - Ruby Logger for writing logs using the Yast
format, can be used by external libraries for logging into y2log
- 3.1.18

-------------------------------------------------------------------
Thu Jan 30 09:27:43 UTC 2014 - mfilka@suse.com

Expand Down
3 changes: 2 additions & 1 deletion package/yast2.spec
Expand Up @@ -17,7 +17,7 @@


Name: yast2
Version: 3.1.17
Version: 3.1.18
Release: 0

BuildRoot: %{_tmppath}/%{name}-%{version}-build
Expand Down Expand Up @@ -208,6 +208,7 @@ mkdir -p "$RPM_BUILD_ROOT"/etc/YaST2
%{yast_ydatadir}/*.ycp
%{yast_clientdir}/*
%{yast_moduledir}/*
%{yast_libdir}/*
%{yast_scrconfdir}/*
%{yast_ybindir}/*
%{yast_agentdir}/ag_*
Expand Down

0 comments on commit 66a9294

Please sign in to comment.