log4rails 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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.bsd +12 -0
  3. data/README.md +37 -0
  4. data/lib/log4r/GDC.rb +41 -0
  5. data/lib/log4r/MDC.rb +59 -0
  6. data/lib/log4r/NDC.rb +86 -0
  7. data/lib/log4r/base.rb +74 -0
  8. data/lib/log4r/config.rb +9 -0
  9. data/lib/log4r/configurator.rb +224 -0
  10. data/lib/log4r/formatter/formatter.rb +105 -0
  11. data/lib/log4r/formatter/log4jxmlformatter.rb +65 -0
  12. data/lib/log4r/formatter/patternformatter.rb +145 -0
  13. data/lib/log4r/lib/drbloader.rb +52 -0
  14. data/lib/log4r/lib/xmlloader.rb +24 -0
  15. data/lib/log4r/log4r-rails.yaml +60 -0
  16. data/lib/log4r/logevent.rb +28 -0
  17. data/lib/log4r/logger.rb +206 -0
  18. data/lib/log4r/loggerfactory.rb +89 -0
  19. data/lib/log4r/logserver.rb +28 -0
  20. data/lib/log4r/outputter/bufferedsyslogoutputter.rb +47 -0
  21. data/lib/log4r/outputter/consoleoutputters.rb +18 -0
  22. data/lib/log4r/outputter/datefileoutputter.rb +117 -0
  23. data/lib/log4r/outputter/emailoutputter.rb +143 -0
  24. data/lib/log4r/outputter/fileoutputter.rb +57 -0
  25. data/lib/log4r/outputter/iooutputter.rb +55 -0
  26. data/lib/log4r/outputter/outputter.rb +134 -0
  27. data/lib/log4r/outputter/outputterfactory.rb +60 -0
  28. data/lib/log4r/outputter/remoteoutputter.rb +40 -0
  29. data/lib/log4r/outputter/rollingfileoutputter.rb +234 -0
  30. data/lib/log4r/outputter/scribeoutputter.rb +37 -0
  31. data/lib/log4r/outputter/staticoutputter.rb +30 -0
  32. data/lib/log4r/outputter/syslogoutputter.rb +126 -0
  33. data/lib/log4r/outputter/udpoutputter.rb +53 -0
  34. data/lib/log4r/railtie.rb +211 -0
  35. data/lib/log4r/rdoc/GDC +14 -0
  36. data/lib/log4r/rdoc/MDC +16 -0
  37. data/lib/log4r/rdoc/NDC +41 -0
  38. data/lib/log4r/rdoc/configurator +243 -0
  39. data/lib/log4r/rdoc/emailoutputter +103 -0
  40. data/lib/log4r/rdoc/formatter +39 -0
  41. data/lib/log4r/rdoc/log4jxmlformatter +21 -0
  42. data/lib/log4r/rdoc/log4r +89 -0
  43. data/lib/log4r/rdoc/logger +175 -0
  44. data/lib/log4r/rdoc/logserver +85 -0
  45. data/lib/log4r/rdoc/outputter +108 -0
  46. data/lib/log4r/rdoc/patternformatter +128 -0
  47. data/lib/log4r/rdoc/scribeoutputter +16 -0
  48. data/lib/log4r/rdoc/syslogoutputter +29 -0
  49. data/lib/log4r/rdoc/win32eventoutputter +7 -0
  50. data/lib/log4r/rdoc/yamlconfigurator +20 -0
  51. data/lib/log4r/repository.rb +88 -0
  52. data/lib/log4r/staticlogger.rb +49 -0
  53. data/lib/log4r/version.rb +4 -0
  54. data/lib/log4r/yamlconfigurator.rb +198 -0
  55. data/lib/log4rails.rb +22 -0
  56. metadata +97 -0
