TwP-logging 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +169 -0
- data/README.rdoc +102 -0
- data/Rakefile +42 -0
- data/data/bad_logging_1.rb +13 -0
- data/data/bad_logging_2.rb +21 -0
- data/data/logging.rb +42 -0
- data/data/logging.yaml +63 -0
- data/data/simple_logging.rb +13 -0
- data/lib/logging.rb +408 -0
- data/lib/logging/appender.rb +303 -0
- data/lib/logging/appenders/buffering.rb +167 -0
- data/lib/logging/appenders/console.rb +62 -0
- data/lib/logging/appenders/email.rb +75 -0
- data/lib/logging/appenders/file.rb +54 -0
- data/lib/logging/appenders/growl.rb +197 -0
- data/lib/logging/appenders/io.rb +69 -0
- data/lib/logging/appenders/rolling_file.rb +291 -0
- data/lib/logging/appenders/syslog.rb +201 -0
- data/lib/logging/config/configurator.rb +190 -0
- data/lib/logging/config/yaml_configurator.rb +195 -0
- data/lib/logging/layout.rb +119 -0
- data/lib/logging/layouts/basic.rb +34 -0
- data/lib/logging/layouts/pattern.rb +296 -0
- data/lib/logging/log_event.rb +51 -0
- data/lib/logging/logger.rb +490 -0
- data/lib/logging/repository.rb +172 -0
- data/lib/logging/root_logger.rb +61 -0
- data/lib/logging/stats.rb +278 -0
- data/lib/logging/utils.rb +130 -0
- data/logging.gemspec +41 -0
- data/test/appenders/test_buffered_io.rb +183 -0
- data/test/appenders/test_console.rb +66 -0
- data/test/appenders/test_email.rb +171 -0
- data/test/appenders/test_file.rb +93 -0
- data/test/appenders/test_growl.rb +128 -0
- data/test/appenders/test_io.rb +142 -0
- data/test/appenders/test_rolling_file.rb +207 -0
- data/test/appenders/test_syslog.rb +194 -0
- data/test/benchmark.rb +87 -0
- data/test/config/test_configurator.rb +70 -0
- data/test/config/test_yaml_configurator.rb +40 -0
- data/test/layouts/test_basic.rb +43 -0
- data/test/layouts/test_pattern.rb +177 -0
- data/test/setup.rb +74 -0
- data/test/test_appender.rb +166 -0
- data/test/test_layout.rb +110 -0
- data/test/test_log_event.rb +80 -0
- data/test/test_logger.rb +734 -0
- data/test/test_logging.rb +267 -0
- data/test/test_repository.rb +126 -0
- data/test/test_root_logger.rb +81 -0
- data/test/test_stats.rb +274 -0
- data/test/test_utils.rb +116 -0
- metadata +156 -0
@@ -0,0 +1,190 @@
|
|
1
|
+
|
2
|
+
module Logging::Config
|
3
|
+
|
4
|
+
# The Configurator class is used to configure the Logging framework
|
5
|
+
# using information found in a block of Ruby code. This block is evaluated
|
6
|
+
# in the context of the configurator's DSL.
|
7
|
+
#
|
8
|
+
class Configurator
|
9
|
+
|
10
|
+
class Error < StandardError; end # :nodoc:
|
11
|
+
|
12
|
+
# call-seq:
|
13
|
+
# Configuraotr.process( &block )
|
14
|
+
#
|
15
|
+
def self.process( &block )
|
16
|
+
new.load(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
# call-seq:
|
20
|
+
# load { block }
|
21
|
+
#
|
22
|
+
# Loads the configuration from the _block_ and configures the Logging
|
23
|
+
# gem.
|
24
|
+
#
|
25
|
+
def load( &block )
|
26
|
+
raise Error, "missing configuration block" unless block
|
27
|
+
|
28
|
+
dsl = TopLevelDSL.new
|
29
|
+
dsl.__instance_eval(&block)
|
30
|
+
|
31
|
+
pre_config dsl.__pre_config
|
32
|
+
::Logging::Logger[:root] # ensures the log levels are defined
|
33
|
+
appenders dsl.__appenders
|
34
|
+
loggers dsl.__loggers
|
35
|
+
end
|
36
|
+
|
37
|
+
# call-seq:
|
38
|
+
# pre_config( config )
|
39
|
+
#
|
40
|
+
# Configures the logging levels, object format style, and root logging
|
41
|
+
# level.
|
42
|
+
#
|
43
|
+
def pre_config( config )
|
44
|
+
if config.nil?
|
45
|
+
::Logging.init unless ::Logging.const_defined? 'MAX_LEVEL_LENGTH'
|
46
|
+
return
|
47
|
+
end
|
48
|
+
|
49
|
+
# define levels
|
50
|
+
levels = config[:levels]
|
51
|
+
::Logging.init(levels) unless levels.nil?
|
52
|
+
|
53
|
+
# format as
|
54
|
+
format = config[:format_as]
|
55
|
+
::Logging.format_as(format) unless format.nil?
|
56
|
+
|
57
|
+
# backtrace
|
58
|
+
value = config[:backtrace]
|
59
|
+
::Logging.backtrace(value) unless value.nil?
|
60
|
+
end
|
61
|
+
|
62
|
+
# call-seq:
|
63
|
+
# appenders( ary )
|
64
|
+
#
|
65
|
+
# Given an array of Appender configurations, this method will iterate
|
66
|
+
# over each and create the Appender(s).
|
67
|
+
#
|
68
|
+
def appenders( ary )
|
69
|
+
ary.each {|name, config| appender(name, config)}
|
70
|
+
end
|
71
|
+
|
72
|
+
# call-seq:
|
73
|
+
# loggers( ary )
|
74
|
+
#
|
75
|
+
# Given an array of Logger configurations, this method will iterate over
|
76
|
+
# each and create the Logger(s).
|
77
|
+
#
|
78
|
+
def loggers( ary )
|
79
|
+
ary.each do |name, config|
|
80
|
+
l = Logging::Logger[name]
|
81
|
+
l.level = config[:level] if config[:level]
|
82
|
+
l.additive = config[:additive] if l.respond_to? :additive=
|
83
|
+
l.trace = config[:trace]
|
84
|
+
l.appenders = Array(config[:appenders]).
|
85
|
+
map {|name| ::Logging::Appender[name]}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# call-seq:
|
90
|
+
# appender( name, config )
|
91
|
+
#
|
92
|
+
# Creates a new Appender based on the given _config_ options (a hash).
|
93
|
+
# The type of Appender created is determined by the 'type' option in the
|
94
|
+
# config. The remaining config options are passed to the Appender
|
95
|
+
# initializer.
|
96
|
+
#
|
97
|
+
# The config options can also contain a 'layout' option. This should be
|
98
|
+
# another set of options used to create a Layout for this Appender.
|
99
|
+
#
|
100
|
+
def appender( name, config )
|
101
|
+
type = config.delete(:type)
|
102
|
+
raise Error, "appender type not given for #{name.inspect}" if type.nil?
|
103
|
+
|
104
|
+
config[:layout] = layout(config[:layout]) if config.has_key? :layout
|
105
|
+
|
106
|
+
clazz = ::Logging::Appenders.const_get type
|
107
|
+
clazz.new(name, config)
|
108
|
+
rescue NameError => err
|
109
|
+
raise Error, "unknown appender class Logging::Appenders::#{type}"
|
110
|
+
end
|
111
|
+
|
112
|
+
# call-seq:
|
113
|
+
# layout( config )
|
114
|
+
#
|
115
|
+
# Creates a new Layout based on the given _config_ options (a hash).
|
116
|
+
# The type of Layout created is determined by the 'type' option in the
|
117
|
+
# config. The remaining config options are passed to the Layout
|
118
|
+
# initializer.
|
119
|
+
#
|
120
|
+
def layout( config )
|
121
|
+
return ::Logging::Layouts::Basic.new if config.nil?
|
122
|
+
|
123
|
+
type = config.delete(:type)
|
124
|
+
raise Error, 'layout type not given' if type.nil?
|
125
|
+
|
126
|
+
clazz = ::Logging::Layouts.const_get type
|
127
|
+
clazz.new config
|
128
|
+
rescue NameError => err
|
129
|
+
raise Error, "unknown layout class Logging::Layouts::#{type}"
|
130
|
+
end
|
131
|
+
|
132
|
+
class DSL
|
133
|
+
alias :__instance_eval :instance_eval
|
134
|
+
|
135
|
+
instance_methods.each do |m|
|
136
|
+
undef_method m unless m[%r/^(__|object_id)/]
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.process( &block )
|
140
|
+
dsl = new
|
141
|
+
dsl.__instance_eval(&block)
|
142
|
+
dsl.__hash
|
143
|
+
end
|
144
|
+
|
145
|
+
def __hash
|
146
|
+
@hash ||= Hash.new
|
147
|
+
end
|
148
|
+
|
149
|
+
def method_missing( method, *args, &block )
|
150
|
+
args << DSL.process(&block) if block
|
151
|
+
|
152
|
+
key = method.to_sym
|
153
|
+
value = (1 == args.length ? args.first : args)
|
154
|
+
__store(key, value)
|
155
|
+
end
|
156
|
+
|
157
|
+
def __store( key, value )
|
158
|
+
__hash[key] = value
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class TopLevelDSL < DSL
|
163
|
+
undef_method :method_missing
|
164
|
+
|
165
|
+
def initialize
|
166
|
+
@loggers = []
|
167
|
+
@appenders = []
|
168
|
+
end
|
169
|
+
|
170
|
+
def pre_config( &block )
|
171
|
+
__store(:preconfig, DSL.process(&block))
|
172
|
+
end
|
173
|
+
|
174
|
+
def logger( name, &block )
|
175
|
+
@loggers << [name, DSL.process(&block)]
|
176
|
+
end
|
177
|
+
|
178
|
+
def appender( name, &block )
|
179
|
+
@appenders << [name, DSL.process(&block)]
|
180
|
+
end
|
181
|
+
|
182
|
+
def __pre_config() __hash[:preconfig]; end
|
183
|
+
def __loggers() @loggers; end
|
184
|
+
def __appenders() @appenders; end
|
185
|
+
end
|
186
|
+
|
187
|
+
end # class Configurator
|
188
|
+
end # module Logging::Config
|
189
|
+
|
190
|
+
# EOF
|
@@ -0,0 +1,195 @@
|
|
1
|
+
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Logging
|
5
|
+
module Config
|
6
|
+
|
7
|
+
# The YamlConfigurator class is used to configure the Logging framework
|
8
|
+
# using information found in a YAML file.
|
9
|
+
#
|
10
|
+
class YamlConfigurator
|
11
|
+
|
12
|
+
class Error < StandardError; end # :nodoc:
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
# call-seq:
|
17
|
+
# YamlConfigurator.load( file, key = 'logging_config' )
|
18
|
+
#
|
19
|
+
# Load the given YAML _file_ and use it to configure the Logging
|
20
|
+
# framework. The file can be either a filename, and open File, or an
|
21
|
+
# IO object. If it is the latter two, the File / IO object will not be
|
22
|
+
# closed by this method.
|
23
|
+
#
|
24
|
+
# The configuration will be loaded from the given _key_ in the YAML
|
25
|
+
# stream.
|
26
|
+
#
|
27
|
+
def load( file, key = 'logging_config' )
|
28
|
+
io, close = nil, false
|
29
|
+
case file
|
30
|
+
when String
|
31
|
+
io = File.open(file, 'r')
|
32
|
+
close = true
|
33
|
+
when IO
|
34
|
+
io = file
|
35
|
+
else
|
36
|
+
raise Error, 'expecting a filename or a File'
|
37
|
+
end
|
38
|
+
|
39
|
+
begin
|
40
|
+
new(io, key).load
|
41
|
+
ensure
|
42
|
+
io.close if close
|
43
|
+
end
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end # class << self
|
47
|
+
|
48
|
+
# call-seq:
|
49
|
+
# YamlConfigurator.new( io, key )
|
50
|
+
#
|
51
|
+
# Creates a new YAML configurator that will load the Logging
|
52
|
+
# configuration from the given _io_ stream. The configuration will be
|
53
|
+
# loaded from the given _key_ in the YAML stream.
|
54
|
+
#
|
55
|
+
def initialize( io, key )
|
56
|
+
YAML.load_documents(io) do |doc|
|
57
|
+
@config = doc[key]
|
58
|
+
break if @config.instance_of?(Hash)
|
59
|
+
end
|
60
|
+
|
61
|
+
unless @config.instance_of?(Hash)
|
62
|
+
raise Error, "Key '#{key}' not defined in YAML configuration"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# call-seq:
|
67
|
+
# load
|
68
|
+
#
|
69
|
+
# Loads the Logging configuration from the data loaded from the YAML
|
70
|
+
# file.
|
71
|
+
#
|
72
|
+
def load
|
73
|
+
pre_config @config['pre_config']
|
74
|
+
::Logging::Logger[:root] # ensures the log levels are defined
|
75
|
+
appenders @config['appenders']
|
76
|
+
loggers @config['loggers']
|
77
|
+
end
|
78
|
+
|
79
|
+
# call-seq:
|
80
|
+
# pre_config( config )
|
81
|
+
#
|
82
|
+
# Configures the logging levels, object format style, and root logging
|
83
|
+
# level.
|
84
|
+
#
|
85
|
+
def pre_config( config )
|
86
|
+
# if no pre_config section was given, just create an empty hash
|
87
|
+
# we do this to ensure that some logging levels are always defined
|
88
|
+
config ||= Hash.new
|
89
|
+
|
90
|
+
# define levels
|
91
|
+
levels = config['define_levels']
|
92
|
+
::Logging.init(levels) unless levels.nil?
|
93
|
+
|
94
|
+
# format as
|
95
|
+
format = config['format_as']
|
96
|
+
::Logging.format_as(format) unless format.nil?
|
97
|
+
|
98
|
+
# backtrace
|
99
|
+
value = config['backtrace']
|
100
|
+
::Logging.backtrace(value) unless value.nil?
|
101
|
+
|
102
|
+
# grab the root logger and set the logging level
|
103
|
+
root = ::Logging::Logger.root
|
104
|
+
if config.has_key?('root')
|
105
|
+
root.level = config['root']['level']
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# call-seq:
|
110
|
+
# appenders( ary )
|
111
|
+
#
|
112
|
+
# Given an array of Appender configurations, this method will iterate
|
113
|
+
# over each and create the Appender(s).
|
114
|
+
#
|
115
|
+
def appenders( ary )
|
116
|
+
return if ary.nil?
|
117
|
+
|
118
|
+
ary.each {|h| appender(h)}
|
119
|
+
end
|
120
|
+
|
121
|
+
# call-seq:
|
122
|
+
# loggers( ary )
|
123
|
+
#
|
124
|
+
# Given an array of Logger configurations, this method will iterate over
|
125
|
+
# each and create the Logger(s).
|
126
|
+
#
|
127
|
+
def loggers( ary )
|
128
|
+
return if ary.nil?
|
129
|
+
|
130
|
+
ary.each do |config|
|
131
|
+
name = config['name']
|
132
|
+
raise Error, 'Logger name not given' if name.nil?
|
133
|
+
|
134
|
+
l = Logging::Logger.new name
|
135
|
+
l.level = config['level'] if config.has_key?('level')
|
136
|
+
l.additive = config['additive'] if l.respond_to? :additive=
|
137
|
+
l.trace = config['trace'] if l.respond_to? :trace=
|
138
|
+
|
139
|
+
if config.has_key?('appenders')
|
140
|
+
l.appenders = config['appenders'].map {|n| ::Logging::Appender[n]}
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# call-seq:
|
146
|
+
# appender( config )
|
147
|
+
#
|
148
|
+
# Creates a new Appender based on the given _config_ options (a hash).
|
149
|
+
# The type of Appender created is determined by the 'type' option in the
|
150
|
+
# config. The remaining config options are passed to the Appender
|
151
|
+
# initializer.
|
152
|
+
#
|
153
|
+
# The config options can also contain a 'layout' option. This should be
|
154
|
+
# another set of options used to create a Layout for this Appender.
|
155
|
+
#
|
156
|
+
def appender( config )
|
157
|
+
return if config.nil?
|
158
|
+
config = config.dup
|
159
|
+
|
160
|
+
type = config.delete('type')
|
161
|
+
raise Error, 'Appender type not given' if type.nil?
|
162
|
+
|
163
|
+
name = config.delete('name')
|
164
|
+
raise Error, 'Appender name not given' if name.nil?
|
165
|
+
|
166
|
+
config['layout'] = layout(config.delete('layout'))
|
167
|
+
|
168
|
+
clazz = ::Logging::Appenders.const_get type
|
169
|
+
clazz.new(name, config)
|
170
|
+
end
|
171
|
+
|
172
|
+
# call-seq:
|
173
|
+
# layout( config )
|
174
|
+
#
|
175
|
+
# Creates a new Layout based on the given _config_ options (a hash).
|
176
|
+
# The type of Layout created is determined by the 'type' option in the
|
177
|
+
# config. The remaining config options are passed to the Layout
|
178
|
+
# initializer.
|
179
|
+
#
|
180
|
+
def layout( config )
|
181
|
+
return if config.nil?
|
182
|
+
config = config.dup
|
183
|
+
|
184
|
+
type = config.delete('type')
|
185
|
+
raise Error, 'Layout type not given' if type.nil?
|
186
|
+
|
187
|
+
clazz = ::Logging::Layouts.const_get type
|
188
|
+
clazz.new config
|
189
|
+
end
|
190
|
+
|
191
|
+
end # class YamlConfigurator
|
192
|
+
end # module Config
|
193
|
+
end # module Logging
|
194
|
+
|
195
|
+
# EOF
|
@@ -0,0 +1,119 @@
|
|
1
|
+
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Logging
|
5
|
+
|
6
|
+
# The +Layout+ class provides methods for formatting log events into a
|
7
|
+
# string representation. Layouts are used by Appenders to format log
|
8
|
+
# events before writing them to the logging destination.
|
9
|
+
#
|
10
|
+
# All other Layouts inherit from this class which provides stub methods.
|
11
|
+
# Each subclass should provide a +format+ method. A layout can be used by
|
12
|
+
# more than one +Appender+ so all the methods need to be thread safe.
|
13
|
+
#
|
14
|
+
class Layout
|
15
|
+
|
16
|
+
# call-seq:
|
17
|
+
# Layout.new( :format_as => :string )
|
18
|
+
#
|
19
|
+
# Creates a new layout that will format objecs as strings using the
|
20
|
+
# given <tt>:format_as</tt> style. This can be one of <tt>:string</tt>,
|
21
|
+
# <tt>:inspect</tt>, or <tt>:yaml</tt>. These formatting commands map to
|
22
|
+
# the following object methods:
|
23
|
+
#
|
24
|
+
# * :string => to_s
|
25
|
+
# * :inspect => inspect
|
26
|
+
# * :yaml => to_yaml
|
27
|
+
#
|
28
|
+
# If the format is not specified then the global object format is used
|
29
|
+
# (see Logging#format_as). If the global object format is not specified
|
30
|
+
# then <tt>:string</tt> is used.
|
31
|
+
#
|
32
|
+
def initialize( opts = {} )
|
33
|
+
default = ::Logging.const_defined?('OBJ_FORMAT') ?
|
34
|
+
::Logging::OBJ_FORMAT : nil
|
35
|
+
|
36
|
+
f = opts.getopt(:format_as, default)
|
37
|
+
f = f.intern if f.instance_of? String
|
38
|
+
|
39
|
+
@obj_format = case f
|
40
|
+
when :inspect, :yaml; f
|
41
|
+
else :string end
|
42
|
+
|
43
|
+
b = opts.getopt(:backtrace, ::Logging.backtrace)
|
44
|
+
@backtrace = case b
|
45
|
+
when :on, 'on', true; true
|
46
|
+
when :off, 'off', false; false
|
47
|
+
else
|
48
|
+
raise ArgumentError, "backtrace must be true or false"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# call-seq:
|
53
|
+
# format( event )
|
54
|
+
#
|
55
|
+
# Returns a string representation of the given loggging _event_. It is
|
56
|
+
# up to subclasses to implement this method.
|
57
|
+
#
|
58
|
+
def format( event ) nil end
|
59
|
+
|
60
|
+
# call-seq:
|
61
|
+
# header
|
62
|
+
#
|
63
|
+
# Returns a header string to be used at the beginning of a logging
|
64
|
+
# appender.
|
65
|
+
#
|
66
|
+
def header( ) '' end
|
67
|
+
|
68
|
+
# call-seq:
|
69
|
+
# footer
|
70
|
+
#
|
71
|
+
# Returns a footer string to be used at the end of a logging appender.
|
72
|
+
#
|
73
|
+
def footer( ) '' end
|
74
|
+
|
75
|
+
# call-seq:
|
76
|
+
# format_obj( obj )
|
77
|
+
#
|
78
|
+
# Return a string representation of the given object. Depending upon
|
79
|
+
# the configuration of the logger system the format will be an +inspect+
|
80
|
+
# based represenation or a +yaml+ based representation.
|
81
|
+
#
|
82
|
+
def format_obj( obj )
|
83
|
+
case obj
|
84
|
+
when String; obj
|
85
|
+
when Exception
|
86
|
+
str = "<#{obj.class.name}> #{obj.message}"
|
87
|
+
if @backtrace && !obj.backtrace.nil?
|
88
|
+
str << "\n\t" << obj.backtrace.join("\n\t")
|
89
|
+
end
|
90
|
+
str
|
91
|
+
when nil; "<#{obj.class.name}> nil"
|
92
|
+
else
|
93
|
+
str = "<#{obj.class.name}> "
|
94
|
+
str << case @obj_format
|
95
|
+
when :inspect; obj.inspect
|
96
|
+
when :yaml; try_yaml(obj)
|
97
|
+
else obj.to_s end
|
98
|
+
str
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# call-seq:
|
103
|
+
# try_yaml( obj )
|
104
|
+
#
|
105
|
+
# Attempt to format the _obj_ using yaml, but fall back to inspect style
|
106
|
+
# formatting if yaml fails.
|
107
|
+
#
|
108
|
+
def try_yaml( obj )
|
109
|
+
"\n#{obj.to_yaml}"
|
110
|
+
rescue TypeError
|
111
|
+
obj.inspect
|
112
|
+
end
|
113
|
+
|
114
|
+
end # class Layout
|
115
|
+
end # module Logging
|
116
|
+
|
117
|
+
Logging.require_all_libs_relative_to(__FILE__, 'layouts')
|
118
|
+
|
119
|
+
# EOF
|