loggability 0.0.1
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.tar.gz.sig +4 -0
- data/.gemtest +0 -0
- data/ChangeLog +9353 -0
- data/History.rdoc +4 -0
- data/Manifest.txt +19 -0
- data/README.rdoc +200 -0
- data/Rakefile +49 -0
- data/bin/loggability +3 -0
- data/lib/loggability.rb +223 -0
- data/lib/loggability/constants.rb +26 -0
- data/lib/loggability/formatter.rb +89 -0
- data/lib/loggability/formatter/color.rb +52 -0
- data/lib/loggability/formatter/default.rb +21 -0
- data/lib/loggability/formatter/html.rb +76 -0
- data/lib/loggability/logger.rb +244 -0
- data/spec/lib/helpers.rb +42 -0
- data/spec/loggability/formatter/color_spec.rb +38 -0
- data/spec/loggability/formatter/html_spec.rb +45 -0
- data/spec/loggability/formatter_spec.rb +50 -0
- data/spec/loggability/logger_spec.rb +149 -0
- data/spec/loggability_spec.rb +84 -0
- metadata +220 -0
- metadata.gz.sig +0 -0
data/History.rdoc
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
ChangeLog
|
2
|
+
History.rdoc
|
3
|
+
Manifest.txt
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
bin/loggability
|
7
|
+
lib/loggability.rb
|
8
|
+
lib/loggability/constants.rb
|
9
|
+
lib/loggability/formatter.rb
|
10
|
+
lib/loggability/formatter/color.rb
|
11
|
+
lib/loggability/formatter/default.rb
|
12
|
+
lib/loggability/formatter/html.rb
|
13
|
+
lib/loggability/logger.rb
|
14
|
+
spec/lib/helpers.rb
|
15
|
+
spec/loggability/formatter/color_spec.rb
|
16
|
+
spec/loggability/formatter/html_spec.rb
|
17
|
+
spec/loggability/formatter_spec.rb
|
18
|
+
spec/loggability/logger_spec.rb
|
19
|
+
spec/loggability_spec.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
= loggability
|
2
|
+
|
3
|
+
home :: http://deveiate.org/projects/loggability
|
4
|
+
code :: http://bitbucket.org/ged/loggability
|
5
|
+
docs :: http://deveiate.org/code/loggability
|
6
|
+
github :: http://github.com/ged/loggability
|
7
|
+
|
8
|
+
|
9
|
+
== Description
|
10
|
+
|
11
|
+
A composable logging system built on the standard Logger library.
|
12
|
+
|
13
|
+
You can add Loggability to large libraries and systems, then hook everything
|
14
|
+
up later when you know where you want logs to be written, at what level of
|
15
|
+
severity, and in which format.
|
16
|
+
|
17
|
+
An example:
|
18
|
+
|
19
|
+
# Load a bunch of libraries
|
20
|
+
require 'strelka'
|
21
|
+
require 'inversion'
|
22
|
+
require 'treequel'
|
23
|
+
require 'loggability'
|
24
|
+
|
25
|
+
# Now tell everything that's using Loggability to log to an HTML
|
26
|
+
# log file at INFO level
|
27
|
+
Loggability.write_to( '/usr/local/www/htdocs/log.html' )
|
28
|
+
Loggability.format_as( :html )
|
29
|
+
Loggability.level = :info
|
30
|
+
|
31
|
+
|
32
|
+
== Prerequisites
|
33
|
+
|
34
|
+
* Ruby 1.9.3 or better, Rubinius 2.0 or better
|
35
|
+
|
36
|
+
It will probably work under any other interpreter in which Logger works, but
|
37
|
+
it's only tested in the above.
|
38
|
+
|
39
|
+
|
40
|
+
== Installation
|
41
|
+
|
42
|
+
$ gem install loggability
|
43
|
+
|
44
|
+
|
45
|
+
== Usage
|
46
|
+
|
47
|
+
Loggability is split up into two parts: {log hosts}[rdoc-ref:Loggability::LogHost]
|
48
|
+
and {log clients}[rdoc-ref:Loggability::LogClient]. A <b>log
|
49
|
+
host</b> is an object that contains a Logger instance that will be used to
|
50
|
+
log stuff. A <b>log client</b> is an object that will write logging messages to a
|
51
|
+
particular <b>log host</b>'s Logger.
|
52
|
+
|
53
|
+
Both parts require that you extend the object with Loggability.
|
54
|
+
|
55
|
+
=== Setting Up A 'Log Host'
|
56
|
+
|
57
|
+
To install a Logger into an object, you use the +log_as+ declaration with a
|
58
|
+
Symbol that will be used as the key for the object's Logger:
|
59
|
+
|
60
|
+
module MyProject
|
61
|
+
extend Loggability
|
62
|
+
log_as :my_project
|
63
|
+
end
|
64
|
+
|
65
|
+
After declaring itself as a log host, it will have an associated Loggability::Logger
|
66
|
+
object that's a wrapper around a Logger instance:
|
67
|
+
|
68
|
+
MyProject.logger
|
69
|
+
# => #<Loggability::Logger:0x4e0c :my_project ...>
|
70
|
+
|
71
|
+
Since it's still a Logger object, you can call all the regular Logger methods:
|
72
|
+
|
73
|
+
MyProject.logger.level = Logger::WARN
|
74
|
+
|
75
|
+
MyProject.logger.debug("Created logger")
|
76
|
+
MyProject.logger.info("Program started")
|
77
|
+
MyProject.logger.warn("Nothing to do!")
|
78
|
+
|
79
|
+
begin
|
80
|
+
File.each_line(path) do |line|
|
81
|
+
unless line =~ /^(\w+) = (.*)$/
|
82
|
+
MyProject.logger.error("Line in wrong format: #{line}")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
rescue => err
|
86
|
+
MyProject.logger.fatal("Caught exception; exiting")
|
87
|
+
MyProject.logger.fatal(err)
|
88
|
+
end
|
89
|
+
|
90
|
+
or use a few new convenience methods for changing the logging level:
|
91
|
+
|
92
|
+
MyProject.logger.level = :debug
|
93
|
+
|
94
|
+
...installing a different formatter:
|
95
|
+
|
96
|
+
MyProject.logger.format_as( :html )
|
97
|
+
|
98
|
+
...changing the output destination:
|
99
|
+
|
100
|
+
log_messages = []
|
101
|
+
MyProject.logger.output_to( log_messages )
|
102
|
+
|
103
|
+
...{and more}[rdoc-ref:Loggability::Logger].
|
104
|
+
|
105
|
+
|
106
|
+
=== Setting Up A 'Log Client'
|
107
|
+
|
108
|
+
To add an object that will log to your log host, after you <tt>extend Loggability</tt>,
|
109
|
+
use the +log_to+ declaration to hook up the object (and instances of the object if
|
110
|
+
you use +log_to+ in a Class) to the log host you specify:
|
111
|
+
|
112
|
+
class MyProject::Server
|
113
|
+
extend Loggability
|
114
|
+
log_to :my_project
|
115
|
+
|
116
|
+
def initialize( config={} )
|
117
|
+
self.log.debug "Creating a server with config: %p" % [ config ]
|
118
|
+
#...
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
You can fetch any object's Logger through the Loggability object:
|
123
|
+
|
124
|
+
Loggability[ MyProject ]
|
125
|
+
# => #<Loggability::Logger:0x007f88ca3bf510 ...>
|
126
|
+
|
127
|
+
Loggability[ MyProject::Server ]
|
128
|
+
# => #<Loggability::Logger:0x007f88ca3bf510 ...>
|
129
|
+
|
130
|
+
Calling the object's <tt>#log</tt> method will return a Proxy for its host's Logger object that will include the object's name in the log messages 'progname'.
|
131
|
+
|
132
|
+
You can also use the <b>log host</b> itself as the argument to +log_to+:
|
133
|
+
|
134
|
+
class MyProject::Client
|
135
|
+
extend Loggability
|
136
|
+
log_to MyProject
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
=== Aggregate Logging
|
141
|
+
|
142
|
+
If you have several <b>log hosts</b>, and you want to affect them all simultaneously,
|
143
|
+
you can do that using the aggregate functions of Loggability. They're the same as the
|
144
|
+
methods on Loggability::Logger:
|
145
|
+
|
146
|
+
# Set all logs to log at INFO level
|
147
|
+
Loggability.level = :info
|
148
|
+
|
149
|
+
# Write HTML logs
|
150
|
+
Loggability.format_with( :html )
|
151
|
+
|
152
|
+
# Log everything to the same logfile
|
153
|
+
Loggability.output_to( "/tmp/my_project_log.html" )
|
154
|
+
|
155
|
+
|
156
|
+
== Contributing
|
157
|
+
|
158
|
+
You can check out the current development source with
|
159
|
+
Mercurial[http://bitbucket.org/ged/loggability], or if you prefer Git, via
|
160
|
+
{its Github mirror}[https://github.com/ged/loggability].
|
161
|
+
|
162
|
+
After checking out the source, run:
|
163
|
+
|
164
|
+
$ rake newb
|
165
|
+
|
166
|
+
This task will install any missing dependencies, run the tests/specs,
|
167
|
+
and generate the API documentation.
|
168
|
+
|
169
|
+
|
170
|
+
== License
|
171
|
+
|
172
|
+
Copyright (c) 2012, Michael Granger
|
173
|
+
All rights reserved.
|
174
|
+
|
175
|
+
Redistribution and use in source and binary forms, with or without
|
176
|
+
modification, are permitted provided that the following conditions are met:
|
177
|
+
|
178
|
+
* Redistributions of source code must retain the above copyright notice,
|
179
|
+
this list of conditions and the following disclaimer.
|
180
|
+
|
181
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
182
|
+
this list of conditions and the following disclaimer in the documentation
|
183
|
+
and/or other materials provided with the distribution.
|
184
|
+
|
185
|
+
* Neither the name of the author/s, nor the names of the project's
|
186
|
+
contributors may be used to endorse or promote products derived from this
|
187
|
+
software without specific prior written permission.
|
188
|
+
|
189
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
190
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
191
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
192
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
193
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
194
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
195
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
196
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
197
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
198
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
199
|
+
|
200
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require 'rake/clean'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'hoe'
|
7
|
+
rescue LoadError
|
8
|
+
abort "This Rakefile requires 'hoe' (gem install hoe)"
|
9
|
+
end
|
10
|
+
|
11
|
+
Hoe.plugin :mercurial
|
12
|
+
Hoe.plugin :signing
|
13
|
+
Hoe.plugin :deveiate
|
14
|
+
|
15
|
+
Hoe.plugins.delete :rubyforge
|
16
|
+
|
17
|
+
hoespec = Hoe.spec 'loggability' do
|
18
|
+
self.readme_file = 'README.rdoc'
|
19
|
+
self.history_file = 'History.rdoc'
|
20
|
+
self.extra_rdoc_files = FileList[ '*.rdoc' ]
|
21
|
+
|
22
|
+
self.developer 'Michael Granger', 'ged@FaerieMUD.org'
|
23
|
+
|
24
|
+
self.dependency 'pluginfactory', '~> 1.0'
|
25
|
+
|
26
|
+
self.dependency 'hoe-deveiate', '~> 0.1', :developer
|
27
|
+
self.dependency 'simplecov', '~> 0.6', :developer
|
28
|
+
|
29
|
+
self.spec_extras[:licenses] = ["Ruby"]
|
30
|
+
self.spec_extras[:rdoc_options] = ['-f', 'fivefish', '-t', 'Loggability Toolkit']
|
31
|
+
self.require_ruby_version( '>=1.9.3' )
|
32
|
+
self.hg_sign_tags = true if self.respond_to?( :hg_sign_tags= )
|
33
|
+
self.check_history_on_release = true if self.respond_to?( :check_history_on_release= )
|
34
|
+
|
35
|
+
self.rdoc_locations << "deveiate:/usr/local/www/public/code/#{remote_rdoc_dir}"
|
36
|
+
end
|
37
|
+
|
38
|
+
ENV['VERSION'] ||= hoespec.spec.version.to_s
|
39
|
+
|
40
|
+
# Ensure the specs pass before checking in
|
41
|
+
task 'hg:precheckin' => [ :check_history, :check_manifest, :spec ]
|
42
|
+
|
43
|
+
|
44
|
+
desc "Build a coverage report"
|
45
|
+
task :coverage do
|
46
|
+
ENV["COVERAGE"] = 'yes'
|
47
|
+
Rake::Task[:spec].invoke
|
48
|
+
end
|
49
|
+
|
data/bin/loggability
ADDED
data/lib/loggability.rb
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
4
|
+
|
5
|
+
require 'logger'
|
6
|
+
require 'date'
|
7
|
+
|
8
|
+
|
9
|
+
# A mixin that provides a top-level logging subsystem based on Logger.
|
10
|
+
module Loggability
|
11
|
+
|
12
|
+
# Package version constant
|
13
|
+
VERSION = '0.0.1'
|
14
|
+
|
15
|
+
# VCS revision
|
16
|
+
REVISION = %q$Revision: 7b3fcf97718a $
|
17
|
+
|
18
|
+
# The key for the global logger (Loggability's own logger)
|
19
|
+
GLOBAL_KEY = :__global__
|
20
|
+
|
21
|
+
# The methods that are delegated across all loggers
|
22
|
+
AGGREGATE_METHODS = [ :level=, :output_to, :write_to, :format_with, :format_as, :formatter= ]
|
23
|
+
|
24
|
+
|
25
|
+
require 'loggability/constants'
|
26
|
+
include Loggability::Constants
|
27
|
+
|
28
|
+
require 'loggability/logger'
|
29
|
+
|
30
|
+
|
31
|
+
##
|
32
|
+
# The Hash of modules that have a Logger, keyed by the name they register with
|
33
|
+
class << self; attr_reader :log_hosts; end
|
34
|
+
@log_hosts = {}
|
35
|
+
|
36
|
+
|
37
|
+
### Return the library's version string
|
38
|
+
def self::version_string( include_buildnum=false )
|
39
|
+
vstring = "%s %s" % [ self.name, VERSION ]
|
40
|
+
vstring << " (build %s)" % [ REVISION[/: ([[:xdigit:]]+)/, 1] || '0' ] if include_buildnum
|
41
|
+
return vstring
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
### Register the specified +host+ as a log host. It should already have been extended
|
46
|
+
### with LogHostMethods.
|
47
|
+
def self::register_loghost( host )
|
48
|
+
key = host.log_host_key
|
49
|
+
if self.log_hosts.key?( key )
|
50
|
+
self.logger.warn "Replacing existing log host for %p (%p) with %p" %
|
51
|
+
[ key, self.log_hosts[key], host ]
|
52
|
+
end
|
53
|
+
|
54
|
+
self.logger.debug "Registering %p log host: %p" % [ key, host ] if self.logger
|
55
|
+
self.log_hosts[ key ] = host
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
### Return the Loggability::Logger for the loghost associated with +logclient+.
|
60
|
+
def self::[]( logclient )
|
61
|
+
key = logclient.log_host_key if logclient.respond_to?( :log_host_key )
|
62
|
+
key ||= GLOBAL_KEY
|
63
|
+
|
64
|
+
return self.log_hosts[ key ].logger
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
### Clear out all log hosts except for ones which start with '_'. This is intended
|
69
|
+
### to be used for testing.
|
70
|
+
def self::clear_loghosts
|
71
|
+
self.log_hosts.delete_if {|key,_| !key.to_s.start_with?('_') }
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
#
|
76
|
+
# :section: Aggregate Methods
|
77
|
+
#
|
78
|
+
|
79
|
+
### Call the method with the given +methodname+ across the loggers of all loghosts with
|
80
|
+
### the given +arg+ and/or +block+.
|
81
|
+
def self::aggregate( methodname, arg, &block )
|
82
|
+
Loggability.log_hosts.values.each do |loghost|
|
83
|
+
loghost.logger.send( methodname, arg, &block )
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
##
|
89
|
+
# :method: level=
|
90
|
+
# :call-seq:
|
91
|
+
# level = newlevel
|
92
|
+
#
|
93
|
+
# Aggregate method: set the log level on all loggers to +newlevel+. See
|
94
|
+
# Loggability::Logger#level= for more info.
|
95
|
+
|
96
|
+
##
|
97
|
+
# :method: output_to
|
98
|
+
# :call-seq:
|
99
|
+
# output_to( destination )
|
100
|
+
# write_to( destination )
|
101
|
+
#
|
102
|
+
# Aggregate method: set all loggers to log to +destination+. See Loggability::Logger#output_to
|
103
|
+
# for more info.
|
104
|
+
|
105
|
+
##
|
106
|
+
# :method: format_with
|
107
|
+
# :call-seq:
|
108
|
+
# format_with( formatter )
|
109
|
+
# format_as( formatter )
|
110
|
+
# formatter = formatter
|
111
|
+
#
|
112
|
+
# Aggregate method: set all loggers to log with the given +formatter+. See
|
113
|
+
# Loggability::Logger#format_with for more info.
|
114
|
+
AGGREGATE_METHODS.each do |meth|
|
115
|
+
block = self.method( :aggregate ).to_proc.curry[ meth ]
|
116
|
+
Loggability.singleton_class.send( :define_method, meth, &block )
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
# Extension for 'log hosts'. A <b>log host</b> is an object that hosts a Loggability::Logger
|
121
|
+
# object, and is typically the top of some kind of hierarchy, like a namespace
|
122
|
+
# module for a project:
|
123
|
+
#
|
124
|
+
# module MyProject
|
125
|
+
#
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# This module isn't mean to be used directly -- it's installed via the Loggability#log_as
|
129
|
+
# declaration, which also does some other initialization that you'll likely want.
|
130
|
+
#
|
131
|
+
#
|
132
|
+
module LogHost
|
133
|
+
|
134
|
+
# The logger that will be used when the logging subsystem is reset
|
135
|
+
attr_accessor :default_logger
|
136
|
+
|
137
|
+
# The logger that's currently in effect
|
138
|
+
attr_accessor :logger
|
139
|
+
alias_method :log, :logger
|
140
|
+
alias_method :log=, :logger=
|
141
|
+
|
142
|
+
# The key associated with the logger for this host
|
143
|
+
attr_accessor :log_host_key
|
144
|
+
|
145
|
+
end # module LogHost
|
146
|
+
|
147
|
+
|
148
|
+
#
|
149
|
+
# :section: LogHost API
|
150
|
+
#
|
151
|
+
|
152
|
+
### Register as a log host associated with the given +key+, add the methods from
|
153
|
+
### LogHost, and install a Loggability::Logger.
|
154
|
+
def log_as( key )
|
155
|
+
self.extend( Loggability::LogHost )
|
156
|
+
self.log_host_key = key.to_sym
|
157
|
+
self.logger = self.default_logger = Loggability::Logger.new
|
158
|
+
Loggability.register_loghost( self )
|
159
|
+
end
|
160
|
+
|
161
|
+
# Install a global logger in Loggability itself
|
162
|
+
extend( Loggability::LogHost )
|
163
|
+
self.log_host_key = GLOBAL_KEY
|
164
|
+
self.logger = self.default_logger = Loggability::Logger.new
|
165
|
+
Loggability.register_loghost( self )
|
166
|
+
|
167
|
+
|
168
|
+
|
169
|
+
# Methods to install for objects which call +log_to+.
|
170
|
+
module LogClient
|
171
|
+
|
172
|
+
##
|
173
|
+
# The key of the log host this client targets
|
174
|
+
attr_accessor :log_host_key
|
175
|
+
|
176
|
+
### Return the Loggability::Logger object associated with the log host the
|
177
|
+
### client is logging to.
|
178
|
+
### :TODO: Use delegation for efficiency.
|
179
|
+
def log
|
180
|
+
@__log ||= Loggability[ self ].proxy_for( self )
|
181
|
+
end
|
182
|
+
|
183
|
+
# Stuff that gets added to instances of Classes that are log hosts.
|
184
|
+
module InstanceMethods
|
185
|
+
|
186
|
+
### Fetch the key of the log host the instance of this client targets
|
187
|
+
def log_host_key
|
188
|
+
return self.class.log_host_key
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
### Delegate to the class's logger.
|
193
|
+
def log
|
194
|
+
@__log ||= Loggability[ self.class ].proxy_for( self )
|
195
|
+
end
|
196
|
+
|
197
|
+
end # module InstanceMethods
|
198
|
+
|
199
|
+
end # module LogClient
|
200
|
+
|
201
|
+
|
202
|
+
#
|
203
|
+
# :section: LogClient API
|
204
|
+
#
|
205
|
+
|
206
|
+
### Register as a <b>log client</b> that will log to to the given +loghost+, which can be
|
207
|
+
### either the +key+ the host registered with, or the log host object itself. Log messages
|
208
|
+
### can be written to the loghost via the LogClient API, which is automatically included.
|
209
|
+
def log_to( loghost )
|
210
|
+
self.extend( Loggability::LogClient )
|
211
|
+
self.log_host_key = if loghost.respond_to?( :log_host_key )
|
212
|
+
loghost.log_host_key
|
213
|
+
else
|
214
|
+
loghost.to_sym
|
215
|
+
end
|
216
|
+
|
217
|
+
# For objects that also can be instantiated
|
218
|
+
include( Loggability::LogClient::InstanceMethods ) if self.is_a?( Class )
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
end # module Strelka
|
223
|
+
|