log4r 1.0.6

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.
Files changed (74) hide show
  1. data/doc/content/contact.html +22 -0
  2. data/doc/content/contribute.html +21 -0
  3. data/doc/content/index.html +90 -0
  4. data/doc/content/license.html +56 -0
  5. data/doc/content/manual.html +449 -0
  6. data/doc/dev/README.developers +55 -0
  7. data/doc/dev/checklist +23 -0
  8. data/doc/dev/things-to-do +5 -0
  9. data/doc/images/log4r-logo.png +0 -0
  10. data/doc/images/logo2.png +0 -0
  11. data/doc/log4r.css +111 -0
  12. data/doc/templates/main.html +147 -0
  13. data/examples/README +19 -0
  14. data/examples/customlevels.rb +34 -0
  15. data/examples/fileroll.rb +40 -0
  16. data/examples/log4r_yaml.yaml +0 -0
  17. data/examples/logclient.rb +25 -0
  18. data/examples/logserver.rb +18 -0
  19. data/examples/moderate.xml +29 -0
  20. data/examples/moderateconfig.rb +66 -0
  21. data/examples/myformatter.rb +23 -0
  22. data/examples/outofthebox.rb +21 -0
  23. data/examples/rrconfig.xml +63 -0
  24. data/examples/rrsetup.rb +42 -0
  25. data/examples/simpleconfig.rb +39 -0
  26. data/examples/xmlconfig.rb +25 -0
  27. data/examples/yaml.rb +30 -0
  28. data/src/log4r.rb +17 -0
  29. data/src/log4r/base.rb +74 -0
  30. data/src/log4r/config.rb +9 -0
  31. data/src/log4r/configurator.rb +224 -0
  32. data/src/log4r/formatter/formatter.rb +105 -0
  33. data/src/log4r/formatter/patternformatter.rb +107 -0
  34. data/src/log4r/lib/drbloader.rb +52 -0
  35. data/src/log4r/lib/xmlloader.rb +24 -0
  36. data/src/log4r/logevent.rb +28 -0
  37. data/src/log4r/logger.rb +194 -0
  38. data/src/log4r/loggerfactory.rb +89 -0
  39. data/src/log4r/logserver.rb +28 -0
  40. data/src/log4r/outputter/consoleoutputters.rb +18 -0
  41. data/src/log4r/outputter/datefileoutputter.rb +110 -0
  42. data/src/log4r/outputter/emailoutputter.rb +116 -0
  43. data/src/log4r/outputter/fileoutputter.rb +49 -0
  44. data/src/log4r/outputter/iooutputter.rb +55 -0
  45. data/src/log4r/outputter/outputter.rb +132 -0
  46. data/src/log4r/outputter/outputterfactory.rb +59 -0
  47. data/src/log4r/outputter/remoteoutputter.rb +40 -0
  48. data/src/log4r/outputter/rollingfileoutputter.rb +126 -0
  49. data/src/log4r/outputter/staticoutputter.rb +30 -0
  50. data/src/log4r/outputter/syslogoutputter.rb +75 -0
  51. data/src/log4r/rdoc/configurator +243 -0
  52. data/src/log4r/rdoc/emailoutputter +103 -0
  53. data/src/log4r/rdoc/formatter +39 -0
  54. data/src/log4r/rdoc/log4r +89 -0
  55. data/src/log4r/rdoc/logger +175 -0
  56. data/src/log4r/rdoc/logserver +85 -0
  57. data/src/log4r/rdoc/outputter +108 -0
  58. data/src/log4r/rdoc/patternformatter +128 -0
  59. data/src/log4r/rdoc/syslogoutputter +29 -0
  60. data/src/log4r/rdoc/yamlconfigurator +20 -0
  61. data/src/log4r/repository.rb +65 -0
  62. data/src/log4r/staticlogger.rb +49 -0
  63. data/src/log4r/yamlconfigurator.rb +0 -0
  64. data/tests/README +10 -0
  65. data/tests/testall.rb +6 -0
  66. data/tests/testbase.rb +49 -0
  67. data/tests/testconf.xml +37 -0
  68. data/tests/testcustom.rb +27 -0
  69. data/tests/testformatter.rb +27 -0
  70. data/tests/testlogger.rb +196 -0
  71. data/tests/testoutputter.rb +111 -0
  72. data/tests/testpatternformatter.rb +21 -0
  73. data/tests/testxmlconf.rb +45 -0
  74. metadata +127 -0
