object_logging 0.1.0
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/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +73 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/lib/object_logging.rb +53 -0
- data/lib/object_logging/log/base.rb +23 -0
- data/lib/object_logging/log/rails_cache.rb +41 -0
- data/lib/object_logging/log/rails_log.rb +14 -0
- data/lib/object_logging/log/stdout.rb +14 -0
- data/lib/object_logging/logger.rb +69 -0
- data/lib/object_logging/metaclass.rb +7 -0
- data/test/object_logging_test.rb +57 -0
- data/test/test_helper.rb +42 -0
- metadata +78 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Christopher J. Bottaro
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
= object_logging
|
2
|
+
|
3
|
+
Super simple logging for objects.
|
4
|
+
|
5
|
+
== Why?
|
6
|
+
|
7
|
+
It's a pain to trudge through large log files. Sometimes you just want to see log messages for one particular object.
|
8
|
+
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
class Something
|
12
|
+
include ObjectLogging
|
13
|
+
def foo
|
14
|
+
logger.debug "entering"
|
15
|
+
logger.info "leaving"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
something = Something.new
|
20
|
+
something.foo
|
21
|
+
puts something.logger.log # => [DEBUG] Something#foo entering
|
22
|
+
# [INFO] Something#foo leaving
|
23
|
+
|
24
|
+
This logs to memory. Your log will be gone when the object goes out of scope.
|
25
|
+
|
26
|
+
=== Logging to the Rails cache
|
27
|
+
|
28
|
+
class Something
|
29
|
+
include ObjectLogging
|
30
|
+
object_logging :rails_cache, :id => :proc_or_method_name_to_identify_object
|
31
|
+
end
|
32
|
+
|
33
|
+
This is useful for when you want to view the log after the object goes out of scope.
|
34
|
+
|
35
|
+
The option <tt>:id</tt> needs to a Proc or method name that returns a string that uniquely identifies the object (i.e. will be used as the cache key).
|
36
|
+
|
37
|
+
=== Logging to the Rails log or STDOUT
|
38
|
+
|
39
|
+
class Something
|
40
|
+
include ObjectLogging
|
41
|
+
object_logging :rails_log
|
42
|
+
end
|
43
|
+
|
44
|
+
class Something
|
45
|
+
include ObjectLogging
|
46
|
+
object_logging :stdout
|
47
|
+
end
|
48
|
+
|
49
|
+
This logs to memory, but also logs to <tt>Rails.logger</tt> or <tt>STDOUT</tt>.
|
50
|
+
|
51
|
+
== Sharing loggers
|
52
|
+
|
53
|
+
You can pass Logger instances between your objects. This is useful for when you want an object to temporarily log to another object's log.
|
54
|
+
|
55
|
+
a = Account.new
|
56
|
+
u = User.new
|
57
|
+
|
58
|
+
a.logger.entries.length # => 0
|
59
|
+
u.logger.entries.length # => 0
|
60
|
+
|
61
|
+
a.logger.debug "blah"
|
62
|
+
u.logger.debug "bleh"
|
63
|
+
|
64
|
+
u.logger = a.logger
|
65
|
+
u.logger.debug "weee"
|
66
|
+
|
67
|
+
a.logger.entries.length # => 2
|
68
|
+
u.logger.entries.length # => 1
|
69
|
+
|
70
|
+
|
71
|
+
== Copyright
|
72
|
+
|
73
|
+
Copyright (c) 2010 Christopher J. Bottaro. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "object_logging"
|
8
|
+
gem.summary = %Q{Super simple logging for objects.}
|
9
|
+
gem.description = %Q{It's a pain to trudge through large log files. Sometimes you just want to see log messages for one particular object.}
|
10
|
+
gem.email = "cjbottaro@alumni.cs.utexas.edu"
|
11
|
+
gem.homepage = "http://github.com/cjbottaro/object_logging"
|
12
|
+
gem.authors = ["Christopher J. Bottaro"]
|
13
|
+
# gem.add_development_dependency "thoughtbot-shoulda"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake/testtask'
|
21
|
+
Rake::TestTask.new(:test) do |test|
|
22
|
+
test.libs << 'lib' << 'test'
|
23
|
+
test.pattern = 'test/**/*_test.rb'
|
24
|
+
test.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
begin
|
28
|
+
require 'rcov/rcovtask'
|
29
|
+
Rcov::RcovTask.new do |test|
|
30
|
+
test.libs << 'test'
|
31
|
+
test.pattern = 'test/**/*_test.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
rescue LoadError
|
35
|
+
task :rcov do
|
36
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
task :test => :check_dependencies
|
41
|
+
|
42
|
+
task :default => :test
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
if File.exist?('VERSION')
|
47
|
+
version = File.read('VERSION')
|
48
|
+
else
|
49
|
+
version = ""
|
50
|
+
end
|
51
|
+
|
52
|
+
rdoc.rdoc_dir = 'rdoc'
|
53
|
+
rdoc.title = "object_logging #{version}"
|
54
|
+
rdoc.rdoc_files.include('README*')
|
55
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
56
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "object_logging/metaclass"
|
2
|
+
require "object_logging/logger"
|
3
|
+
|
4
|
+
module ObjectLogging
|
5
|
+
|
6
|
+
def self.included(mod)
|
7
|
+
mod.send(:extend, ClassMethods)
|
8
|
+
mod.send(:include, InstanceMethods)
|
9
|
+
mod.metaclass.class_eval do
|
10
|
+
alias_method :inherited_without_object_logging, :inherited
|
11
|
+
alias_method :inherited, :inherited_with_object_logging
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
|
17
|
+
def inherited_with_object_logging(mod)
|
18
|
+
inherited_without_object_logging(mod)
|
19
|
+
object_logging_copy = @object_logging && @object_logging.collect do |e|
|
20
|
+
begin
|
21
|
+
e.dup
|
22
|
+
rescue TypeError
|
23
|
+
e
|
24
|
+
end
|
25
|
+
end
|
26
|
+
mod.instance_variable_set("@object_logging", object_logging_copy)
|
27
|
+
end
|
28
|
+
|
29
|
+
def object_logging(*args)
|
30
|
+
if args.empty?
|
31
|
+
@object_logging
|
32
|
+
else
|
33
|
+
options = args.last.kind_of?(Hash) ? args.pop : {}
|
34
|
+
@object_logging = [args.first, options]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
module InstanceMethods
|
41
|
+
|
42
|
+
def logger
|
43
|
+
@logger ||= Logger.new(self)
|
44
|
+
@logger.objectify(self)
|
45
|
+
end
|
46
|
+
|
47
|
+
def logger=(logger)
|
48
|
+
@logger = logger
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ObjectLogging
|
2
|
+
module Log
|
3
|
+
class Base
|
4
|
+
|
5
|
+
def initialize(object, options)
|
6
|
+
@storage = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def log(level, context, message)
|
10
|
+
@storage << [level, context, message]
|
11
|
+
end
|
12
|
+
|
13
|
+
def entries
|
14
|
+
@storage
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear
|
18
|
+
@storage = []
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "object_logging/log/base"
|
2
|
+
|
3
|
+
module ObjectLogging
|
4
|
+
module Log
|
5
|
+
class RailsCache < Base
|
6
|
+
|
7
|
+
def initialize(object, options)
|
8
|
+
@key = make_key(object, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def log(level, context, message)
|
12
|
+
Rails.cache.write(key, entries << [level, context, message])
|
13
|
+
end
|
14
|
+
|
15
|
+
def entries
|
16
|
+
Rails.cache.read(key) || []
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear
|
20
|
+
Rails.cache.delete(key)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def key
|
26
|
+
@key
|
27
|
+
end
|
28
|
+
|
29
|
+
def make_key(object, options)
|
30
|
+
id = options[:id]
|
31
|
+
if id.kind_of(Proc)
|
32
|
+
key = id.call(object)
|
33
|
+
else
|
34
|
+
key = object.send(id)
|
35
|
+
end
|
36
|
+
"object_logging/#{key}"
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module ObjectLogging
|
2
|
+
class Logger
|
3
|
+
|
4
|
+
def initialize(object)
|
5
|
+
@log = instantiate_log(object)
|
6
|
+
end
|
7
|
+
|
8
|
+
def objectify(object)
|
9
|
+
(@object = object) and self
|
10
|
+
end
|
11
|
+
|
12
|
+
%w[debug info warn error fatal].each do |level|
|
13
|
+
class_eval <<-str
|
14
|
+
def #{level}(message, options = {})
|
15
|
+
make_entry("#{level}", message, options)
|
16
|
+
end
|
17
|
+
str
|
18
|
+
end
|
19
|
+
|
20
|
+
def log
|
21
|
+
entries.collect do |level, context, message|
|
22
|
+
"[#{level}] #{context} #{message}"
|
23
|
+
end.join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
def entries
|
27
|
+
@log.entries
|
28
|
+
end
|
29
|
+
|
30
|
+
def clear
|
31
|
+
@log.clear
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def instantiate_log(object)
|
37
|
+
type, options = object.class.object_logging
|
38
|
+
type = "base", options = {} if type.nil?
|
39
|
+
class_name = type.to_s.split("_").collect{ |word| word.capitalize }.join
|
40
|
+
klass = ObjectLogging::Log.const_get(class_name)
|
41
|
+
klass.new(object, options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def make_entry(level, message, options)
|
45
|
+
method_name = options[:method_name] || get_method_name
|
46
|
+
class_name = options[:class_name] || get_class_name(method_name)
|
47
|
+
context = "#{class_name}##{method_name}"
|
48
|
+
@log.log(level.upcase, context, message)
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_method_name
|
52
|
+
m = caller[2].match(/`(.+)'/)
|
53
|
+
if m
|
54
|
+
m[1]
|
55
|
+
else
|
56
|
+
"(unknown)"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_class_name(method_name)
|
61
|
+
if @object.respond_to?(method_name.to_sym)
|
62
|
+
@object.class.name
|
63
|
+
else
|
64
|
+
"(unknown)"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ObjectLoggingTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_basic
|
6
|
+
u = User.new
|
7
|
+
u.foo
|
8
|
+
u.bar
|
9
|
+
expected = [
|
10
|
+
["DEBUG", "User#foo", "foo"],
|
11
|
+
["INFO", "User#bar", "bar"]
|
12
|
+
]
|
13
|
+
assert_equal expected, u.logger.entries
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_usurping
|
17
|
+
u = User.new
|
18
|
+
a = Account.new
|
19
|
+
|
20
|
+
u.foo
|
21
|
+
a.foi
|
22
|
+
|
23
|
+
u_logger = u.logger
|
24
|
+
u.logger = a.logger
|
25
|
+
|
26
|
+
u.bar
|
27
|
+
a.baz
|
28
|
+
|
29
|
+
u.logger = u_logger
|
30
|
+
|
31
|
+
u.foo
|
32
|
+
a.foi
|
33
|
+
|
34
|
+
expected = [
|
35
|
+
["DEBUG", "User#foo", "foo"],
|
36
|
+
["DEBUG", "User#foo", "foo"]
|
37
|
+
]
|
38
|
+
assert_equal expected, u.logger.entries
|
39
|
+
|
40
|
+
expected = [
|
41
|
+
["DEBUG", "Account#foi", "foi"],
|
42
|
+
["INFO", "User#bar", "bar"],
|
43
|
+
["INFO", "Account#baz", "baz"],
|
44
|
+
["DEBUG", "Account#foi", "foi"],
|
45
|
+
]
|
46
|
+
assert_equal expected, a.logger.entries
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_inheritance
|
50
|
+
p = Person.new
|
51
|
+
s = Schmuck.new
|
52
|
+
assert_equal p.class.object_logging, s.class.object_logging
|
53
|
+
assert_not_equal p.class.object_logging.object_id, s.class.object_logging.object_id
|
54
|
+
assert_equal([:rails_log, {}], s.class.object_logging)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
+
require 'object_logging'
|
7
|
+
|
8
|
+
class Test::Unit::TestCase
|
9
|
+
end
|
10
|
+
|
11
|
+
class User
|
12
|
+
include ObjectLogging
|
13
|
+
|
14
|
+
def foo
|
15
|
+
logger.debug("foo")
|
16
|
+
end
|
17
|
+
|
18
|
+
def bar
|
19
|
+
logger.info("bar")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Account
|
24
|
+
include ObjectLogging
|
25
|
+
|
26
|
+
def foi
|
27
|
+
logger.debug("foi")
|
28
|
+
end
|
29
|
+
|
30
|
+
def baz
|
31
|
+
logger.info("baz")
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
class Person
|
37
|
+
include ObjectLogging
|
38
|
+
object_logging :rails_log
|
39
|
+
end
|
40
|
+
|
41
|
+
class Schmuck < Person
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: object_logging
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Christopher J. Bottaro
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-10 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: It's a pain to trudge through large log files. Sometimes you just want to see log messages for one particular object.
|
22
|
+
email: cjbottaro@alumni.cs.utexas.edu
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- LICENSE
|
29
|
+
- README.rdoc
|
30
|
+
files:
|
31
|
+
- .document
|
32
|
+
- .gitignore
|
33
|
+
- LICENSE
|
34
|
+
- README.rdoc
|
35
|
+
- Rakefile
|
36
|
+
- VERSION
|
37
|
+
- lib/object_logging.rb
|
38
|
+
- lib/object_logging/log/base.rb
|
39
|
+
- lib/object_logging/log/rails_cache.rb
|
40
|
+
- lib/object_logging/log/rails_log.rb
|
41
|
+
- lib/object_logging/log/stdout.rb
|
42
|
+
- lib/object_logging/logger.rb
|
43
|
+
- lib/object_logging/metaclass.rb
|
44
|
+
- test/object_logging_test.rb
|
45
|
+
- test/test_helper.rb
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/cjbottaro/object_logging
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options:
|
52
|
+
- --charset=UTF-8
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.3.6
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Super simple logging for objects.
|
76
|
+
test_files:
|
77
|
+
- test/object_logging_test.rb
|
78
|
+
- test/test_helper.rb
|