1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
|
# :include: rdoc/configurator
#
# == Other Info
#
# Version:: $Id$
require "log4r/logger"
require "log4r/outputter/staticoutputter"
require "log4r/lib/xmlloader"
require "log4r/logserver"
require "log4r/outputter/remoteoutputter"
# TODO: catch unparsed parameters #{FOO} and die
module Log4r
# Gets raised when Configurator encounters bad XML.
class ConfigError < Exception
end
# See log4r/configurator.rb
class Configurator
include REXML if HAVE_REXML
@@params = Hash.new
# Get a parameter's value
def self.[](param); @@params[param] end
# Define a parameter with a value
def self.[]=(param, value); @@params[param] = value end
# Sets the custom levels. This method accepts symbols or strings.
#
# Configurator.custom_levels('My', 'Custom', :Levels)
#
# Alternatively, you can specify custom levels in XML:
#
# <log4r_config>
# <pre_config>
# <custom_levels>
# My, Custom, Levels
# </custom_levels>
# ...
def self.custom_levels(*levels)
return Logger.root if levels.size == 0
for i in 0...levels.size
name = levels[i].to_s
if name =~ /\s/ or name !~ /^[A-Z]/
raise TypeError, "#{name} is not a valid Ruby Constant name", caller
end
end
Log4r.define_levels *levels
end
# Given a filename, loads the XML configuration for Log4r.
def self.load_xml_file(filename)
detect_rexml
actual_load Document.new(File.new(filename))
end
# You can load a String XML configuration instead of a file.
def self.load_xml_string(string)
detect_rexml
actual_load Document.new(string)
end
#######
private
#######
def self.detect_rexml
unless HAVE_REXML
raise LoadError,
"Need REXML to load XML configuration", caller[1..-1]
end
end
def self.actual_load(doc)
confignode = doc.elements['//log4r_config']
if confignode.nil?
raise ConfigError,
"<log4r_config> element not defined", caller[1..-1]
end
decode_xml(confignode)
end
def self.decode_xml(doc)
decode_pre_config(doc.elements['pre_config'])
doc.elements.each('outputter') {|e| decode_outputter(e)}
doc.elements.each('logger') {|e| decode_logger(e)}
doc.elements.each('logserver') {|e| decode_logserver(e)}
end
def self.decode_pre_config(e)
return Logger.root if e.nil?
decode_custom_levels(e.elements['custom_levels'])
global_config(e.elements['global'])
global_config(e.elements['root'])
decode_parameters(e.elements['parameters'])
e.elements.each('parameter') {|p| decode_parameter(p)}
end
def self.decode_custom_levels(e)
return Logger.root if e.nil? or e.text.nil?
begin custom_levels *Log4rTools.comma_split(e.text)
rescue TypeError => te
raise ConfigError, te.message, caller[1..-4]
end
end
def self.global_config(e)
return if e.nil?
globlev = e.value_of 'level'
return if globlev.nil?
lev = LNAMES.index(globlev) # find value in LNAMES
Log4rTools.validate_level(lev, 4) # choke on bad level
Logger.global.level = lev
end
def self.decode_parameters(e)
e.elements.each{|p| @@params[p.name] = p.text} unless e.nil?
end
def self.decode_parameter(e)
@@params[e.value_of('name')] = e.value_of 'value'
end
def self.decode_outputter(e)
# fields
name = e.value_of 'name'
type = e.value_of 'type'
level = e.value_of 'level'
only_at = e.value_of 'only_at'
# validation
raise ConfigError, "Outputter missing name", caller[1..-3] if name.nil?
raise ConfigError, "Outputter missing type", caller[1..-3] if type.nil?
Log4rTools.validate_level(LNAMES.index(level)) unless level.nil?
only_levels = []
unless only_at.nil?
for lev in Log4rTools.comma_split(only_at)
alev = LNAMES.index(lev)
Log4rTools.validate_level(alev, 3)
only_levels.push alev
end
end
formatter = decode_formatter(e.elements['formatter'])
# build the eval string
buff = "Outputter[name] = #{type}.new name"
buff += ",:level=>#{LNAMES.index(level)}" unless level.nil?
buff += ",:formatter=>formatter" unless formatter.nil?
params = decode_hash_params(e)
buff += "," + params.join(',') if params.size > 0
begin eval buff
rescue Exception => ae
raise ConfigError,
"Problem creating outputter: #{ae.message}", caller[1..-3]
end
Outputter[name].only_at *only_levels if only_levels.size > 0
Outputter[name]
end
def self.decode_formatter(e)
return nil if e.nil?
type = e.value_of 'type'
raise ConfigError, "Formatter missing type", caller[1..-4] if type.nil?
buff = "#{type}.new " + decode_hash_params(e).join(',')
begin return eval(buff)
rescue Exception => ae
raise ConfigError,
"Problem creating outputter: #{ae.message}", caller[1..-4]
end
end
ExcludeParams = %w{formatter level name type}
# Does the fancy parameter to hash argument transformation
def self.decode_hash_params(e)
buff = []
e.attributes.each_attribute {|p|
next if ExcludeParams.include? p.name
buff << ":" + p.name + "=>" + paramsub(p.value)
}
e.elements.each {|p|
next if ExcludeParams.include? p.name
buff << ":" + p.name + "=>" + paramsub(p.text)
}
buff
end
# Substitues any #{foo} in the XML with Parameter['foo']
def self.paramsub(str)
return nil if str.nil?
@@params.each {|param, value| str.sub! '#{'+param+'}', value}
"'" + str + "'"
end
def self.decode_logger(e)
l = Logger.new e.value_of('name')
decode_logger_common(l, e)
end
def self.decode_logserver(e)
return unless HAVE_REXML
name = e.value_of 'name'
uri = e.value_of 'uri'
l = LogServer.new name, uri
decode_logger_common(l, e)
end
def self.decode_logger_common(l, e)
level = e.value_of 'level'
additive = e.value_of 'additive'
trace = e.value_of 'trace'
l.level = LNAMES.index(level) unless level.nil?
l.additive = additive unless additive.nil?
l.trace = trace unless trace.nil?
# and now for outputters
outs = e.value_of 'outputters'
Log4rTools.comma_split(outs).each {|n| l.add n.strip} unless outs.nil?
e.elements.each('outputter') {|e|
name = (e.value_of 'name' or e.text)
l.add Outputter[name]
}
end
end
end
|