filterfish-logging 0.9.8

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 (55) hide show
  1. data/History.txt +176 -0
  2. data/Manifest.txt +54 -0
  3. data/README.txt +93 -0
  4. data/Rakefile +28 -0
  5. data/data/logging.yaml +63 -0
  6. data/lib/logging.rb +288 -0
  7. data/lib/logging/appender.rb +257 -0
  8. data/lib/logging/appenders/console.rb +43 -0
  9. data/lib/logging/appenders/email.rb +131 -0
  10. data/lib/logging/appenders/file.rb +55 -0
  11. data/lib/logging/appenders/growl.rb +182 -0
  12. data/lib/logging/appenders/io.rb +81 -0
  13. data/lib/logging/appenders/rolling_file.rb +293 -0
  14. data/lib/logging/appenders/syslog.rb +202 -0
  15. data/lib/logging/config/yaml_configurator.rb +197 -0
  16. data/lib/logging/layout.rb +103 -0
  17. data/lib/logging/layouts/basic.rb +35 -0
  18. data/lib/logging/layouts/pattern.rb +292 -0
  19. data/lib/logging/log_event.rb +50 -0
  20. data/lib/logging/logger.rb +388 -0
  21. data/lib/logging/repository.rb +151 -0
  22. data/lib/logging/root_logger.rb +60 -0
  23. data/lib/logging/utils.rb +44 -0
  24. data/tasks/ann.rake +78 -0
  25. data/tasks/bones.rake +21 -0
  26. data/tasks/gem.rake +106 -0
  27. data/tasks/manifest.rake +49 -0
  28. data/tasks/notes.rake +22 -0
  29. data/tasks/post_load.rake +37 -0
  30. data/tasks/rdoc.rake +49 -0
  31. data/tasks/rubyforge.rake +57 -0
  32. data/tasks/setup.rb +253 -0
  33. data/tasks/svn.rake +45 -0
  34. data/tasks/test.rake +38 -0
  35. data/test/appenders/test_console.rb +40 -0
  36. data/test/appenders/test_email.rb +167 -0
  37. data/test/appenders/test_file.rb +94 -0
  38. data/test/appenders/test_growl.rb +115 -0
  39. data/test/appenders/test_io.rb +113 -0
  40. data/test/appenders/test_rolling_file.rb +187 -0
  41. data/test/appenders/test_syslog.rb +192 -0
  42. data/test/benchmark.rb +88 -0
  43. data/test/config/test_yaml_configurator.rb +41 -0
  44. data/test/layouts/test_basic.rb +44 -0
  45. data/test/layouts/test_pattern.rb +173 -0
  46. data/test/setup.rb +66 -0
  47. data/test/test_appender.rb +162 -0
  48. data/test/test_layout.rb +85 -0
  49. data/test/test_log_event.rb +81 -0
  50. data/test/test_logger.rb +589 -0
  51. data/test/test_logging.rb +250 -0
  52. data/test/test_repository.rb +123 -0
  53. data/test/test_root_logger.rb +82 -0
  54. data/test/test_utils.rb +48 -0
  55. metadata +126 -0
