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.
- data/History.txt +176 -0
- data/Manifest.txt +54 -0
- data/README.txt +93 -0
- data/Rakefile +28 -0
- data/data/logging.yaml +63 -0
- data/lib/logging.rb +288 -0
- data/lib/logging/appender.rb +257 -0
- data/lib/logging/appenders/console.rb +43 -0
- data/lib/logging/appenders/email.rb +131 -0
- data/lib/logging/appenders/file.rb +55 -0
- data/lib/logging/appenders/growl.rb +182 -0
- data/lib/logging/appenders/io.rb +81 -0
- data/lib/logging/appenders/rolling_file.rb +293 -0
- data/lib/logging/appenders/syslog.rb +202 -0
- data/lib/logging/config/yaml_configurator.rb +197 -0
- data/lib/logging/layout.rb +103 -0
- data/lib/logging/layouts/basic.rb +35 -0
- data/lib/logging/layouts/pattern.rb +292 -0
- data/lib/logging/log_event.rb +50 -0
- data/lib/logging/logger.rb +388 -0
- data/lib/logging/repository.rb +151 -0
- data/lib/logging/root_logger.rb +60 -0
- data/lib/logging/utils.rb +44 -0
- data/tasks/ann.rake +78 -0
- data/tasks/bones.rake +21 -0
- data/tasks/gem.rake +106 -0
- data/tasks/manifest.rake +49 -0
- data/tasks/notes.rake +22 -0
- data/tasks/post_load.rake +37 -0
- data/tasks/rdoc.rake +49 -0
- data/tasks/rubyforge.rake +57 -0
- data/tasks/setup.rb +253 -0
- data/tasks/svn.rake +45 -0
- data/tasks/test.rake +38 -0
- data/test/appenders/test_console.rb +40 -0
- data/test/appenders/test_email.rb +167 -0
- data/test/appenders/test_file.rb +94 -0
- data/test/appenders/test_growl.rb +115 -0
- data/test/appenders/test_io.rb +113 -0
- data/test/appenders/test_rolling_file.rb +187 -0
- data/test/appenders/test_syslog.rb +192 -0
- data/test/benchmark.rb +88 -0
- data/test/config/test_yaml_configurator.rb +41 -0
- data/test/layouts/test_basic.rb +44 -0
- data/test/layouts/test_pattern.rb +173 -0
- data/test/setup.rb +66 -0
- data/test/test_appender.rb +162 -0
- data/test/test_layout.rb +85 -0
- data/test/test_log_event.rb +81 -0
- data/test/test_logger.rb +589 -0
- data/test/test_logging.rb +250 -0
- data/test/test_repository.rb +123 -0
- data/test/test_root_logger.rb +82 -0
- data/test/test_utils.rb +48 -0
- 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
|