lib/loggability.rb in loggability-0.1.0 vs lib/loggability.rb in loggability-0.2.0
- old
+ new
@@ -3,27 +3,50 @@
# encoding: utf-8
require 'logger'
require 'date'
-
# A mixin that provides a top-level logging subsystem based on Logger.
module Loggability
# Package version constant
- VERSION = '0.1.0'
+ VERSION = '0.2.0'
# VCS revision
- REVISION = %q$Revision: ea1633c450be $
+ REVISION = %q$Revision: 4c9840dcb9fd $
# The key for the global logger (Loggability's own logger)
GLOBAL_KEY = :__global__
# The methods that are delegated across all loggers
AGGREGATE_METHODS = [ :level=, :output_to, :write_to, :format_with, :format_as, :formatter= ]
+ # Configuration defaults
+ CONFIG_DEFAULTS = {
+ :defaults => {
+ :severity => 'warn',
+ :formatter => 'default',
+ :output => 'STDERR',
+ },
+ }
+ # Regexp for parsing logspec lines in the config
+ LOGSPEC_PATTERN = %r{
+ ^
+ \s*
+ ((?i:debug|info|warn|error|fatal)) # severity
+ (?:
+ \s+
+ ((?:[\w\-/:\.]|\\[ ])+)
+ )?
+ (?: \s+\(
+ (\w+)
+ \) )?
+ \s*
+ $
+ }x
+
require 'loggability/constants'
include Loggability::Constants
require 'loggability/logger'
@@ -54,13 +77,30 @@
self.logger.debug "Registering %p log host: %p" % [ key, host ] if self.logger
self.log_hosts[ key ] = host
end
+ ### Return the log host key for +object+, using its #log_host_key method
+ ### if it has one, or returning it as a Symbol if it responds to #to_sym. Returns
+ ### +nil+ if no key could be derived.
+ def self::log_host_key_for( object )
+ return object.log_host_key if object.respond_to?( :log_host_key )
+ return object.to_sym if object.respond_to?( :to_sym )
+ return nil
+ end
+
+
+ ### Returns +true+ if there is a log host associated with the given +object+.
+ def self::log_host?( object )
+ key = self.log_host_key_for( object ) or return false
+ return self.log_hosts.key?( key )
+ end
+
+
### Return the Loggability::Logger for the loghost associated with +logclient+.
def self::[]( logclient )
- key = logclient.log_host_key if logclient.respond_to?( :log_host_key )
+ key = self.log_host_key_for( logclient )
key ||= GLOBAL_KEY
return self.log_hosts[ key ].logger
end
@@ -77,11 +117,14 @@
#
### Call the method with the given +methodname+ across the loggers of all loghosts with
### the given +arg+ and/or +block+.
def self::aggregate( methodname, arg, &block )
+ # self.log.debug "Aggregating a call to %p with %p to %d log hosts" %
+ # [ methodname, arg, Loggability.log_hosts.length ]
Loggability.log_hosts.values.each do |loghost|
+ # self.log.debug " %p.logger.%s( %p )" % [ loghost, methodname, arg ]
loghost.logger.send( methodname, arg, &block )
end
end
@@ -219,19 +262,82 @@
### Register as a <b>log client</b> that will log to to the given +loghost+, which can be
### either the +key+ the host registered with, or the log host object itself. Log messages
### can be written to the loghost via the LogClient API, which is automatically included.
def log_to( loghost )
- self.extend( Loggability::LogClient )
- self.log_host_key = if loghost.respond_to?( :log_host_key )
- loghost.log_host_key
+ extend( Loggability::LogClient )
+ include( Loggability::LogClient::InstanceMethods ) if self.is_a?( Class )
+
+ self.log_host_key = Loggability.log_host_key_for( loghost )
+ end
+
+
+ #
+ # :section: Configurability Support
+ #
+
+ # Load the Configurability library if it's installed
+ begin
+ require 'configurability'
+ rescue LoadError
+ end
+
+
+ # Configurability support -- load Loggability configuration from the 'logging' section
+ # of the config.
+ if defined?( Configurability )
+ extend Configurability
+ config_key :logging if respond_to?( :config_key )
+ end
+
+ ### Configurability API -- configure logging.
+ def self::configure( config=nil )
+ if config
+ self.log.debug "Configuring Loggability with custom config."
+
+ # Set up all loggers with defaults first
+ if defaultspec = config.delete( :__default__ ) || config.delete( '__default__' )
+ level, format, target = self.parse_config_spec( defaultspec )
+ Loggability.level = level if level
+ Loggability.format_as( format ) if format
+ Loggability.output_to( target ) if target
+ end
+
+ # Then let individual configs override.
+ config.each do |key, logspec|
+ unless Loggability.log_host?( key )
+ self.log.debug " no such log host %p; skipping" % [ key ]
+ next
+ end
+
+ self.log.debug " configuring logger for %p: %s" % [ key, logspec ]
+ level, format, target = self.parse_config_spec( logspec )
+ Loggability[ key ].level = level if level
+ Loggability[ key ].format_with( format ) if format
+ Loggability[ key ].output_to( target ) if target
+ end
+ else
+ self.log.debug "Configuring Loggability with defaults."
+ end
+ end
+
+
+ ### Parse the specified +spec+ into level,
+ def self::parse_config_spec( spec )
+ match = LOGSPEC_PATTERN.match( spec ) or
+ raise ArgumentError, "Couldn't parse logspec: %p" % [ spec ]
+ self.log.error " parsed config spec %p -> %p" % [ spec, match ]
+ severity, target, format = match.captures
+
+ target = case target
+ when 'STDOUT' then $stdout
+ when 'STDERR' then $stderr
else
- loghost.to_sym
+ target
end
- # For objects that also can be instantiated
- include( Loggability::LogClient::InstanceMethods ) if self.is_a?( Class )
+ return severity, format, target
end
-end # module Strelka
+end # module Loggability