@@ -0,0 +1,151 @@
1
+ # $Id$
2
+
3
+ require 'singleton'
4
+
5
+ module Logging
6
+
7
+ # The Repository is a hash that stores references to all Loggers
8
+ # that have been created. It provides methods to determine parent/child
9
+ # relationships between Loggers and to retrieve Loggers from the hash.
10
+ #
11
+ class Repository
12
+ include Singleton
13
+
14
+ PATH_DELIMITER = '::' # :nodoc:
15
+
16
+ # nodoc:
17
+ #
18
+ # This is a singleton class -- use the +instance+ method to obtain the
19
+ # +Repository+ instance.
20
+ #
21
+ def initialize
22
+ @h = {:root => ::Logging::RootLogger.new}
23
+ end
24
+
25
+ # call-seq:
26
+ # instance[name]
27
+ #
28
+ # Returns the +Logger+ named _name_.
29
+ #
30
+ # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
31
+ # retrieve the logger. When _name_ is a +Class+ the class name will be
32
+ # used to retrieve the logger. When _name_ is an object the name of the
33
+ # object's class will be used to retrieve the logger.
34
+ #
35
+ # Example:
36
+ #
37
+ # repo = Repository.instance
38
+ # obj = MyClass.new
39
+ #
40
+ # log1 = repo[obj]
41
+ # log2 = repo[MyClass]
42
+ # log3 = repo['MyClass']
43
+ #
44
+ # log1.object_id == log2.object_id # => true
45
+ # log2.object_id == log3.object_id # => true
46
+ #
47
+ def []( key ) @h[to_key(key)] end
48
+
49
+ # call-seq:
50
+ # instance[name] = logger
51
+ #
52
+ # Stores the _logger_ under the given _name_.
53
+ #
54
+ # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
55
+ # store the logger. When _name_ is a +Class+ the class name will be
56
+ # used to store the logger. When _name_ is an object the name of the
57
+ # object's class will be used to store the logger.
58
+ #
59
+ def []=( key, val ) @h[to_key(key)] = val end
60
+
61
+ # call-seq:
62
+ # fetch( name )
63
+ #
64
+ # Returns the +Logger+ named _name_. An +IndexError+ will be raised if
65
+ # the logger does not exist.
66
+ #
67
+ # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
68
+ # retrieve the logger. When _name_ is a +Class+ the class name will be
69
+ # used to retrieve the logger. When _name_ is an object the name of the
70
+ # object's class will be used to retrieve the logger.
71
+ #
72
+ def fetch( key ) @h.fetch(to_key(key)) end
73
+
74
+ # call-seq:
75
+ # has_logger?( name )
76
+ #
77
+ # Returns +true+ if the given logger exists in the repository. Returns
78
+ # +false+ if this is not the case.
79
+ #
80
+ # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
81
+ # retrieve the logger. When _name_ is a +Class+ the class name will be
82
+ # used to retrieve the logger. When _name_ is an object the name of the
83
+ # object's class will be used to retrieve the logger.
84
+ #
85
+ def has_logger?( key ) @h.has_key?(to_key(key)) end
86
+
87
+ # call-seq:
88
+ # parent( key )
89
+ #
90
+ # Returns the parent logger for the logger identified by _key_ where
91
+ # _key_ follows the same identification rules described in
92
+ # +Repository#[]+. A parent is returned regardless of the
93
+ # existence of the logger referenced by _key_.
94
+ #
95
+ def parent( key )
96
+ key = to_key(key)
97
+ a = key.split PATH_DELIMITER
98
+
99
+ p = @h[:root]
100
+ while a.slice!(-1) and !a.empty?
101
+ k = a.join PATH_DELIMITER
102
+ if @h.has_key? k then p = @h[k]; break end
103
+ end
104
+ p
105
+ end
106
+
107
+ # call-seq:
108
+ # children( key )
109
+ #
110
+ # Returns an array of the children loggers for the logger identified by
111
+ # _key_ where _key_ follows the same identification rules described in
112
+ # +Repository#[]+. Children are returned regardless of the
113
+ # existence of the logger referenced by _key_.
114
+ #
115
+ def children( key )
116
+ key = to_key(key)
117
+ depth = key.split(PATH_DELIMITER).length
118
+ rgxp = Regexp.new "^#{key}#{PATH_DELIMITER}"
119
+
120
+ a = @h.keys.map do |k|
121
+ if k =~ rgxp
122
+ l = @h[k]
123
+ d = l.parent.name.split(PATH_DELIMITER).length
124
+ if d <= depth then l else nil end
125
+ end
126
+ end
127
+ a.compact.sort
128
+ end
129
+
130
+ # call-seq:
131
+ # to_key( key )
132
+ #
133
+ # Takes the given _key_ and converts it into a form that can be used to
134
+ # retrieve a logger from the +Repository+ hash.
135
+ #
136
+ # When _key_ is a +String+ or a +Symbol+ it will be returned "as is".
137
+ # When _key_ is a +Class+ the class name will be returned. When _key_ is
138
+ # an object the name of the object's class will be returned.
139
+ #
140
+ def to_key( key )
141
+ case key
142
+ when Symbol, String; key
143
+ when Class; key.name
144
+ when Object; key.class.name
145
+ end
146
+ end
147
+
148
+ end # class Repository
149
+ end # module Logging
150
+
151
+ # EOF
@@ -0,0 +1,60 @@
1
+ # $Id$
2
+
3
+ module Logging
4
+
5
+ # The root logger exists to ensure that all loggers have a parent and a
6
+ # defined logging level. If a logger is additive, eventually its log
7
+ # events will propogate up to the root logger.
8
+ #
9
+ class RootLogger < Logger
10
+
11
+ # undefine the methods that the root logger does not need
12
+ %w(additive additive= parent parent=).each do |m|
13
+ undef_method m.intern
14
+ end
15
+
16
+ # call-seq:
17
+ # RootLogger.new
18
+ #
19
+ # Returns a new root logger instance. This method will be called only
20
+ # once when the +Repository+ singleton instance is created.
21
+ #
22
+ def initialize( )
23
+ ::Logging.init unless ::Logging.const_defined? 'MAX_LEVEL_LENGTH'
24
+
25
+ @name = 'root'
26
+ @appenders = []
27
+ @additive = false
28
+ @trace = false
29
+ self.level = 0
30
+ end
31
+
32
+ # call-seq:
33
+ # log <=> other
34
+ #
35
+ # Compares this logger by name to another logger. The normal return codes
36
+ # for +String+ objects apply.
37
+ #
38
+ def <=>( other )
39
+ case other
40
+ when self; 0
41
+ when ::Logging::Logger; -1
42
+ else raise ArgumentError, 'expecting a Logger instance' end
43
+ end
44
+
45
+ # call-seq:
46
+ # level = :all
47
+ #
48
+ # Set the level for the root logger. The functionality of this method is
49
+ # the same as +Logger#level=+, but setting the level to +nil+ for the
50
+ # root logger is not allowed. The level is silently set to :all.
51
+ #
52
+ def level=( level )
53
+ level ||= 0
54
+ super
55
+ end
56
+
57
+ end # class RootLogger
58
+ end # module Logging
59
+
60
+ # EOF
@@ -0,0 +1,44 @@
1
+ # $Id$
2
+
3
+ class Hash
4
+
5
+ # call-seq:
6
+ # getopt( key, default = nil, :as => class )
7
+ #
8
+ # Returns the value associated with the _key_. If the has does not contain
9
+ # the _key_, then the _default_ value is returned.
10
+ #
11
+ # Optionally, the value can be converted into to an instance of the given
12
+ # _class_. The supported classes are:
13
+ #
14
+ # Integer
15
+ # Float
16
+ # Array
17
+ # String
18
+ # Symbol
19
+ #
20
+ # If the value is +nil+, then no converstion will be performed.
21
+ #
22
+ def getopt( *args )
23
+ opts = args.last.instance_of?(Hash) ? args.pop : {}
24
+ key, default = args
25
+
26
+ val = if has_key?(key); self[key]
27
+ elsif has_key?(key.to_s); self[key.to_s]
28
+ elsif has_key?(key.to_s.intern); self[key.to_s.intern]
29
+ else default end
30
+
31
+ return if val.nil?
32
+ return val unless opts.has_key?(:as)
33
+
34
+ case opts[:as].name.intern
35
+ when :Integer; Integer(val)
36
+ when :Float; Float(val)
37
+ when :Array; Array(val)
38
+ when :String; String(val)
39
+ when :Symbol; String(val).intern
40
+ else val end
41
+ end
42
+ end
43
+
44
+ # EOF
data/tasks/ann.rake ADDED
@@ -0,0 +1,78 @@
1
+ # $Id$
2
+
3
+ begin
4
+ require 'bones/smtp_tls'
5
+ rescue LoadError
6
+ require 'net/smtp'
7
+ end
8
+ require 'time'
9
+
10
+ namespace :ann do
11
+
12
+ file PROJ.ann.file do
13
+ ann = PROJ.ann
14
+ puts "Generating #{ann.file}"
15
+ File.open(ann.file,'w') do |fd|
16
+ fd.puts("#{PROJ.name} version #{PROJ.version}")
17
+ fd.puts(" by #{Array(PROJ.authors).first}") if PROJ.authors
18
+ fd.puts(" #{PROJ.url}") if PROJ.url
19
+ fd.puts(" (the \"#{PROJ.release_name}\" release)") if PROJ.release_name
20
+ fd.puts
21
+ fd.puts("== DESCRIPTION")
22
+ fd.puts
23
+ fd.puts(PROJ.description)
24
+ fd.puts
25
+ fd.puts(PROJ.changes.sub(%r/^.*$/, '== CHANGES'))
26
+ fd.puts
27
+ ann.paragraphs.each do |p|
28
+ fd.puts "== #{p.upcase}"
29
+ fd.puts
30
+ fd.puts paragraphs_of(PROJ.readme_file, p).join("\n\n")
31
+ fd.puts
32
+ end
33
+ fd.puts ann.text if ann.text
34
+ end
35
+ end
36
+
37
+ desc "Create an announcement file"
38
+ task :announcement => PROJ.ann.file
39
+
40
+ desc "Send an email announcement"
41
+ task :email => PROJ.ann.file do
42
+ ann = PROJ.ann
43
+ from = ann.email[:from] || PROJ.email
44
+ to = Array(ann.email[:to])
45
+
46
+ ### build a mail header for RFC 822
47
+ rfc822msg = "From: #{from}\n"
48
+ rfc822msg << "To: #{to.join(',')}\n"
49
+ rfc822msg << "Subject: [ANN] #{PROJ.name} #{PROJ.version}"
50
+ rfc822msg << " (#{PROJ.release_name})" if PROJ.release_name
51
+ rfc822msg << "\n"
52
+ rfc822msg << "Date: #{Time.new.rfc822}\n"
53
+ rfc822msg << "Message-Id: "
54
+ rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{ann.email[:domain]}>\n\n"
55
+ rfc822msg << File.read(ann.file)
56
+
57
+ params = [:server, :port, :domain, :acct, :passwd, :authtype].map do |key|
58
+ ann.email[key]
59
+ end
60
+
61
+ params[3] = PROJ.email if params[3].nil?
62
+
63
+ if params[4].nil?
64
+ STDOUT.write "Please enter your e-mail password (#{params[3]}): "
65
+ params[4] = STDIN.gets.chomp
66
+ end
67
+
68
+ ### send email
69
+ Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
70
+ end
71
+ end # namespace :ann
72
+
73
+ desc 'Alias to ann:announcement'
74
+ task :ann => 'ann:announcement'
75
+
76
+ CLOBBER << PROJ.ann.file
77
+
78
+ # EOF
data/tasks/bones.rake ADDED
@@ -0,0 +1,21 @@
1
+ # $Id$
2
+
3
+ if HAVE_BONES
4
+
5
+ namespace :bones do
6
+
7
+ desc 'Show the PROJ open struct'
8
+ task :debug do |t|
9
+ atr = if ARGV.length == 2
10
+ t.application.top_level_tasks.pop
11
+ end
12
+
13
+ if atr then Bones::Debug.show_attr(PROJ, atr)
14
+ else Bones::Debug.show PROJ end
15
+ end
16
+
17
+ end # namespace :bones
18
+
19
+ end # HAVE_BONES
20
+
21
+ # EOF
data/tasks/gem.rake ADDED
@@ -0,0 +1,106 @@
1
+ # $Id$
2
+
3
+ require 'rake/gempackagetask'
4
+
5
+ namespace :gem do
6
+
7
+ PROJ.gem.spec = Gem::Specification.new do |s|
8
+ s.name = PROJ.name
9
+ s.version = PROJ.version
10
+ s.summary = PROJ.summary
11
+ s.authors = Array(PROJ.authors)
12
+ s.email = PROJ.email
13
+ s.homepage = Array(PROJ.url).first
14
+ s.rubyforge_project = PROJ.rubyforge.name
15
+ s.post_install_message = PROJ.gem.post_install_message
16
+
17
+ s.description = PROJ.description
18
+
19
+ PROJ.gem.dependencies.each do |dep|
20
+ s.add_dependency(*dep)
21
+ end
22
+
23
+ s.files = PROJ.gem.files
24
+ s.executables = PROJ.gem.executables.map {|fn| File.basename(fn)}
25
+ s.extensions = PROJ.gem.files.grep %r/extconf\.rb$/
26
+
27
+ s.bindir = 'bin'
28
+ dirs = Dir["{#{PROJ.libs.join(',')}}"]
29
+ s.require_paths = dirs unless dirs.empty?
30
+
31
+ incl = Regexp.new(PROJ.rdoc.include.join('|'))
32
+ excl = PROJ.rdoc.exclude.dup.concat %w[\.rb$ ^(\.\/|\/)?ext]
33
+ excl = Regexp.new(excl.join('|'))
34
+ rdoc_files = PROJ.gem.files.find_all do |fn|
35
+ case fn
36
+ when excl; false
37
+ when incl; true
38
+ else false end
39
+ end
40
+ s.rdoc_options = PROJ.rdoc.opts + ['--main', PROJ.rdoc.main]
41
+ s.extra_rdoc_files = rdoc_files
42
+ s.has_rdoc = true
43
+
44
+ if test ?f, PROJ.test.file
45
+ s.test_file = PROJ.test.file
46
+ else
47
+ s.test_files = PROJ.test.files.to_a
48
+ end
49
+ end
50
+
51
+ desc 'Show information about the gem'
52
+ task :debug do
53
+ puts PROJ.gem.spec.to_ruby
54
+ end
55
+
56
+ pkg = Rake::PackageTask.new(PROJ.name, PROJ.version) do |pkg|
57
+ pkg.need_tar = PROJ.gem.need_tar
58
+ pkg.need_zip = PROJ.gem.need_zip
59
+ pkg.package_files += PROJ.gem.spec.files
60
+ end
61
+ Rake::Task['gem:package'].instance_variable_set(:@full_comment, nil)
62
+
63
+ gem_file = if PROJ.gem.spec.platform == Gem::Platform::RUBY
64
+ "#{pkg.package_name}.gem"
65
+ else
66
+ "#{pkg.package_name}-#{PROJ.gem.spec.platform}.gem"
67
+ end
68
+
69
+ desc "Build the gem file #{gem_file}"
70
+ task :package => "#{pkg.package_dir}/#{gem_file}"
71
+
72
+ file "#{pkg.package_dir}/#{gem_file}" => [pkg.package_dir] + PROJ.gem.spec.files do
73
+ when_writing("Creating GEM") {
74
+ Gem::Builder.new(PROJ.gem.spec).build
75
+ verbose(true) {
76
+ mv gem_file, "#{pkg.package_dir}/#{gem_file}"
77
+ }
78
+ }
79
+ end
80
+
81
+ desc 'Install the gem'
82
+ task :install => [:clobber, :package] do
83
+ sh "#{SUDO} #{GEM} install pkg/#{PROJ.gem.spec.full_name}"
84
+ end
85
+
86
+ desc 'Uninstall the gem'
87
+ task :uninstall do
88
+ installed_list = Gem.source_index.find_name(PROJ.name)
89
+ if installed_list and installed_list.collect { |s| s.version.to_s}.include?(PROJ.version) then
90
+ sh "#{SUDO} #{GEM} uninstall -v '#{PROJ.version}' -i -x #{PROJ.name}"
91
+ end
92
+ end
93
+
94
+ desc 'Reinstall the gem'
95
+ task :reinstall => [:uninstall, :install]
96
+
97
+ end # namespace :gem
98
+
99
+ desc 'Alias to gem:package'
100
+ task :gem => 'gem:package'
101
+
102
+ task :clobber => 'gem:clobber_package'
103
+
104
+ remove_desc_for_task %w(gem:clobber_package)
105
+
106
+ # EOF