1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
require 'singleton'
module Logging
# The Repository is a hash that stores references to all Loggers
# that have been created. It provides methods to determine parent/child
# relationships between Loggers and to retrieve Loggers from the hash.
#
class Repository
include Singleton
PATH_DELIMITER = '::' # :nodoc:
# nodoc:
#
# This is a singleton class -- use the +instance+ method to obtain the
# +Repository+ instance.
#
def initialize
@h = {:root => ::Logging::RootLogger.new}
# configures the internal logger which is disabled by default
logger = ::Logging::Logger.allocate
logger._setup(
to_key(::Logging),
:parent => @h[:root],
:additive => false,
:level => ::Logging::LEVELS.length # turns this logger off
)
@h[logger.name] = logger
end
# call-seq:
# instance[name]
#
# Returns the +Logger+ named _name_.
#
# When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
# retrieve the logger. When _name_ is a +Class+ the class name will be
# used to retrieve the logger. When _name_ is an object the name of the
# object's class will be used to retrieve the logger.
#
# Example:
#
# repo = Repository.instance
# obj = MyClass.new
#
# log1 = repo[obj]
# log2 = repo[MyClass]
# log3 = repo['MyClass']
#
# log1.object_id == log2.object_id # => true
# log2.object_id == log3.object_id # => true
#
def []( key ) @h[to_key(key)] end
# call-seq:
# instance[name] = logger
#
# Stores the _logger_ under the given _name_.
#
# When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
# store the logger. When _name_ is a +Class+ the class name will be
# used to store the logger. When _name_ is an object the name of the
# object's class will be used to store the logger.
#
def []=( key, val ) @h[to_key(key)] = val end
# call-seq:
# fetch( name )
#
# Returns the +Logger+ named _name_. An +KeyError+ will be raised if
# the logger does not exist.
#
# When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
# retrieve the logger. When _name_ is a +Class+ the class name will be
# used to retrieve the logger. When _name_ is an object the name of the
# object's class will be used to retrieve the logger.
#
def fetch( key ) @h.fetch(to_key(key)) end
# call-seq:
# has_logger?( name )
#
# Returns +true+ if the given logger exists in the repository. Returns
# +false+ if this is not the case.
#
# When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
# retrieve the logger. When _name_ is a +Class+ the class name will be
# used to retrieve the logger. When _name_ is an object the name of the
# object's class will be used to retrieve the logger.
#
def has_logger?( key ) @h.has_key?(to_key(key)) end
# call-seq:
# delete( name )
#
# Deletes the named logger from the repository. All direct children of the
# logger will have their parent reassigned. So the parent of the logger
# being deleted becomes the new parent of the children.
#
# When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
# remove the logger. When _name_ is a +Class+ the class name will be
# used to remove the logger. When _name_ is an object the name of the
# object's class will be used to remove the logger.
#
# Raises a RuntimeError if you try to delete the root logger.
# Raises an KeyError if the named logger is not found.
def delete( key )
key = to_key(key)
raise 'the :root logger cannot be deleted' if :root == key
parent = @h.fetch(key).parent
children(key).each {|c| c.__send__(:parent=, parent)}
@h.delete(key)
end
# call-seq:
# parent( key )
#
# Returns the parent logger for the logger identified by _key_ where
# _key_ follows the same identification rules described in
# <tt>Repository#[]</tt>. A parent is returned regardless of the
# existence of the logger referenced by _key_.
#
# A note about parents -
#
# If you have a class A::B::C, then the parent of C is B, and the parent
# of B is A. Parents are determined by namespace.
#
def parent( key )
name = parent_name(to_key(key))
return if name.nil?
@h[name]
end
# call-seq:
# children( key )
#
# Returns an array of the children loggers for the logger identified by
# _key_ where _key_ follows the same identification rules described in
# +Repository#[]+. Children are returned regardless of the
# existence of the logger referenced by _key_.
#
def children( parent )
ary = []
parent = to_key(parent)
@h.each_pair do |child,logger|
next if :root == child
ary << logger if parent == parent_name(child)
end
return ary.sort
end
# call-seq:
# to_key( key )
#
# Takes the given _key_ and converts it into a form that can be used to
# retrieve a logger from the +Repository+ hash.
#
# When _key_ is a +String+ or a +Symbol+ it will be returned "as is".
# When _key_ is a +Class+ the class name will be returned. When _key_ is
# an object the name of the object's class will be returned.
#
def to_key( key )
case key
when :root, 'root'; :root
when String; key
when Symbol; key.to_s
when Module; key.logger_name
when Object; key.class.logger_name
end
end
# Returns the name of the parent for the logger identified by the given
# _key_. If the _key_ is for the root logger, then +nil+ is returned.
#
def parent_name( key )
return if :root == key
a = key.split PATH_DELIMITER
p = :root
while a.slice!(-1) and !a.empty?
k = a.join PATH_DELIMITER
if @h.has_key? k then p = k; break end
end
p
end
# :stopdoc:
def self.reset
if defined?(@singleton__instance__)
@singleton__mutex__.synchronize {
@singleton__instance__ = nil
}
else
@__instance__ = nil
class << self
nonce = class << Singleton; self; end
if defined?(nonce::FirstInstanceCall)
define_method(:instance, nonce::FirstInstanceCall)
else
remove_method(:instance)
Singleton.__init__(::Logging::Repository)
end
end
end
return nil
end
# :startdoc:
end # class Repository
end # module Logging
|