loggability 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|