globalog 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/globalog.rb +110 -0
- data/lib/globalog_args.rb +50 -0
- data/lib/globalog_hijack.rb +51 -0
- data/test/external_helper.rb +25 -0
- data/test/tc_globalog_main.rb +126 -0
- metadata +57 -0
data/lib/globalog.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# This gem aims to provide a global cascading logging system, command line arguments aware,
|
2
|
+
# to centralize the settings of your individual loggers.
|
3
|
+
#
|
4
|
+
# It is thought to be compatible with other gems using OptionParser to collect command line arguments, by hijacking the ARGV at require time before others grabs it. (So, it must be required before say, 'Test/Unit' to hijack the ARGV).
|
5
|
+
#
|
6
|
+
# Each individual logger can follow the setting's cascade, or not. If it does, the command line arguments or the first globalog to setup its parameters have precedence over the local settings. And in case no other globalog is setup is present, the local parameters are used for logging.
|
7
|
+
#
|
8
|
+
# It is essentially compatible with existing Logger, because it uses logger as it base lib. So all logging is done the same way, with all of logger instance methods also working on globalog instances. You can then transition code logged with logger easily, by either replacing the Logger initialisation in your code by a GlobaLog initialisation, or by leaving logger where it is and only deriving its output and level settings from globalog class methods of the same names, still allowing you to tap into globalog cascading settings.
|
9
|
+
#
|
10
|
+
# The logging in Globalog is done with Logger so please refer to its documentation for the logging methodologies: http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/
|
11
|
+
#
|
12
|
+
# ///////////////////////////////////////////////////////////////////////////////////////
|
13
|
+
# Example:
|
14
|
+
#
|
15
|
+
# # script1.rb
|
16
|
+
# require 'globalog'
|
17
|
+
# $log = GlobaLog.logger(STDERR,:warn)
|
18
|
+
#
|
19
|
+
# module Script1
|
20
|
+
# def example
|
21
|
+
# $log.warn("Example") {"Printing Warning!!"}
|
22
|
+
# $log.info("Example") {"Printing Info!!"}
|
23
|
+
# $log.debug("Example") {"Printing Debug!!"}
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# calling the example method will result in:
|
28
|
+
#
|
29
|
+
# Script1.example # => Printing Warning!!
|
30
|
+
#
|
31
|
+
# But if you require script1, inside an other script, setting different GlobaLog init parameters, they will have precedence and cascade down as in the example below.
|
32
|
+
#
|
33
|
+
# # script2.rb
|
34
|
+
# require 'globalog'
|
35
|
+
# require 'script1'
|
36
|
+
#
|
37
|
+
# $log = GlobaLog.logger(STDERR,:info)
|
38
|
+
# Script1.example
|
39
|
+
#
|
40
|
+
# running script2 will output:
|
41
|
+
#
|
42
|
+
# > ruby script2.rb
|
43
|
+
# => Printing Warning!!
|
44
|
+
# => Printing Info!!
|
45
|
+
#
|
46
|
+
# And you can also run script2 with arguments to get different log level or output:
|
47
|
+
#
|
48
|
+
# > ruby script2.rb -L debug
|
49
|
+
# => Printing Warning!!
|
50
|
+
# => Printing Info!!
|
51
|
+
# => Printing Debug!!
|
52
|
+
#
|
53
|
+
# So this allow you to set a default Logger setting in your libraries, override them with an other default setting in client scripts and still get the flexibility to override both defaults at runtime by providing command line arguments. Ideal for testing purposes where you want a default log level for test overriding the Local log level of your tested libraries, while allowing you to choose the test log level at runtime.
|
54
|
+
#
|
55
|
+
#
|
56
|
+
# Author:: lp (mailto:lp@spiralix.org)
|
57
|
+
# Copyright:: 2009 Louis-Philippe Perron - Released under the terms of the MIT license
|
58
|
+
#
|
59
|
+
# :title:GlobaLog
|
60
|
+
|
61
|
+
require 'logger'
|
62
|
+
class GlobaLog < Logger
|
63
|
+
require 'globalog_args'
|
64
|
+
require 'globalog_hijack'
|
65
|
+
|
66
|
+
# The +GlobaLog.logger+ acts as a constructor method for the logger.
|
67
|
+
# === Parameters
|
68
|
+
# * _def_out_ = the output io or logfile path
|
69
|
+
# * _def_level_ = the log level, as a symbol (i.e. :warn, :info, etc)
|
70
|
+
# * _master_ = (optional) the logger presence in the cascading settings chain
|
71
|
+
# _master_ can be any of the following:
|
72
|
+
# * _true_ = Impose its settings on the loggers down the chain
|
73
|
+
# * _false_ = Use the chain settings if present (default)
|
74
|
+
# * _nil_ = Is out of the chain
|
75
|
+
# === Example
|
76
|
+
# @log = GlobaLog.logger('logfile.txt',:error,true)
|
77
|
+
|
78
|
+
def GlobaLog.logger(def_out,def_level,master=false)
|
79
|
+
Args.are({:log_output => def_out, :log_level => def_level},master)
|
80
|
+
if master.nil?
|
81
|
+
log = self.new(def_out)
|
82
|
+
log.level = Args.sym_to_level(def_level)
|
83
|
+
else
|
84
|
+
log = self.new(Args::log_output)
|
85
|
+
log.level = Args::log_level
|
86
|
+
end
|
87
|
+
return log
|
88
|
+
end
|
89
|
+
|
90
|
+
# The +GlobaLog::output+ method return the current log output.
|
91
|
+
# Can be used to chain existing Logger instances to GlobaLog cascade,
|
92
|
+
# when you don't want to replace them with GlobaLog instances.
|
93
|
+
# (and you can only replace the constructor, the logging will still work)
|
94
|
+
# === Example
|
95
|
+
# $logger = Logger.new(GlobaLog::output)
|
96
|
+
def GlobaLog::output
|
97
|
+
Args::log_output
|
98
|
+
end
|
99
|
+
|
100
|
+
# The +Globalog::level+ method returns the current log level.
|
101
|
+
# Can be used to chain existing Logger instances to GlobaLog cascade,
|
102
|
+
# when you don't want to replace them with GlobaLog instances.
|
103
|
+
# (and you can only replace the constructor, the logging will still work)
|
104
|
+
# === Example
|
105
|
+
# $logger.level = GlobaLog::level
|
106
|
+
def GlobaLog::level
|
107
|
+
Args::log_level
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class GlobaLog
|
2
|
+
# The Args module manages the GlobaLog arguments in the background.
|
3
|
+
# Author:: lp (mailto:lp@spiralix.org)
|
4
|
+
# Copyright:: 2009 Louis-Philippe Perron - Released under the terms of the MIT license
|
5
|
+
#
|
6
|
+
# :title:GlobaLog/Args
|
7
|
+
module Args
|
8
|
+
|
9
|
+
def Args.are(args,override=false)
|
10
|
+
$logger_args ||= Hash.new
|
11
|
+
if override == true
|
12
|
+
$logger_args[:log_level] = args[:log_level].to_sym unless args[:log_level].nil?
|
13
|
+
$logger_args[:log_output] = args[:log_output] unless args[:log_output].nil?
|
14
|
+
else
|
15
|
+
$logger_args[:log_level] ||= args[:log_level].to_sym unless args[:log_level].nil?
|
16
|
+
$logger_args[:log_output] ||= args[:log_output] unless args[:log_output].nil?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def Args::log_output
|
21
|
+
$logger_args[:log_output]
|
22
|
+
end
|
23
|
+
|
24
|
+
def Args::log_level
|
25
|
+
if $logger_args[:log_level].is_a?(Symbol)
|
26
|
+
$logger_args[:log_level] = self.sym_to_level($logger_args[:log_level])
|
27
|
+
end
|
28
|
+
$logger_args[:log_level]
|
29
|
+
end
|
30
|
+
|
31
|
+
def Args.sym_to_level(sym)
|
32
|
+
case sym
|
33
|
+
when :debug
|
34
|
+
return Logger::DEBUG
|
35
|
+
when :info
|
36
|
+
return Logger::INFO
|
37
|
+
when :warn
|
38
|
+
return Logger::WARN
|
39
|
+
when :error
|
40
|
+
return Logger::ERROR
|
41
|
+
when :fatal
|
42
|
+
return Logger::FATAL
|
43
|
+
else
|
44
|
+
return Logger::UNKNOWN
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class GlobaLog
|
2
|
+
# The Hijack class manages the acquisition of command line arguments,
|
3
|
+
# playing nicely with other command line aware libs.
|
4
|
+
# Author:: lp (mailto:lp@spiralix.org)
|
5
|
+
# Copyright:: 2009 Louis-Philippe Perron - Released under the terms of the MIT license
|
6
|
+
#
|
7
|
+
# :title:GlobaLog/Hijack
|
8
|
+
class Hijack < Hash
|
9
|
+
require 'optparse'
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super()
|
13
|
+
self[:log_level] = nil
|
14
|
+
self[:log_output] = nil
|
15
|
+
opts = OptionParser.new do |opts|
|
16
|
+
opts.on('-L','--log-level [STRING]','sets the Test Log Level') do |string|
|
17
|
+
self[:log_level] = string.to_sym
|
18
|
+
end
|
19
|
+
opts.on('-O','--log-output [I/O]','sets the Test Log output') do |io|
|
20
|
+
self[:log_output] = io
|
21
|
+
end
|
22
|
+
end
|
23
|
+
opts.parse!($keep_argv)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.keep_wanted_argv
|
27
|
+
args = Array.new(ARGV); ARGV.clear; keep = []
|
28
|
+
wanted = ['-L', '--log-level', '-O', '--log-output']
|
29
|
+
catch :finished do
|
30
|
+
loop do
|
31
|
+
throw :finished if args.empty?
|
32
|
+
catch :found do
|
33
|
+
wanted.each do |arg|
|
34
|
+
if args[0] == arg
|
35
|
+
2.times { keep << args.shift }
|
36
|
+
throw :found
|
37
|
+
end
|
38
|
+
end
|
39
|
+
ARGV << args.shift
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
$keep_argv ||= keep
|
44
|
+
end
|
45
|
+
|
46
|
+
self.keep_wanted_argv
|
47
|
+
Args.are(self.new)
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module LogMessage
|
2
|
+
|
3
|
+
def log_all_level(identifier)
|
4
|
+
@log.debug('test') {"#{identifier} -- debug"}
|
5
|
+
@log.info('test') {"#{identifier} -- info"}
|
6
|
+
@log.warn('test') {"#{identifier} -- warn"}
|
7
|
+
@log.error('test') {"#{identifier} -- error"}
|
8
|
+
@log.fatal('test') {"#{identifier} -- fatal"}
|
9
|
+
@log.unknown('test') {"#{identifier} -- unknown"}
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
class External
|
15
|
+
include LogMessage
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@log = GlobaLog.logger(STDERR,:warn)
|
19
|
+
end
|
20
|
+
|
21
|
+
def log
|
22
|
+
log_all_level('external')
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'globalog'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
require 'test/external_helper'
|
6
|
+
|
7
|
+
class TestGlobaLogMain < Test::Unit::TestCase
|
8
|
+
include LogMessage
|
9
|
+
$test_file = 'test_log'
|
10
|
+
|
11
|
+
def setup
|
12
|
+
File.new($test_file,'w').close
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_globalog
|
16
|
+
output = STDERR
|
17
|
+
level = :error
|
18
|
+
@log = GlobaLog.logger(output,level,true)
|
19
|
+
assert_equal(output,GlobaLog::output)
|
20
|
+
assert_equal(3,GlobaLog::level)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_globalog_debug
|
24
|
+
prepare_test(:debug)
|
25
|
+
check_test(:debug)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_globalog_info
|
29
|
+
prepare_test(:info)
|
30
|
+
check_test(:info)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_globalog_warn
|
34
|
+
prepare_test(:warn)
|
35
|
+
check_test(:warn)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_globalog_error
|
39
|
+
prepare_test(:error)
|
40
|
+
check_test(:error)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_globalog_fatal
|
44
|
+
prepare_test(:fatal)
|
45
|
+
check_test(:fatal)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_globalog_unknown
|
49
|
+
prepare_test(:unknown)
|
50
|
+
check_test(:unknown)
|
51
|
+
end
|
52
|
+
|
53
|
+
def teardown
|
54
|
+
@log.close
|
55
|
+
File.delete($test_file)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def prepare_test(level)
|
61
|
+
@log = GlobaLog.logger($test_file,level,true)
|
62
|
+
log_all_level('base test')
|
63
|
+
pid1 = fork {log_all_level('fork 1'); exit}
|
64
|
+
pid2 = fork {log_all_level('fork 2'); exit}
|
65
|
+
Process.waitpid(pid2,0)
|
66
|
+
External.new().log
|
67
|
+
end
|
68
|
+
|
69
|
+
def check_test(level)
|
70
|
+
f = File.open($test_file,'r'); content = f.read; f.close
|
71
|
+
check_players(content)
|
72
|
+
check_level(level,content)
|
73
|
+
end
|
74
|
+
|
75
|
+
def check_players(content)
|
76
|
+
assert_match(/base/,content)
|
77
|
+
assert_match(/fork 1/,content)
|
78
|
+
assert_match(/fork 2/,content)
|
79
|
+
assert_match(/external/,content)
|
80
|
+
end
|
81
|
+
|
82
|
+
def check_level(level,content)
|
83
|
+
level_match = match_assertions(content)
|
84
|
+
level_no_match = no_match_assertions(content)
|
85
|
+
case level
|
86
|
+
when :debug
|
87
|
+
0.upto(5) { |num| level_match[num].call }
|
88
|
+
when :info
|
89
|
+
0.upto(4) { |num| level_match[num].call }
|
90
|
+
5.downto(5) { |num| level_no_match[num].call }
|
91
|
+
when :warn
|
92
|
+
0.upto(3) { |num| level_match[num].call }
|
93
|
+
5.downto(4) { |num| level_no_match[num].call }
|
94
|
+
when :error
|
95
|
+
0.upto(2) { |num| level_match[num].call }
|
96
|
+
5.downto(3) { |num| level_no_match[num].call }
|
97
|
+
when :fatal
|
98
|
+
0.upto(1) { |num| level_match[num].call }
|
99
|
+
5.downto(2) { |num| level_no_match[num].call }
|
100
|
+
when :unknown
|
101
|
+
0.upto(0) { |num| level_match[num].call }
|
102
|
+
5.downto(1) { |num| level_no_match[num].call }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def match_assertions(content)
|
107
|
+
[ lambda { assert_match(/unknown/,content) },
|
108
|
+
lambda { assert_match(/fatal/,content) },
|
109
|
+
lambda { assert_match(/error/,content) },
|
110
|
+
lambda { assert_match(/warn/,content) },
|
111
|
+
lambda { assert_match(/info/,content) },
|
112
|
+
lambda { assert_match(/debug/,content) } ]
|
113
|
+
end
|
114
|
+
|
115
|
+
def no_match_assertions(content)
|
116
|
+
[ lambda { assert_no_match(/unknown/,content) },
|
117
|
+
lambda { assert_no_match(/fatal/,content) },
|
118
|
+
lambda { assert_no_match(/error/,content) },
|
119
|
+
lambda { assert_no_match(/warn/,content) },
|
120
|
+
lambda { assert_no_match(/info/,content) },
|
121
|
+
lambda { assert_no_match(/debug/,content) } ]
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: globalog
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Louis-Philippe Perron
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-12 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: lp@spiralix.org
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/globalog.rb
|
26
|
+
- lib/globalog_args.rb
|
27
|
+
- lib/globalog_hijack.rb
|
28
|
+
- test/external_helper.rb
|
29
|
+
- test/tc_globalog_main.rb
|
30
|
+
has_rdoc: true
|
31
|
+
homepage: http://globalog.rubyforge.org/
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: "0"
|
42
|
+
version:
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "0"
|
48
|
+
version:
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
rubyforge_project: GlobaLog
|
52
|
+
rubygems_version: 1.2.0
|
53
|
+
signing_key:
|
54
|
+
specification_version: 2
|
55
|
+
summary: Cascading Global Log
|
56
|
+
test_files:
|
57
|
+
- test/tc_globalog_main.rb
|