@@ -0,0 +1,40 @@
1
+ # :nodoc:
2
+ require 'log4r/lib/drbloader'
3
+ require 'log4r/outputter/outputter'
4
+
5
+ module Log4r
6
+ # See log4r/logserver.rb
7
+ class RemoteOutputter < Outputter
8
+
9
+ def initialize(_name, hash={})
10
+ super(_name, hash)
11
+ @uri = (hash[:uri] or hash['uri'])
12
+ @buffsize = (hash[:buffsize] or hash['buffsize'] or 1).to_i
13
+ @buff = []
14
+ connect
15
+ end
16
+
17
+ if HAVE_ROMP
18
+ include ROMPClient
19
+ else
20
+ def initialize(*args)
21
+ raise RuntimeError, "LogServer not supported. ROMP is required", caller
22
+ end
23
+ end
24
+
25
+
26
+ # Call flush to send any remaining LogEvents to the remote server.
27
+ def flush
28
+ synch { send_buffer }
29
+ end
30
+
31
+ private
32
+
33
+ def canonical_log(logevent)
34
+ synch {
35
+ @buff.push logevent
36
+ send_buffer if @buff.size >= @buffsize
37
+ }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,234 @@
1
+
2
+ # :nodoc:
3
+ # Version:: $Id: rollingfileoutputter.rb,v 1.2 2009/09/29 18:13:13 colbygk Exp $
4
+
5
+ require "log4r/outputter/fileoutputter"
6
+ require "log4r/staticlogger"
7
+
8
+ require 'fileutils'
9
+
10
+ module Log4r
11
+
12
+ # RollingFileOutputter - subclass of FileOutputter that rolls files on size
13
+ # or time. So, given a filename of "error.log", the first log file will be "error000001.log".
14
+ # When its check condition is exceeded, it'll create and log to "error000002.log", etc.
15
+ #
16
+ # Additional hash arguments are:
17
+ #
18
+ # [<tt>:maxsize</tt>] Maximum size of the file in bytes.
19
+ # [<tt>:maxtime</tt>] Maximum age of the file in seconds.
20
+ # [<tt>:max_backups</tt>] Maxium number of prior log files to maintain. If max_backups is a positive number,
21
+ # then each time a roll happens, RollingFileOutputter will delete the oldest backup log files in excess
22
+ # of this number (if any). So, if max_backups is 10, then a maximum of 11 files will be maintained (the current
23
+ # log, plus 10 backups). If max_backups is 0, no backups will be kept. If it is negative (the default),
24
+ # there will be no limit on the number of files created. Note that the sequence numbers will continue to escalate;
25
+ # old sequence numbers are not reused.
26
+ # [<tt>:trunc</tt>] If true, deletes ALL existing log files (based on :filename) upon initialization,
27
+ # and the sequence numbering will start over at 000001. Otherwise continues logging where it left off
28
+ # last time (i.e. either to the file with the highest sequence number, or a new file, as appropriate).
29
+ class RollingFileOutputter < FileOutputter
30
+
31
+ attr_reader :current_sequence_number, :maxsize, :maxtime, :start_time, :max_backups
32
+
33
+ def initialize(_name, hash={})
34
+ super( _name, hash.merge({:create => false}) )
35
+ if hash.has_key?(:maxsize) || hash.has_key?('maxsize')
36
+ _maxsize = (hash[:maxsize] or hash['maxsize']).to_i
37
+ if _maxsize.class != Fixnum
38
+ raise TypeError, "Argument 'maxsize' must be an Fixnum", caller
39
+ end
40
+ if _maxsize == 0
41
+ raise TypeError, "Argument 'maxsize' must be > 0", caller
42
+ end
43
+ @maxsize = _maxsize
44
+ end
45
+ if hash.has_key?(:maxtime) || hash.has_key?('maxtime')
46
+ _maxtime = (hash[:maxtime] or hash['maxtime']).to_i
47
+ if _maxtime.class != Fixnum
48
+ raise TypeError, "Argument 'maxtime' must be an Fixnum", caller
49
+ end
50
+ if _maxtime == 0
51
+ raise TypeError, "Argument 'maxtime' must be > 0", caller
52
+ end
53
+ @maxtime = _maxtime
54
+ end
55
+ if hash.has_key?(:max_backups) || hash.has_key?('max_backups')
56
+ _max_backups = (hash[:max_backups] or hash['max_backups']).to_i
57
+ if _max_backups.class != Fixnum
58
+ raise TypeError, "Argument 'max_backups' must be an Fixnum", caller
59
+ end
60
+ @max_backups = _max_backups
61
+ else
62
+ @max_backups = -1
63
+ end
64
+ # @filename starts out as the file (including path) provided by the user, e.g. "\usr\logs\error.log".
65
+ # It will get assigned the current log file (including sequence number)
66
+ # @log_dir is the directory in which we'll log, e.g. "\usr\logs"
67
+ # @file_extension is the file's extension (if any) including any period, e.g. ".log"
68
+ # @core_file_name is the part of the log file's name, sans sequence digits or extension, e.g. "error"
69
+ @log_dir = File.dirname(@filename)
70
+ @file_extension = File.extname(@filename) # Note: the File API doc comment states that this doesn't include the period, but its examples and behavior do include it. We'll depend on the latter.
71
+ @core_file_name = File.basename(@filename, @file_extension)
72
+ if (@trunc)
73
+ purge_log_files(0)
74
+ end
75
+ @current_sequence_number = get_current_sequence_number()
76
+ makeNewFilename
77
+ # Now @filename points to a properly sequenced filename, which may or may not yet exist.
78
+ open_log_file('a')
79
+
80
+ # Note: it's possible we're already in excess of our time or size constraint for the current file;
81
+ # no worries -- if a new file needs to be started, it'll happen during the write() call.
82
+ end
83
+
84
+ #######
85
+ private
86
+ #######
87
+
88
+ # Delete all but the latest number_to_keep log files.
89
+ def purge_log_files(number_to_keep)
90
+ Dir.chdir(@log_dir) do
91
+ # Make a list of the log files to delete. Start with all of the matching log files...
92
+ glob = "#{@core_file_name}[0-9][0-9][0-9][0-9][0-9][0-9]#{@file_extension}"
93
+ files = Dir.glob(glob)
94
+
95
+ # ... if there are fewer than our threshold, just return...
96
+ if (files.size() <= number_to_keep )
97
+ # Logger.log_internal {"No log files need purging."}
98
+ return
99
+ end
100
+ # ...then remove those that we want to keep (i.e. the most recent #{number_to_keep} files).
101
+ files.sort!().slice!(-number_to_keep, number_to_keep)
102
+
103
+ # Delete the files. We use force (rm_f), so in case any files can't be deleted (e.g. someone's got one
104
+ # open in an editor), we'll swallow the error and keep going.
105
+ FileUtils.rm_f(files)
106
+ Logger.log_internal { "Purged #{files.length} log files: #{files}" }
107
+ end
108
+ end
109
+
110
+ # Get the highest existing log file sequence number, or 1 if there are no existing log files.
111
+ def get_current_sequence_number()
112
+ max_seq_no = 0
113
+ Dir.foreach(@log_dir) do |child|
114
+ if child =~ /^#{@core_file_name}(\d+)#{@file_extension}$/
115
+ seq_no = $1.to_i
116
+ if (seq_no > max_seq_no)
117
+ max_seq_no = seq_no
118
+ end
119
+ end
120
+ end
121
+ return [max_seq_no, 1].max
122
+ end
123
+
124
+ # perform the write
125
+ def write(data)
126
+ # we have to keep track of the file size ourselves - File.size doesn't
127
+ # seem to report the correct size when the size changes rapidly
128
+ @datasize += data.size + 1 # the 1 is for newline
129
+ roll if requiresRoll
130
+ super
131
+ end
132
+
133
+ # Constructs a new filename from the @current_sequence_number, @core_file_name, and @file_extension,
134
+ # and assigns it to @filename
135
+ def makeNewFilename
136
+ # note use of hard coded 6 digit sequence width - is this enough files?
137
+ padded_seq_no = "0" * (6 - @current_sequence_number.to_s.length) + @current_sequence_number.to_s
138
+ newbase = "#{@core_file_name}#{padded_seq_no}#{@file_extension}"
139
+ @filename = File.join(@log_dir, newbase)
140
+ end
141
+
142
+ # Open @filename with the given mode:
143
+ # 'a' - appends to the end of the file if it exists; otherwise creates it.
144
+ # 'w' - truncates the file to zero length if it exists, otherwise creates it.
145
+ # Re-initializes @datasize and @startime appropriately.
146
+ def open_log_file(mode)
147
+ # It appears that if a file has been recently deleted then recreated, calls like
148
+ # File.ctime can return the erstwhile creation time. File.size? can similarly return
149
+ # old information. So instead of simply doing ctime and size checks after File.new, we
150
+ # do slightly more complicated checks beforehand:
151
+ if (mode == 'w' || !File.exists?(@filename))
152
+ @start_time = Time.now()
153
+ @datasize = 0
154
+ else
155
+ @start_time = File.ctime(@filename)
156
+ @datasize = File.size?(@filename) || 0 # File.size? returns nil even if the file exists but is empty; we convert it to 0.
157
+ end
158
+ @out = File.new(@filename, mode)
159
+ Logger.log_internal {"File #{@filename} opened with mode #{mode}"}
160
+ end
161
+
162
+ # does the file require a roll?
163
+ def requiresRoll
164
+ if !@maxsize.nil? && @datasize > @maxsize
165
+ Logger.log_internal { "Rolling because #{@filename} (#{@datasize} bytes) has exceded the maxsize limit (#{@maxsize} bytes)." }
166
+ return true
167
+ end
168
+ if !@maxtime.nil? && (Time.now - @start_time) > @maxtime
169
+ Logger.log_internal { "Rolling because #{@filename} (created: #{@start_time}) has exceded the maxtime age (#{@maxtime} seconds)." }
170
+ return true
171
+ end
172
+ false
173
+ end
174
+
175
+ # roll the file
176
+ def roll
177
+ begin
178
+ # If @baseFilename == @filename, then this method is about to
179
+ # try to close out a file that is not actually opened because
180
+ # fileoutputter has been called with the parameter roll=true
181
+ # TODO: Is this check valid any more? I suspect not. Am commenting out...:
182
+ #if ( @baseFilename != @filename ) then
183
+ @out.close
184
+ #end
185
+ rescue
186
+ Logger.log_internal {
187
+ "RollingFileOutputter '#{@name}' could not close #{@filename}"
188
+ }
189
+ end
190
+
191
+ # Prepare the next file. (Note: if max_backups is zero, we can skip this; we'll
192
+ # just overwrite the existing log file)
193
+ if (@max_backups != 0)
194
+ @current_sequence_number += 1
195
+ makeNewFilename
196
+ end
197
+
198
+ open_log_file('w')
199
+
200
+ # purge any excess log files (unless max_backups is negative, which means don't purge).
201
+ if (@max_backups >= 0)
202
+ purge_log_files(@max_backups + 1)
203
+ end
204
+
205
+ end
206
+
207
+ end
208
+
209
+ end
210
+
211
+ # this can be found in examples/fileroll.rb as well
212
+ if __FILE__ == $0
213
+ require 'log4r'
214
+ include Log4r
215
+
216
+
217
+ timeLog = Logger.new 'WbExplorer'
218
+ timeLog.outputters = RollingFileOutputter.new("WbExplorer", { "filename" => "TestTime.log", "maxtime" => 10, "trunc" => true })
219
+ timeLog.level = DEBUG
220
+
221
+ 100.times { |t|
222
+ timeLog.info "blah #{t}"
223
+ sleep(1.0)
224
+ }
225
+
226
+ sizeLog = Logger.new 'WbExplorer'
227
+ sizeLog.outputters = RollingFileOutputter.new("WbExplorer", { "filename" => "TestSize.log", "maxsize" => 16000, "trunc" => true })
228
+ sizeLog.level = DEBUG
229
+
230
+ 10000.times { |t|
231
+ sizeLog.info "blah #{t}"
232
+ }
233
+
234
+ end
@@ -0,0 +1,37 @@
1
+ # :nodoc:
2
+ # Version:: $Id$
3
+
4
+ require "log4r/outputter/outputter"
5
+ require "rubygems"
6
+ require "scribe"
7
+
8
+ module Log4r
9
+ class ScribeOutputter < Outputter
10
+ attr_reader :host, :port, :category
11
+
12
+ def initialize(_name, hash={})
13
+ super(_name, hash)
14
+ @host = (hash[:host] or hash[:host] or 'localhost')
15
+ @port = (hash[:port] or hash[:port] or '1463')
16
+ @category = (hash[:category] or hash[:category] or 'default')
17
+
18
+ @client = Scribe.new("#{@host}:#{@port}", category=@category, add_newlines=false)
19
+ end
20
+
21
+ private
22
+
23
+ def write(data)
24
+ begin
25
+ @client.log(data.strip, @category)
26
+ rescue ScribeThrift::Client::TransportException => e
27
+ Logger.log_internal(-2) {
28
+ "Caught TransportException, is the scribe server alive?"
29
+ }
30
+ rescue ThriftClient::NoServersAvailable => e
31
+ Logger.log_internal(-2) {
32
+ "No scribe servers are available!"
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,30 @@
1
+ # :nodoc:
2
+ module Log4r
3
+
4
+ class Outputter < Monitor
5
+ # Retrieve an outputter.
6
+ def self.[](name)
7
+ out = @@outputters[name]
8
+ if out.nil?
9
+ return case name
10
+ when 'stdout' then StdoutOutputter.new 'stdout'
11
+ when 'stderr' then StderrOutputter.new 'stderr'
12
+ else nil end
13
+ end
14
+ out
15
+ end
16
+ def self.stdout; Outputter['stdout'] end
17
+ def self.stderr; Outputter['stderr'] end
18
+ # Set an outputter.
19
+ def self.[]=(name, outputter)
20
+ @@outputters[name] = outputter
21
+ end
22
+ # Yields each outputter's name and reference.
23
+ def self.each
24
+ @@outputters.each {|name, outputter| yield name, outputter}
25
+ end
26
+ def self.each_outputter
27
+ @@outputters.each_value {|outputter| yield outputter}
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,126 @@
1
+ # :include: ../rdoc/syslogoutputter
2
+ #
3
+ # Version:: $Id$
4
+ # Author:: Steve Lumos
5
+ # Author:: Leon Torres
6
+
7
+ require 'log4r/formatter/formatter'
8
+ require 'log4r/outputter/outputter'
9
+ require 'log4r/configurator'
10
+ require 'syslog'
11
+
12
+ module Log4r
13
+
14
+ SYSLOGNAMES = Hash.new
15
+
16
+ class SyslogOutputter < Outputter
17
+ include Syslog::Constants
18
+
19
+ # maps default log4r levels to syslog priorities (logevents never see ALL and OFF)
20
+ # SYSLOG Levels are:
21
+ # "DEBUG" => Syslog::LOG_DEBUG
22
+ # "INFO" => Syslog::LOG_INFO
23
+ # "NOTICE" => Syslog::LOG_NOTICE
24
+ # "WARN" => Syslog::LOG_WARN
25
+ # "ERROR" => Syslog::LOG_ERROR
26
+ # "FATAL" => Syslog::LOG_FATAL
27
+ # "ALERT" => Syslog::LOG_ALERT
28
+ # "EMERG" => Syslog::LOG_EMERG
29
+ SYSLOG_LEVELS_MAP = {
30
+ "DEBUG" => LOG_DEBUG,
31
+ "INFO" => LOG_INFO,
32
+ "NOTICE" => LOG_NOTICE, # by default NOTICE is not in log4r
33
+ "WARN" => LOG_WARNING,
34
+ "ERROR" => LOG_ERR,
35
+ "FATAL" => LOG_CRIT,
36
+ "ALERT" => LOG_ALERT, # by default ALERT is not in log4r
37
+ "EMERG" => LOG_EMERG, # by default EMERG is not in log4r
38
+ }
39
+
40
+ # mapping from Log4r default levels to syslog, by string name
41
+ # "DEBUG" => "DEBUG"
42
+ # "INFO" => "INFO"
43
+ # "WARN" => "WARN"
44
+ # "ERROR" => "ERROR"
45
+ # "FATAL" => "FATAL"
46
+ SYSLOG_LOG4R_MAP = {
47
+ "DEBUG" => "DEBUG",
48
+ "INFO" => "INFO",
49
+ "WARN" => "WARN",
50
+ "ERROR" => "ERROR",
51
+ "FATAL" => "FATAL"
52
+ # "NOTICE" => "INFO", # by default NOTICE is not in log4r
53
+ # "ALERT" => "FATAL", # by default ALERT is not in log4r
54
+ # "EMERG" => "FATAL" # by default EMERG is not in log4r
55
+ }
56
+
57
+ @levels_map = SYSLOG_LOG4R_MAP
58
+
59
+ # There are 3 hash arguments
60
+ #
61
+ # [<tt>:ident</tt>] syslog ident, defaults to _name
62
+ # [<tt>:logopt</tt>] syslog logopt, defaults to LOG_PID | LOG_CONS
63
+ # [<tt>:facility</tt>] syslog facility, defaults to LOG_USER
64
+ def initialize(_name, hash={})
65
+ super(_name, hash)
66
+ @ident = (hash[:ident] or hash['ident'] or _name)
67
+ @logopt = (hash[:logopt] or hash['logopt'] or LOG_PID | LOG_CONS).to_i
68
+ @facility = (hash[:facility] or hash['facility'] or LOG_USER).to_i
69
+ map_levels_by_name_to_syslog()
70
+ end
71
+
72
+ def closed?
73
+ @level == OFF
74
+ end
75
+
76
+ def close
77
+ @level = OFF
78
+ OutputterFactory.create_methods(self)
79
+ Logger.log_internal {"Outputter '#{@name}' closed Syslog and set to OFF"}
80
+ end
81
+
82
+ # A single hash argument that maps custom names to syslog names
83
+ #
84
+ # [<tt>levels_map</tt>] A map that will create a linkage between levels
85
+ # in a hash and underlying syslog levels.
86
+ # By default, these are direct mapping of the log4r
87
+ # levels (e.g. "DEBUG" => "DEBUG")
88
+ # If you have defined your own custom levels, you
89
+ # should provide this underlying mapping, otherwise
90
+ # all messages will be mapped to the underlying syslog
91
+ # level of INFO by default.
92
+ # e.g.
93
+ # You have created custom levels called:
94
+ # <tt>Configurator.custom_levels "HIGH", "MEDIUM", "LOW"</tt>
95
+ # To map these to 'equivilent' syslog levels, after instantiatin
96
+ # a syslogoutputter:
97
+ # <tt>SyslogOutputter.map_levels_by_name_to_syslog(
98
+ # { "HIGH" => "ALERT", "MEDIUM" => "WARN", "LOW" => "INFO" }
99
+ # )</tt>
100
+ def map_levels_by_name_to_syslog( lmap = SYSLOG_LOG4R_MAP )
101
+ @levels_map = lmap
102
+ end
103
+
104
+ def get_levels_map()
105
+ return @levels_map
106
+ end
107
+
108
+ private
109
+
110
+ def canonical_log(logevent)
111
+ pri = SYSLOG_LEVELS_MAP[@levels_map[LNAMES[logevent.level]]] rescue pri = LOG_INFO
112
+ o = format(logevent)
113
+ if o.kind_of? Exception then
114
+ msg = "#{o.class} at (#{o.backtrace[0]}): #{o.message}"
115
+ elsif o.respond_to? :to_str then
116
+ msg = o.to_str
117
+ else
118
+ msg = o.inspect
119
+ end
120
+
121
+ Syslog.open(@ident, @logopt, @facility) do |s|
122
+ s.log(pri, '%s', msg)
123
+ end
124
+ end
125
+ end
126
+ end