mtn_log4r 1.1.11
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.
- checksums.yaml +15 -0
- data/doc/content/contact.html +22 -0
- data/doc/content/contribute.html +21 -0
- data/doc/content/index.html +90 -0
- data/doc/content/license.html +56 -0
- data/doc/content/manual.html +449 -0
- data/doc/dev/README.developers +55 -0
- data/doc/dev/checklist +23 -0
- data/doc/dev/things-to-do +5 -0
- data/doc/images/log4r-logo.png +0 -0
- data/doc/images/logo2.png +0 -0
- data/doc/log4r.css +111 -0
- data/doc/rdoc-log4r.css +696 -0
- data/doc/templates/main.html +147 -0
- data/examples/README +19 -0
- data/examples/ancestors.rb +53 -0
- data/examples/chainsaw_settings.xml +7 -0
- data/examples/customlevels.rb +34 -0
- data/examples/filelog.rb +25 -0
- data/examples/fileroll.rb +40 -0
- data/examples/gmail.rb +30 -0
- data/examples/gmail.yaml +95 -0
- data/examples/log4r_yaml.yaml +0 -0
- data/examples/logclient.rb +25 -0
- data/examples/logserver.rb +18 -0
- data/examples/moderate.xml +29 -0
- data/examples/moderateconfig.rb +66 -0
- data/examples/myformatter.rb +23 -0
- data/examples/outofthebox.rb +21 -0
- data/examples/rdoc-gen +2 -0
- data/examples/rrconfig.xml +63 -0
- data/examples/rrsetup.rb +42 -0
- data/examples/simpleconfig.rb +39 -0
- data/examples/syslogcustom.rb +52 -0
- data/examples/xmlconfig.rb +25 -0
- data/examples/yaml.rb +30 -0
- data/lib/log4r/GDC.rb +41 -0
- data/lib/log4r/MDC.rb +59 -0
- data/lib/log4r/NDC.rb +86 -0
- data/lib/log4r/base.rb +74 -0
- data/lib/log4r/config.rb +9 -0
- data/lib/log4r/configurator.rb +224 -0
- data/lib/log4r/formatter/formatter.rb +109 -0
- data/lib/log4r/formatter/log4jxmlformatter.rb +65 -0
- data/lib/log4r/formatter/patternformatter.rb +145 -0
- data/lib/log4r/lib/drbloader.rb +52 -0
- data/lib/log4r/lib/xmlloader.rb +24 -0
- data/lib/log4r/logevent.rb +28 -0
- data/lib/log4r/logger.rb +199 -0
- data/lib/log4r/loggerfactory.rb +89 -0
- data/lib/log4r/logserver.rb +28 -0
- data/lib/log4r/outputter/consoleoutputters.rb +18 -0
- data/lib/log4r/outputter/datefileoutputter.rb +117 -0
- data/lib/log4r/outputter/emailoutputter.rb +143 -0
- data/lib/log4r/outputter/fileoutputter.rb +56 -0
- data/lib/log4r/outputter/iooutputter.rb +55 -0
- data/lib/log4r/outputter/outputter.rb +134 -0
- data/lib/log4r/outputter/outputterfactory.rb +61 -0
- data/lib/log4r/outputter/rabbitoutputter.rb +70 -0
- data/lib/log4r/outputter/remoteoutputter.rb +40 -0
- data/lib/log4r/outputter/rollingfileoutputter.rb +234 -0
- data/lib/log4r/outputter/scribeoutputter.rb +37 -0
- data/lib/log4r/outputter/staticoutputter.rb +30 -0
- data/lib/log4r/outputter/syslogoutputter.rb +130 -0
- data/lib/log4r/outputter/udpoutputter.rb +53 -0
- data/lib/log4r/rdoc/GDC +14 -0
- data/lib/log4r/rdoc/MDC +16 -0
- data/lib/log4r/rdoc/NDC +41 -0
- data/lib/log4r/rdoc/configurator +243 -0
- data/lib/log4r/rdoc/emailoutputter +103 -0
- data/lib/log4r/rdoc/formatter +39 -0
- data/lib/log4r/rdoc/log4jxmlformatter +21 -0
- data/lib/log4r/rdoc/log4r +89 -0
- data/lib/log4r/rdoc/logger +175 -0
- data/lib/log4r/rdoc/logserver +85 -0
- data/lib/log4r/rdoc/outputter +108 -0
- data/lib/log4r/rdoc/patternformatter +128 -0
- data/lib/log4r/rdoc/scribeoutputter +16 -0
- data/lib/log4r/rdoc/syslogoutputter +29 -0
- data/lib/log4r/rdoc/win32eventoutputter +7 -0
- data/lib/log4r/rdoc/yamlconfigurator +20 -0
- data/lib/log4r/repository.rb +88 -0
- data/lib/log4r/staticlogger.rb +49 -0
- data/lib/log4r/version.rb +4 -0
- data/lib/log4r/yamlconfigurator.rb +198 -0
- data/lib/log4r.rb +18 -0
- data/tests/README +10 -0
- data/tests/testGDC.rb +24 -0
- data/tests/testMDC.rb +40 -0
- data/tests/testNDC.rb +25 -0
- data/tests/test_helper.rb +12 -0
- data/tests/testall.rb +6 -0
- data/tests/testbase.rb +48 -0
- data/tests/testchainsaw.rb +42 -0
- data/tests/testconf.xml +37 -0
- data/tests/testcustom.rb +30 -0
- data/tests/testformatter.rb +31 -0
- data/tests/testlogger.rb +200 -0
- data/tests/testoutputter.rb +143 -0
- data/tests/testpatternformatter.rb +76 -0
- data/tests/testthreads.rb +31 -0
- data/tests/testxmlconf.rb +48 -0
- data/tests/testyaml.rb +39 -0
- data/tests/testyaml_arrays.yaml +25 -0
- data/tests/testyaml_injection.yaml +22 -0
- metadata +193 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# :include: rdoc/configurator
|
|
2
|
+
#
|
|
3
|
+
# == Other Info
|
|
4
|
+
#
|
|
5
|
+
# Version:: $Id$
|
|
6
|
+
|
|
7
|
+
require "log4r/logger"
|
|
8
|
+
require "log4r/outputter/staticoutputter"
|
|
9
|
+
require "log4r/lib/xmlloader"
|
|
10
|
+
require "log4r/logserver"
|
|
11
|
+
require "log4r/outputter/remoteoutputter"
|
|
12
|
+
|
|
13
|
+
# TODO: catch unparsed parameters #{FOO} and die
|
|
14
|
+
module Log4r
|
|
15
|
+
# Gets raised when Configurator encounters bad XML.
|
|
16
|
+
class ConfigError < Exception
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# See log4r/configurator.rb
|
|
20
|
+
class Configurator
|
|
21
|
+
include REXML if HAVE_REXML
|
|
22
|
+
@@params = Hash.new
|
|
23
|
+
|
|
24
|
+
# Get a parameter's value
|
|
25
|
+
def self.[](param); @@params[param] end
|
|
26
|
+
# Define a parameter with a value
|
|
27
|
+
def self.[]=(param, value); @@params[param] = value end
|
|
28
|
+
|
|
29
|
+
# Sets the custom levels. This method accepts symbols or strings.
|
|
30
|
+
#
|
|
31
|
+
# Configurator.custom_levels('My', 'Custom', :Levels)
|
|
32
|
+
#
|
|
33
|
+
# Alternatively, you can specify custom levels in XML:
|
|
34
|
+
#
|
|
35
|
+
# <log4r_config>
|
|
36
|
+
# <pre_config>
|
|
37
|
+
# <custom_levels>
|
|
38
|
+
# My, Custom, Levels
|
|
39
|
+
# </custom_levels>
|
|
40
|
+
# ...
|
|
41
|
+
|
|
42
|
+
def self.custom_levels(*levels)
|
|
43
|
+
return Logger.root if levels.size == 0
|
|
44
|
+
for i in 0...levels.size
|
|
45
|
+
name = levels[i].to_s
|
|
46
|
+
if name =~ /\s/ or name !~ /^[A-Z]/
|
|
47
|
+
raise TypeError, "#{name} is not a valid Ruby Constant name", caller
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
Log4r.define_levels *levels
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Given a filename, loads the XML configuration for Log4r.
|
|
54
|
+
def self.load_xml_file(filename)
|
|
55
|
+
detect_rexml
|
|
56
|
+
actual_load Document.new(File.new(filename))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# You can load a String XML configuration instead of a file.
|
|
60
|
+
def self.load_xml_string(string)
|
|
61
|
+
detect_rexml
|
|
62
|
+
actual_load Document.new(string)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
#######
|
|
66
|
+
private
|
|
67
|
+
#######
|
|
68
|
+
|
|
69
|
+
def self.detect_rexml
|
|
70
|
+
unless HAVE_REXML
|
|
71
|
+
raise LoadError,
|
|
72
|
+
"Need REXML to load XML configuration", caller[1..-1]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.actual_load(doc)
|
|
77
|
+
confignode = doc.elements['//log4r_config']
|
|
78
|
+
if confignode.nil?
|
|
79
|
+
raise ConfigError,
|
|
80
|
+
"<log4r_config> element not defined", caller[1..-1]
|
|
81
|
+
end
|
|
82
|
+
decode_xml(confignode)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.decode_xml(doc)
|
|
86
|
+
decode_pre_config(doc.elements['pre_config'])
|
|
87
|
+
doc.elements.each('outputter') {|e| decode_outputter(e)}
|
|
88
|
+
doc.elements.each('logger') {|e| decode_logger(e)}
|
|
89
|
+
doc.elements.each('logserver') {|e| decode_logserver(e)}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.decode_pre_config(e)
|
|
93
|
+
return Logger.root if e.nil?
|
|
94
|
+
decode_custom_levels(e.elements['custom_levels'])
|
|
95
|
+
global_config(e.elements['global'])
|
|
96
|
+
global_config(e.elements['root'])
|
|
97
|
+
decode_parameters(e.elements['parameters'])
|
|
98
|
+
e.elements.each('parameter') {|p| decode_parameter(p)}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.decode_custom_levels(e)
|
|
102
|
+
return Logger.root if e.nil? or e.text.nil?
|
|
103
|
+
begin custom_levels *Log4rTools.comma_split(e.text)
|
|
104
|
+
rescue TypeError => te
|
|
105
|
+
raise ConfigError, te.message, caller[1..-4]
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def self.global_config(e)
|
|
110
|
+
return if e.nil?
|
|
111
|
+
globlev = e.value_of 'level'
|
|
112
|
+
return if globlev.nil?
|
|
113
|
+
lev = LNAMES.index(globlev) # find value in LNAMES
|
|
114
|
+
Log4rTools.validate_level(lev, 4) # choke on bad level
|
|
115
|
+
Logger.global.level = lev
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self.decode_parameters(e)
|
|
119
|
+
e.elements.each{|p| @@params[p.name] = p.text} unless e.nil?
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def self.decode_parameter(e)
|
|
123
|
+
@@params[e.value_of('name')] = e.value_of 'value'
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def self.decode_outputter(e)
|
|
127
|
+
# fields
|
|
128
|
+
name = e.value_of 'name'
|
|
129
|
+
type = e.value_of 'type'
|
|
130
|
+
level = e.value_of 'level'
|
|
131
|
+
only_at = e.value_of 'only_at'
|
|
132
|
+
# validation
|
|
133
|
+
raise ConfigError, "Outputter missing name", caller[1..-3] if name.nil?
|
|
134
|
+
raise ConfigError, "Outputter missing type", caller[1..-3] if type.nil?
|
|
135
|
+
Log4rTools.validate_level(LNAMES.index(level)) unless level.nil?
|
|
136
|
+
only_levels = []
|
|
137
|
+
unless only_at.nil?
|
|
138
|
+
for lev in Log4rTools.comma_split(only_at)
|
|
139
|
+
alev = LNAMES.index(lev)
|
|
140
|
+
Log4rTools.validate_level(alev, 3)
|
|
141
|
+
only_levels.push alev
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
formatter = decode_formatter(e.elements['formatter'])
|
|
145
|
+
# build the eval string
|
|
146
|
+
buff = "Outputter[name] = #{type}.new name"
|
|
147
|
+
buff += ",:level=>#{LNAMES.index(level)}" unless level.nil?
|
|
148
|
+
buff += ",:formatter=>formatter" unless formatter.nil?
|
|
149
|
+
params = decode_hash_params(e)
|
|
150
|
+
buff += "," + params.join(',') if params.size > 0
|
|
151
|
+
begin eval buff
|
|
152
|
+
rescue Exception => ae
|
|
153
|
+
raise ConfigError,
|
|
154
|
+
"Problem creating outputter: #{ae.message}", caller[1..-3]
|
|
155
|
+
end
|
|
156
|
+
Outputter[name].only_at *only_levels if only_levels.size > 0
|
|
157
|
+
Outputter[name]
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def self.decode_formatter(e)
|
|
161
|
+
return nil if e.nil?
|
|
162
|
+
type = e.value_of 'type'
|
|
163
|
+
raise ConfigError, "Formatter missing type", caller[1..-4] if type.nil?
|
|
164
|
+
buff = "#{type}.new " + decode_hash_params(e).join(',')
|
|
165
|
+
begin return eval(buff)
|
|
166
|
+
rescue Exception => ae
|
|
167
|
+
raise ConfigError,
|
|
168
|
+
"Problem creating outputter: #{ae.message}", caller[1..-4]
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
ExcludeParams = %w{formatter level name type}
|
|
173
|
+
|
|
174
|
+
# Does the fancy parameter to hash argument transformation
|
|
175
|
+
def self.decode_hash_params(e)
|
|
176
|
+
buff = []
|
|
177
|
+
e.attributes.each_attribute {|p|
|
|
178
|
+
next if ExcludeParams.include? p.name
|
|
179
|
+
buff << ":" + p.name + "=>" + paramsub(p.value)
|
|
180
|
+
}
|
|
181
|
+
e.elements.each {|p|
|
|
182
|
+
next if ExcludeParams.include? p.name
|
|
183
|
+
buff << ":" + p.name + "=>" + paramsub(p.text)
|
|
184
|
+
}
|
|
185
|
+
buff
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Substitues any #{foo} in the XML with Parameter['foo']
|
|
189
|
+
def self.paramsub(str)
|
|
190
|
+
return nil if str.nil?
|
|
191
|
+
@@params.each {|param, value| str.sub! '#{'+param+'}', value}
|
|
192
|
+
"'" + str + "'"
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def self.decode_logger(e)
|
|
196
|
+
l = Logger.new e.value_of('name')
|
|
197
|
+
decode_logger_common(l, e)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def self.decode_logserver(e)
|
|
201
|
+
return unless HAVE_REXML
|
|
202
|
+
name = e.value_of 'name'
|
|
203
|
+
uri = e.value_of 'uri'
|
|
204
|
+
l = LogServer.new name, uri
|
|
205
|
+
decode_logger_common(l, e)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def self.decode_logger_common(l, e)
|
|
209
|
+
level = e.value_of 'level'
|
|
210
|
+
additive = e.value_of 'additive'
|
|
211
|
+
trace = e.value_of 'trace'
|
|
212
|
+
l.level = LNAMES.index(level) unless level.nil?
|
|
213
|
+
l.additive = additive unless additive.nil?
|
|
214
|
+
l.trace = trace unless trace.nil?
|
|
215
|
+
# and now for outputters
|
|
216
|
+
outs = e.value_of 'outputters'
|
|
217
|
+
Log4rTools.comma_split(outs).each {|n| l.add n.strip} unless outs.nil?
|
|
218
|
+
e.elements.each('outputter') {|e|
|
|
219
|
+
name = (e.value_of 'name' or e.text)
|
|
220
|
+
l.add Outputter[name]
|
|
221
|
+
}
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# :include: ../rdoc/formatter
|
|
2
|
+
#
|
|
3
|
+
# Version:: $Id$
|
|
4
|
+
|
|
5
|
+
require "singleton"
|
|
6
|
+
require 'json'
|
|
7
|
+
require "log4r/base"
|
|
8
|
+
|
|
9
|
+
module Log4r
|
|
10
|
+
|
|
11
|
+
# Formatter is an abstract class and a null object
|
|
12
|
+
class Formatter
|
|
13
|
+
def initialize(hash={})
|
|
14
|
+
end
|
|
15
|
+
# Define this method in a subclass to format data.
|
|
16
|
+
def format(logevent)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# SimpleFormatter produces output like this:
|
|
21
|
+
#
|
|
22
|
+
# WARN loggername> Danger, Will Robinson, danger!
|
|
23
|
+
#
|
|
24
|
+
# Does not write traces and does not inspect objects.
|
|
25
|
+
|
|
26
|
+
class SimpleFormatter < Formatter
|
|
27
|
+
def format(event)
|
|
28
|
+
sprintf("%*s %s> %s\n", MaxLevelLength, LNAMES[event.level],
|
|
29
|
+
event.name, event.data)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# BasicFormatter produces output like this:
|
|
34
|
+
#
|
|
35
|
+
# WARN loggername: I dropped my Wookie!
|
|
36
|
+
#
|
|
37
|
+
# Or like this if trace is on:
|
|
38
|
+
#
|
|
39
|
+
# WARN loggername(file.rb at 12): Hot potato!
|
|
40
|
+
#
|
|
41
|
+
# Also, it will pretty-print any Exception it gets and
|
|
42
|
+
# +inspect+ everything else.
|
|
43
|
+
#
|
|
44
|
+
# Hash arguments include:
|
|
45
|
+
#
|
|
46
|
+
# +depth+:: How many lines of the stacktrace to display.
|
|
47
|
+
|
|
48
|
+
class BasicFormatter < SimpleFormatter
|
|
49
|
+
@@basicformat = "%*s %s"
|
|
50
|
+
|
|
51
|
+
def initialize(hash={})
|
|
52
|
+
@depth = (hash[:depth] or hash['depth'] or 7).to_i
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def format(event)
|
|
56
|
+
buff = sprintf(@@basicformat, MaxLevelLength, LNAMES[event.level],
|
|
57
|
+
event.name)
|
|
58
|
+
buff << (event.tracer.nil? ? "" : "(#{event.tracer[0]})") + ": "
|
|
59
|
+
buff << format_object(event.data) + "\n"
|
|
60
|
+
buff
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Formats data according to its class:
|
|
64
|
+
#
|
|
65
|
+
# String:: Prints it out as normal.
|
|
66
|
+
# Exception:: Produces output similar to command-line exceptions.
|
|
67
|
+
# Object:: Prints the type of object, then the output of
|
|
68
|
+
# +inspect+. An example -- Array: [1, 2, 3]
|
|
69
|
+
|
|
70
|
+
def format_object(obj)
|
|
71
|
+
klass = obj.class
|
|
72
|
+
case
|
|
73
|
+
when klass == Exception
|
|
74
|
+
return "Caught #{obj.class}: #{obj.message}\n\t" +\
|
|
75
|
+
(obj.backtrace.nil? ? [] : obj.backtrace[0...@depth]).join("\n\t").gsub('"','\\\\"')
|
|
76
|
+
when klass == Hash
|
|
77
|
+
return obj.to_json.gsub('"','\\\\"')
|
|
78
|
+
when klass == String
|
|
79
|
+
return obj.gsub('"','\\\\"')
|
|
80
|
+
else # inspect the object
|
|
81
|
+
return "#{obj.class}: #{obj.inspect}".gsub('"','\\\\"')
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Formats objects the same way irb does:
|
|
87
|
+
#
|
|
88
|
+
# loggername:foo.rb in 12>
|
|
89
|
+
# [1, 3, 4]
|
|
90
|
+
# loggername:foo.rb in 13>
|
|
91
|
+
# {1=>"1"}
|
|
92
|
+
#
|
|
93
|
+
# Strings don't get inspected. just printed. The trace is optional.
|
|
94
|
+
|
|
95
|
+
class ObjectFormatter < Formatter
|
|
96
|
+
def format(event)
|
|
97
|
+
buff = event.logger.name
|
|
98
|
+
buff << (event.tracer.nil? ? "" : ":#{event.tracer[0]}") + ">\n"
|
|
99
|
+
buff << (event.data.kind_of?(String) ? event.data : event.data.inspect)
|
|
100
|
+
buff << "\n"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Outputters that don't define a Formatter will get this, which
|
|
105
|
+
# is currently BasicFormatter
|
|
106
|
+
class DefaultFormatter < BasicFormatter
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# :include: ../rdoc/log4jxmlformatter
|
|
2
|
+
#
|
|
3
|
+
# == Other Info
|
|
4
|
+
#
|
|
5
|
+
# Version:: $Id$
|
|
6
|
+
|
|
7
|
+
require "log4r/formatter/formatter"
|
|
8
|
+
|
|
9
|
+
require "rubygems"
|
|
10
|
+
begin
|
|
11
|
+
require "builder"
|
|
12
|
+
rescue LoadError
|
|
13
|
+
puts "builder gem is required to use log4jxmlformatter, i.e. gem install builder"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module Log4r
|
|
17
|
+
|
|
18
|
+
class Log4jXmlFormatter < BasicFormatter
|
|
19
|
+
|
|
20
|
+
def format(logevent)
|
|
21
|
+
logger = logevent.fullname.gsub('::', '.')
|
|
22
|
+
timestamp = (Time.now.to_f * 1000).to_i
|
|
23
|
+
level = LNAMES[logevent.level]
|
|
24
|
+
message = format_object(logevent.data)
|
|
25
|
+
exception = message if logevent.data.kind_of? Exception
|
|
26
|
+
file, line, method = parse_caller(logevent.tracer[0]) if logevent.tracer
|
|
27
|
+
|
|
28
|
+
builder = Builder::XmlMarkup.new
|
|
29
|
+
xml = builder.log4j :event, :logger => logger,
|
|
30
|
+
:timestamp => timestamp,
|
|
31
|
+
:level => level,
|
|
32
|
+
:thread => '' do |e|
|
|
33
|
+
e.log4j :NDC, NDC.get
|
|
34
|
+
e.log4j :message, message
|
|
35
|
+
e.log4j :throwable, exception if exception
|
|
36
|
+
e.log4j :locationInfo, :class => '',
|
|
37
|
+
:method => method,
|
|
38
|
+
:file => file,
|
|
39
|
+
:line => line
|
|
40
|
+
e.log4j :properties do |p|
|
|
41
|
+
MDC.get_context.each do |key, value|
|
|
42
|
+
p.log4j :data, :name => key, :value => value
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
xml
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
#######
|
|
50
|
+
private
|
|
51
|
+
#######
|
|
52
|
+
|
|
53
|
+
def parse_caller(line)
|
|
54
|
+
if /^(.+?):(\d+)(?::in `(.*)')?/ =~ line
|
|
55
|
+
file = Regexp.last_match[1]
|
|
56
|
+
line = Regexp.last_match[2].to_i
|
|
57
|
+
method = Regexp.last_match[3]
|
|
58
|
+
[file, line, method]
|
|
59
|
+
else
|
|
60
|
+
[]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# :include: ../rdoc/patternformatter
|
|
2
|
+
#
|
|
3
|
+
# == Other Info
|
|
4
|
+
#
|
|
5
|
+
# Version:: $Id$
|
|
6
|
+
|
|
7
|
+
require "log4r/formatter/formatter"
|
|
8
|
+
require "log4r/GDC"
|
|
9
|
+
require "log4r/MDC"
|
|
10
|
+
require "log4r/NDC"
|
|
11
|
+
|
|
12
|
+
module Log4r
|
|
13
|
+
# See log4r/formatter/patternformatter.rb
|
|
14
|
+
class PatternFormatter < BasicFormatter
|
|
15
|
+
|
|
16
|
+
# Arguments to sprintf keyed to directive letters<br>
|
|
17
|
+
# %c - event short name<br>
|
|
18
|
+
# %C - event fullname<br>
|
|
19
|
+
# %d - date<br>
|
|
20
|
+
# %g - Global Diagnostic Context (GDC)<br>
|
|
21
|
+
# %t - trace<br>
|
|
22
|
+
# %m - message<br>
|
|
23
|
+
# %h - thread name<br>
|
|
24
|
+
# %p - process ID aka PID<br>
|
|
25
|
+
# %M - formatted message<br>
|
|
26
|
+
# %l - Level in string form<br>
|
|
27
|
+
# %x - Nested Diagnostic Context (NDC)<br>
|
|
28
|
+
# %X - Mapped Diagnostic Context (MDC), syntax is "%X{key}"<br>
|
|
29
|
+
# %% - Insert a %<br>
|
|
30
|
+
DirectiveTable = {
|
|
31
|
+
"c" => 'event.name',
|
|
32
|
+
"C" => 'event.fullname',
|
|
33
|
+
"d" => 'format_date',
|
|
34
|
+
"g" => 'Log4r::GDC.get()',
|
|
35
|
+
"t" => '(event.tracer.nil? ? "no trace" : event.tracer[0])',
|
|
36
|
+
"T" => '(event.tracer.nil? ? "no trace" : event.tracer[0].split(File::SEPARATOR)[-1])',
|
|
37
|
+
"m" => 'event.data',
|
|
38
|
+
"h" => '(Thread.current[:name] or Thread.current.to_s)',
|
|
39
|
+
"p" => 'Process.pid.to_s',
|
|
40
|
+
"M" => 'format_object(event.data)',
|
|
41
|
+
"l" => 'LNAMES[event.level]',
|
|
42
|
+
"x" => 'Log4r::NDC.get()',
|
|
43
|
+
"X" => 'Log4r::MDC.get("DTR_REPLACE")',
|
|
44
|
+
"%" => '"%"'
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Matches the first directive encountered and the stuff around it.
|
|
48
|
+
#
|
|
49
|
+
# * $1 is the stuff before directive or "" if not applicable
|
|
50
|
+
# * $2 is the directive group or nil if there's none
|
|
51
|
+
# * $3 is the %#.# match within directive group
|
|
52
|
+
# * $4 is the .# match which we don't use (it's there to match properly)
|
|
53
|
+
# * $5 is the directive letter
|
|
54
|
+
# * $6 is the stuff after the directive or "" if not applicable
|
|
55
|
+
# * $7 is the remainder
|
|
56
|
+
|
|
57
|
+
DirectiveRegexp = /([^%]*)((%-?\d*(\.\d+)?)([cCdgtTmhpMlxX%]))?(\{.+?\})?(.*)/
|
|
58
|
+
|
|
59
|
+
# default date format
|
|
60
|
+
ISO8601 = "%Y-%m-%d %H:%M:%S"
|
|
61
|
+
|
|
62
|
+
attr_reader :pattern, :date_pattern, :date_method
|
|
63
|
+
|
|
64
|
+
# Accepts the following hash arguments (either a string or a symbol):
|
|
65
|
+
#
|
|
66
|
+
# [<tt>pattern</tt>] A pattern format string.
|
|
67
|
+
# [<tt>date_pattern</tt>] A Time#strftime format string. See the
|
|
68
|
+
# Ruby Time class for details.
|
|
69
|
+
# [+date_method+]
|
|
70
|
+
# As an option to date_pattern, specify which
|
|
71
|
+
# Time.now method to call. For
|
|
72
|
+
# example, +usec+ or +to_s+.
|
|
73
|
+
# Specify it as a String or Symbol.
|
|
74
|
+
#
|
|
75
|
+
# The default date format is ISO8601, which looks like this:
|
|
76
|
+
#
|
|
77
|
+
# yyyy-mm-dd hh:mm:ss => 2001-01-12 13:15:50
|
|
78
|
+
|
|
79
|
+
def initialize(hash={})
|
|
80
|
+
super(hash)
|
|
81
|
+
@pattern = (hash['pattern'] or hash[:pattern] or nil)
|
|
82
|
+
@date_pattern = (hash['date_pattern'] or hash[:date_pattern] or nil)
|
|
83
|
+
@date_method = (hash['date_method'] or hash[:date_method] or nil)
|
|
84
|
+
@date_pattern = ISO8601 if @date_pattern.nil? and @date_method.nil?
|
|
85
|
+
PatternFormatter.create_format_methods(self)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# PatternFormatter works by dynamically defining a <tt>format</tt> method
|
|
89
|
+
# based on the supplied pattern format. This method contains a call to
|
|
90
|
+
# Kernel#sptrintf with arguments containing the data requested in
|
|
91
|
+
# the pattern format.
|
|
92
|
+
#
|
|
93
|
+
# How is this magic accomplished? First, we visit each directive
|
|
94
|
+
# and change the %#.# component to %#.#s. The directive letter is then
|
|
95
|
+
# used to cull an appropriate entry from the DirectiveTable for the
|
|
96
|
+
# sprintf argument list. After assembling the method definition, we
|
|
97
|
+
# run module_eval on it, and voila.
|
|
98
|
+
|
|
99
|
+
def PatternFormatter.create_format_methods(pf) #:nodoc:
|
|
100
|
+
# first, define the format_date method
|
|
101
|
+
if pf.date_method
|
|
102
|
+
module_eval "def pf.format_date; Time.now.#{pf.date_method}; end"
|
|
103
|
+
else
|
|
104
|
+
module_eval <<-EOS
|
|
105
|
+
def pf.format_date
|
|
106
|
+
Time.now.strftime "#{pf.date_pattern}"
|
|
107
|
+
end
|
|
108
|
+
EOS
|
|
109
|
+
end
|
|
110
|
+
# and now the main format method
|
|
111
|
+
ebuff = "def pf.format(event)\n sprintf(\""
|
|
112
|
+
_pattern = pf.pattern.dup
|
|
113
|
+
args = [] # the args to sprintf which we'll append to ebuff lastly
|
|
114
|
+
while true # work on each match in turn
|
|
115
|
+
match = DirectiveRegexp.match _pattern
|
|
116
|
+
ebuff << match[1] unless match[1].empty?
|
|
117
|
+
break if match[2].nil?
|
|
118
|
+
# deal with the directive by inserting a %#.#s where %#.# is copied
|
|
119
|
+
# directy from the match
|
|
120
|
+
ebuff << match[3] + "s"
|
|
121
|
+
|
|
122
|
+
if ( match[5] == 'X' && match[6] != nil ) then
|
|
123
|
+
|
|
124
|
+
# MDC matches, need to be able to handle String, Symbol or Number
|
|
125
|
+
match6sub = /[\{\}\"]/
|
|
126
|
+
mdcmatches = match[6].match /\{(:?)(\d*)(.*)\}/
|
|
127
|
+
|
|
128
|
+
if ( mdcmatches[1] == "" && mdcmatches[2] == "" )
|
|
129
|
+
match6sub = /[\{\}]/ # don't remove surrounding "'s if String
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
args <<
|
|
133
|
+
DirectiveTable[match[5]].gsub("DTR_REPLACE", match[6]).gsub(match6sub,'')
|
|
134
|
+
else
|
|
135
|
+
args << DirectiveTable[match[5]] # cull the data for our argument list
|
|
136
|
+
end
|
|
137
|
+
break if match[7].empty?
|
|
138
|
+
_pattern = match[7]
|
|
139
|
+
end
|
|
140
|
+
ebuff << '\n", ' + args.join(', ') + ")\n"
|
|
141
|
+
ebuff << "end\n"
|
|
142
|
+
module_eval ebuff
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#:nodoc:
|
|
2
|
+
module Log4r
|
|
3
|
+
begin
|
|
4
|
+
require 'romp'
|
|
5
|
+
HAVE_ROMP = true
|
|
6
|
+
rescue LoadError
|
|
7
|
+
HAVE_ROMP = false
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
if HAVE_ROMP
|
|
11
|
+
|
|
12
|
+
module ROMPServer #:nodoc:
|
|
13
|
+
private
|
|
14
|
+
def start_server(_uri, accept)
|
|
15
|
+
@server = ROMP::Server.new(_uri, accept) # what if accept is nil?
|
|
16
|
+
@server.bind(self, "Log4r::LogServer")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module ROMPClient #:nodoc:
|
|
21
|
+
private
|
|
22
|
+
def connect
|
|
23
|
+
begin
|
|
24
|
+
@client = ROMP::Client.new(@uri, false)
|
|
25
|
+
@remote_logger = @client.resolve("Log4r::LogServer")
|
|
26
|
+
rescue Exception => e
|
|
27
|
+
Logger.log_internal(-2) {
|
|
28
|
+
"RemoteOutputter '#{@name}' failed to connect to #{@uri}!"
|
|
29
|
+
}
|
|
30
|
+
Logger.log_internal {e}
|
|
31
|
+
self.level = OFF
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
# we use propagated = true
|
|
35
|
+
def send_buffer
|
|
36
|
+
begin
|
|
37
|
+
@buff.each {|levent|
|
|
38
|
+
lname = LNAMES[levent.level].downcase
|
|
39
|
+
@remote_logger.oneway(lname, levent, true)
|
|
40
|
+
}
|
|
41
|
+
rescue Exception => e
|
|
42
|
+
Logger.log_internal(-2) {"RemoteOutputter '#{@name}' can't log!"}
|
|
43
|
+
Logger.log_internal {e}
|
|
44
|
+
self.level = OFF
|
|
45
|
+
ensure @buff.clear
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#:nodoc:
|
|
2
|
+
module Log4r
|
|
3
|
+
begin
|
|
4
|
+
require 'rexml/document'
|
|
5
|
+
HAVE_REXML = true
|
|
6
|
+
rescue LoadError
|
|
7
|
+
HAVE_REXML = false
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
if Log4r::HAVE_REXML
|
|
12
|
+
module REXML #:nodoc: all
|
|
13
|
+
class Element
|
|
14
|
+
def value_of(elmt)
|
|
15
|
+
val = attributes[elmt]
|
|
16
|
+
if val.nil?
|
|
17
|
+
sub = elements[elmt]
|
|
18
|
+
val = sub.text unless sub.nil?
|
|
19
|
+
end
|
|
20
|
+
val
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# :nodoc:
|
|
2
|
+
module Log4r
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# LogEvent wraps up all the miscellaneous data associated with a logging
|
|
6
|
+
# statement. It gets passed around to the varied components of Log4r and
|
|
7
|
+
# should be of interest to those creating extensions.
|
|
8
|
+
#
|
|
9
|
+
# Data contained:
|
|
10
|
+
#
|
|
11
|
+
# [level] The integer level of the log event. Use LNAMES[level]
|
|
12
|
+
# to get the actual level name.
|
|
13
|
+
# [tracer] The execution stack returned by <tt>caller</tt> at the
|
|
14
|
+
# log event. It is nil if the invoked Logger's trace is false.
|
|
15
|
+
# [data] The object that was passed into the logging method.
|
|
16
|
+
# [name] The name of the logger that was invoked.
|
|
17
|
+
# [fullname] The fully qualified name of the logger that was invoked.
|
|
18
|
+
#
|
|
19
|
+
# Note that creating timestamps is a task left to formatters.
|
|
20
|
+
|
|
21
|
+
class LogEvent
|
|
22
|
+
attr_reader :level, :tracer, :data, :name, :fullname
|
|
23
|
+
def initialize(level, logger, tracer, data)
|
|
24
|
+
@level, @tracer, @data = level, tracer, data
|
|
25
|
+
@name, @fullname = logger.name, logger.fullname
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|