@@ -0,0 +1,9 @@
1
+ # :nodoc:
2
+ # Version:: $Id: config.rb,v 1.1.1.1 2004/03/19 03:31:06 fando Exp $
3
+
4
+ module Log4r
5
+ module Log4rConfig #:nodoc:
6
+ LogLevels = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']
7
+ LoggerPathDelimiter = '::'
8
+ end
9
+ end
@@ -0,0 +1,224 @@
1
+ # :include: rdoc/configurator
2
+ #
3
+ # == Other Info
4
+ #
5
+ # Version:: $Id: configurator.rb,v 1.1.1.1 2004/03/19 03:31:06 fando Exp $
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,105 @@
1
+ # :include: ../rdoc/formatter
2
+ #
3
+ # Version:: $Id: formatter.rb,v 1.2 2009/09/19 05:16:43 colbygk Exp $
4
+
5
+ require "singleton"
6
+
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
+ if obj.kind_of? Exception
72
+ return "Caught #{obj.class}: #{obj.message}\n\t" +\
73
+ obj.backtrace[0...@depth].join("\n\t")
74
+ elsif obj.kind_of? String
75
+ return obj
76
+ else # inspect the object
77
+ return "#{obj.class}: #{obj.inspect}"
78
+ end
79
+ end
80
+ end
81
+
82
+ # Formats objects the same way irb does:
83
+ #
84
+ # loggername:foo.rb in 12>
85
+ # [1, 3, 4]
86
+ # loggername:foo.rb in 13>
87
+ # {1=>"1"}
88
+ #
89
+ # Strings don't get inspected. just printed. The trace is optional.
90
+
91
+ class ObjectFormatter < Formatter
92
+ def format(event)
93
+ buff = event.logger.name
94
+ buff << (event.tracer.nil? ? "" : ":#{event.tracer[0]}") + ">\n"
95
+ buff << (event.data.kind_of?(String) ? event.data : event.data.inspect)
96
+ buff << "\n"
97
+ end
98
+ end
99
+
100
+ # Outputters that don't define a Formatter will get this, which
101
+ # is currently BasicFormatter
102
+ class DefaultFormatter < BasicFormatter
103
+ end
104
+
105
+ end
@@ -0,0 +1,107 @@
1
+ # :include: ../rdoc/patternformatter
2
+ #
3
+ # == Other Info
4
+ #
5
+ # Version:: $Id: patternformatter.rb,v 1.3 2009/09/19 05:16:43 colbygk Exp $
6
+
7
+ require "log4r/formatter/formatter"
8
+
9
+ module Log4r
10
+ # See log4r/formatter/patternformatter.rb
11
+ class PatternFormatter < BasicFormatter
12
+
13
+ # Arguments to sprintf keyed to directive letters
14
+ DirectiveTable = {
15
+ "c" => 'event.name',
16
+ "C" => 'event.fullname',
17
+ "d" => 'format_date',
18
+ "t" => '(event.tracer.nil? ? "no trace" : event.tracer[0])',
19
+ "m" => 'event.data',
20
+ "M" => 'format_object(event.data)',
21
+ "l" => 'LNAMES[event.level]',
22
+ "%" => '"%"'
23
+ }
24
+
25
+ # Matches the first directive encountered and the stuff around it.
26
+ #
27
+ # * $1 is the stuff before directive or "" if not applicable
28
+ # * $2 is the directive group or nil if there's none
29
+ # * $3 is the %#.# match within directive group
30
+ # * $4 is the .# match which we don't use (it's there to match properly)
31
+ # * $5 is the directive letter
32
+ # * $6 is the stuff after the directive or "" if not applicable
33
+
34
+ DirectiveRegexp = /([^%]*)((%-?\d*(\.\d+)?)([cCdtmMl%]))?(.*)/
35
+
36
+ # default date format
37
+ ISO8601 = "%Y-%m-%d %H:%M:%S"
38
+
39
+ attr_reader :pattern, :date_pattern, :date_method
40
+
41
+ # Accepts the following hash arguments (either a string or a symbol):
42
+ #
43
+ # [<tt>pattern</tt>] A pattern format string.
44
+ # [<tt>date_pattern</tt>] A Time#strftime format string. See the
45
+ # Ruby Time class for details.
46
+ # [+date_method+]
47
+ # As an option to date_pattern, specify which
48
+ # Time.now method to call. For
49
+ # example, +usec+ or +to_s+.
50
+ # Specify it as a String or Symbol.
51
+ #
52
+ # The default date format is ISO8601, which looks like this:
53
+ #
54
+ # yyyy-mm-dd hh:mm:ss => 2001-01-12 13:15:50
55
+
56
+ def initialize(hash={})
57
+ super(hash)
58
+ @pattern = (hash['pattern'] or hash[:pattern] or nil)
59
+ @date_pattern = (hash['date_pattern'] or hash[:date_pattern] or nil)
60
+ @date_method = (hash['date_method'] or hash[:date_method] or nil)
61
+ @date_pattern = ISO8601 if @date_pattern.nil? and @date_method.nil?
62
+ PatternFormatter.create_format_methods(self)
63
+ end
64
+
65
+ # PatternFormatter works by dynamically defining a <tt>format</tt> method
66
+ # based on the supplied pattern format. This method contains a call to
67
+ # Kernel#sptrintf with arguments containing the data requested in
68
+ # the pattern format.
69
+ #
70
+ # How is this magic accomplished? First, we visit each directive
71
+ # and change the %#.# component to %#.#s. The directive letter is then
72
+ # used to cull an appropriate entry from the DirectiveTable for the
73
+ # sprintf argument list. After assembling the method definition, we
74
+ # run module_eval on it, and voila.
75
+
76
+ def PatternFormatter.create_format_methods(pf) #:nodoc:
77
+ # first, define the format_date method
78
+ if pf.date_method
79
+ module_eval "def pf.format_date; Time.now.#{pf.date_method}; end"
80
+ else
81
+ module_eval <<-EOS
82
+ def pf.format_date
83
+ Time.now.strftime "#{pf.date_pattern}"
84
+ end
85
+ EOS
86
+ end
87
+ # and now the main format method
88
+ ebuff = "def pf.format(event)\n sprintf(\""
89
+ _pattern = pf.pattern.dup
90
+ args = [] # the args to sprintf which we'll append to ebuff lastly
91
+ while true # work on each match in turn
92
+ match = DirectiveRegexp.match _pattern
93
+ ebuff << match[1] unless match[1].empty?
94
+ break if match[2].nil?
95
+ # deal with the directive by inserting a %#.#s where %#.# is copied
96
+ # directy from the match
97
+ ebuff << match[3] + "s"
98
+ args << DirectiveTable[match[5]] # cull the data for our argument list
99
+ break if match[6].empty?
100
+ _pattern = match[6]
101
+ end
102
+ ebuff << '\n", ' + args.join(', ') + ")\n"
103
+ ebuff << "end\n"
104
+ module_eval ebuff
105
+ end
106
+ end
107
+ 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