object_logging 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
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.
@@ -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.
@@ -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,14 @@
1
+ require "object_logging/log/base"
2
+
3
+ module ObjectLogging
4
+ module Log
5
+ class RailsLog < Base
6
+
7
+ def log(level, context, message)
8
+ super
9
+ Rails.logger.send(level.downcase, "#{context} #{message}")
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require "object_logging/log/base"
2
+
3
+ module ObjectLogging
4
+ module Log
5
+ class Stdout < Base
6
+
7
+ def log(level, context, message)
8
+ super
9
+ puts "[#{level.downcase}] #{context} #{message}"
10
+ end
11
+
12
+ end
13
+ end
14
+ 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,7 @@
1
+ class Object
2
+ def metaclass
3
+ class << self
4
+ self
5
+ end
6
+ end
7
+ 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
@@ -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