debug_logging 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a2354763d5bcb6438947c4e268683c956477b812
4
+ data.tar.gz: 2c0c20aff357b165857f6c7794bb54e87e2b7ac3
5
+ SHA512:
6
+ metadata.gz: b6312e56ce69f08fa23d1e57c24b7e10354e4f971304b6dbed74d3232cb2593d1ccff250f0e5eebc51e24edf80c60c646c8f636cdf135a7d8d1967289903334d
7
+ data.tar.gz: 987ea132ee891882e14a1bee41bbe47084700468767588e21eaa2a487098178613b36592d0f69e17c55fdfcad9bd1a175a0613bea9b5064bf028212fd53ab6a2
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.1
5
+ - 2.2
6
+ - 2.3
7
+ - 2.4.0
8
+ before_install: gem install bundler -v 1.14.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in debug_logging.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # DebugLogging
2
+
3
+ ## Next Level Magic
4
+
5
+ * Classes inheriting from Module.
6
+ * Cats and dogs sleeping together.
7
+ * Yet this gem monkey patches nothing.
8
+ * 100% clean.
9
+ * 0% obtrusive.
10
+ * 100% tested.
11
+ * 50% Ruby 2.0+ compatible.
12
+ * 100% Ruby 2.1+ compatible.
13
+ * 10g Monosodium glutamate.
14
+
15
+ NOTE: The manner this is made to work for class methods is totally different than the way this is made to work for instance methods.
16
+
17
+ NOTE: The instance method logging works on Ruby 2.0+
18
+
19
+ NOTE: The class method logging works on Ruby 2.1+
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem 'debug_logging'
27
+ ```
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install debug_logging
36
+
37
+ ## Usage
38
+
39
+ Crack open the specs for usage examples.
40
+
41
+ ### Without Rails
42
+
43
+ It just works. ;)
44
+ Configuration can go anywhere you want.
45
+
46
+ ### With Rails
47
+
48
+ Recommend creating `config/initializers/debug_logging.rb` with:
49
+ ```ruby
50
+ # Showing the defaults
51
+ DebugLogging.logger = Logger.new(STDOUT) # you probably want to override to be the Rails.logger
52
+ DebugLogging.log_level = :debug # at what level do the messages created by this gem sent at?
53
+ DebugLogging.last_hash_to_s_proc = nil # e.g. ->(hash) { "#{hash.keys}" }
54
+ DebugLogging.last_hash_max_length = 1_000
55
+ DebugLogging.args_max_length = 1_000
56
+ DebugLogging.instance_benchmarks = false
57
+ DebugLogging.class_benchmarks = false
58
+ DebugLogging.add_invocation_id = true # invocation id allows you to identify a method call uniquely in a log
59
+ DebugLogging.ellipsis = " ✂️ …".freeze
60
+ ```
61
+
62
+ ```ruby
63
+ class Car
64
+
65
+ # For instance methods:
66
+ # Option 1: specify the exact method(s) to add logging to
67
+ include DebugLogging::InstanceLogger.new(i_methods: [:drive, :stop])
68
+
69
+ extend DebugLogging::ClassLogger
70
+
71
+ logged def self.make; new; end
72
+ def self.design(*args); new; end
73
+ def self.safety(*args); new; end
74
+ logged :design, :safety
75
+
76
+ def drive(speed); speed; end
77
+ def stop; 0; end
78
+
79
+ # For instance methods:
80
+ # Option 2: add logging to all instance methods defined above (but *not* defined below)
81
+ include DebugLogging::InstanceLogger.new(i_methods: self.instance_methods(false))
82
+
83
+ def will_not_be_logged; false; end
84
+
85
+ end
86
+ ```
87
+
88
+ ## Development
89
+
90
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
91
+
92
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
93
+
94
+ ## Contributing
95
+
96
+ Bug reports and pull requests are welcome on GitHub at https://github.com/pboling/debug_logging.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "debug_logging"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'debug_logging/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "debug_logging"
8
+ spec.version = DebugLogging::VERSION
9
+ spec.authors = ["Peter Boling"]
10
+ spec.email = ["peter.boling@gmail.com"]
11
+
12
+ spec.summary = %q{Drop-in debug logging useful when a call stack gets unruly}
13
+ spec.description = %q{Automatically log Class.method(arguments) as they are called at runtime!}
14
+ spec.homepage = "https://github.com/pboling/debug_logging"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "rspec-pending_for"
24
+ spec.add_development_dependency "bundler", "~> 1.14"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ end
@@ -0,0 +1,30 @@
1
+ module DebugLogging
2
+ module ArgumentPrinter
3
+ def self.to_s(args)
4
+ length = 0
5
+ if DebugLogging.last_hash_to_s_proc && args[-1].is_a?(Hash)
6
+ if args.length > 1
7
+ add_args_ellipsis = false
8
+ add_last_hash_ellipsis = false
9
+ printed_args = args[0..(-2)].map {|x| x.inspect}.join(", ").tap {|x| add_args_ellipsis = x.length > DebugLogging.args_max_length}[0..(DebugLogging.args_max_length)]
10
+ printed_args << DebugLogging.ellipsis if add_args_ellipsis
11
+ printed_args << ", " << DebugLogging.last_hash_to_s_proc.call(args[-1]).tap {|x| add_last_hash_ellipsis = x.length > DebugLogging.last_hash_max_length}[0..(DebugLogging.last_hash_max_length)]
12
+ printed_args << DebugLogging.ellipsis if add_last_hash_ellipsis
13
+ else
14
+ printed_args = DebugLogging.last_hash_to_s_proc.call(args[0]).tap {|x| add_last_hash_ellipsis = x.length > DebugLogging.last_hash_max_length}[0..(DebugLogging.last_hash_max_length)]
15
+ printed_args << DebugLogging.ellipsis if add_last_hash_ellipsis
16
+ end
17
+ else
18
+ add_args_ellipsis = false
19
+ if args.length == 1 && args[0].is_a?(Hash)
20
+ # handle double splat
21
+ printed_args = ("**" << args.map {|x| x.inspect}.join(", ").tap {|x| add_args_ellipsis = x.length > DebugLogging.args_max_length})[0..(DebugLogging.args_max_length)]
22
+ else
23
+ printed_args = args.map {|x| x.inspect}.join(", ").tap {|x| add_args_ellipsis = x.length > DebugLogging.args_max_length}[0..(DebugLogging.args_max_length)]
24
+ end
25
+ printed_args << DebugLogging.ellipsis if add_args_ellipsis
26
+ end
27
+ "(#{printed_args})"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ module DebugLogging
2
+ module ClassLogger
3
+ def logged(*methods_to_log)
4
+ methods_to_log.each do |method_to_log|
5
+ # method name will always be a symbol
6
+ original_method = method(method_to_log)
7
+ (class << self; self; end).class_eval do
8
+ define_method(method_to_log) do |*args|
9
+ method_return_value = nil
10
+ invocation_id = " ~#{args.object_id}@#{Time.now.to_i}~" if DebugLogging.add_invocation_id && args
11
+ DebugLogging.log "#{self}.#{method_to_log}#{ArgumentPrinter.to_s(args)}#{invocation_id}"
12
+ if DebugLogging.class_benchmarks
13
+ elapsed = Benchmark.realtime do
14
+ method_return_value = original_method.call(*args)
15
+ end
16
+ DebugLogging.log "#{self}.#{method_to_log} completed in #{sprintf("%f", elapsed)}s#{invocation_id}"
17
+ else
18
+ method_return_value = original_method.call(*args)
19
+ end
20
+ method_return_value
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module DebugLogging
2
+ class InstanceLogger < Module
3
+ def initialize(i_methods: nil)
4
+ @instance_methods_to_log = Array(i_methods) if i_methods
5
+ end
6
+ def included(base)
7
+ if @instance_methods_to_log
8
+ instance_method_logger = DebugLogging::InstanceLoggerModulizer.to_mod(@instance_methods_to_log)
9
+ base.send(:prepend, instance_method_logger)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ module DebugLogging
2
+ module InstanceLoggerModulizer
3
+ def self.to_mod(methods_to_log = [])
4
+ Module.new do
5
+ Array(methods_to_log).each do |method_to_log|
6
+ define_method(method_to_log.to_sym) do |*args, &block|
7
+ method_return_value = nil
8
+ invocation_id = " ~#{args.object_id}@#{Time.now.to_i}~" if DebugLogging.add_invocation_id && args
9
+ DebugLogging.log "#{self.class}##{method_to_log}#{DebugLogging::ArgumentPrinter.to_s(args)}#{invocation_id}"
10
+ if DebugLogging.instance_benchmarks
11
+ elapsed = Benchmark.realtime do
12
+ method_return_value = super(*args, &block)
13
+ end
14
+ DebugLogging.log "#{self.class}##{method_to_log} completed in #{sprintf("%f", elapsed)}s#{invocation_id}"
15
+ else
16
+ method_return_value = super(*args, &block)
17
+ end
18
+ method_return_value
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module DebugLogging
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,123 @@
1
+ require "logger"
2
+ require "debug_logging/version"
3
+ require "debug_logging/argument_printer"
4
+ require "debug_logging/instance_logger_modulizer"
5
+ require "debug_logging/instance_logger"
6
+ require "debug_logging/class_logger"
7
+
8
+ ####################
9
+ # #
10
+ # Next Level Magic #
11
+ # Classes inheriting from Module.
12
+ # Cats and dogs sleeping together.
13
+ # #
14
+ ####################
15
+ # #
16
+ # NOTE: The manner this is made to work for class methods is totally different
17
+ # than the way this is made to work for instance methods.
18
+ # NOTE: The instance method manner works on Ruby 2.0+
19
+ # NOTE: The class method manner works on Ruby 2.1+
20
+ # #
21
+ ####################
22
+ # #
23
+ # USAGE (see specs)#
24
+ # #
25
+ # class Car
26
+ #
27
+ # # For instance methods:
28
+ # # Option 1: specify the exact method(s) to add logging to
29
+ # include DebugLogging::InstanceLogger.new(i_methods: [:drive, :stop])
30
+ #
31
+ # extend DebugLogging::ClassLogger
32
+ #
33
+ # logged def self.make; new; end
34
+ # def self.design(*args); new; end
35
+ # def self.safety(*args); new; end
36
+ # logged :design, :safety
37
+ #
38
+ # def drive(speed); speed; end
39
+ # def stop; 0; end
40
+ #
41
+ # # For instance methods:
42
+ # # Option 2: add logging to all instance methods defined above (but *not* defined below)
43
+ # include DebugLogging::InstanceLogger.new(i_methods: self.instance_methods(false))
44
+ #
45
+ # def will_not_be_logged; false; end
46
+ #
47
+ # end
48
+ # #
49
+ ####################
50
+
51
+ module DebugLogging
52
+ def self.config_reset
53
+ @@logger = nil
54
+ @@log_level = :debug
55
+ @@last_hash_to_s_proc = nil
56
+ @@last_hash_max_length = 1_000
57
+ @@args_max_length = 1_000
58
+ @@instance_benchmarks = false
59
+ @@class_benchmarks = false
60
+ @@add_invocation_id = true
61
+ @@ellipsis = " ✂️ …".freeze
62
+ end
63
+ def self.logger
64
+ @@logger ||= Logger.new(STDOUT)
65
+ end
66
+ def self.logger=(logger)
67
+ @@logger = logger
68
+ end
69
+ def self.log_level
70
+ @@log_level || :debug
71
+ end
72
+ def self.log_level=(log_level)
73
+ @@log_level = log_level
74
+ end
75
+ def self.last_hash_to_s_proc
76
+ @@last_hash_to_s_proc
77
+ end
78
+ def self.last_hash_to_s_proc=(last_hash_to_s_proc)
79
+ @@last_hash_to_s_proc = last_hash_to_s_proc
80
+ end
81
+ def self.last_hash_max_length
82
+ @@last_hash_max_length || 1_000
83
+ end
84
+ def self.last_hash_max_length=(last_hash_max_length)
85
+ @@last_hash_max_length = last_hash_max_length
86
+ end
87
+ def self.args_max_length
88
+ @@args_max_length || 1_000
89
+ end
90
+ def self.args_max_length=(args_max_length)
91
+ @@args_max_length = args_max_length
92
+ end
93
+ def self.instance_benchmarks
94
+ @@instance_benchmarks
95
+ end
96
+ def self.instance_benchmarks=(instance_benchmarks)
97
+ require "benchmark" if instance_benchmarks
98
+ @@instance_benchmarks = instance_benchmarks
99
+ end
100
+ def self.class_benchmarks
101
+ @@class_benchmarks
102
+ end
103
+ def self.class_benchmarks=(class_benchmarks)
104
+ require "benchmark" if class_benchmarks
105
+ @@class_benchmarks = class_benchmarks
106
+ end
107
+ def self.add_invocation_id
108
+ @@add_invocation_id
109
+ end
110
+ def self.add_invocation_id=(add_invocation_id)
111
+ @@add_invocation_id = add_invocation_id
112
+ end
113
+ def self.ellipsis
114
+ @@ellipsis
115
+ end
116
+ def self.ellipsis=(ellipsis)
117
+ @@ellipsis = ellipsis
118
+ end
119
+ def self.log(message)
120
+ logger.send(log_level, message)
121
+ end
122
+ config_reset # setup defaults
123
+ end
@@ -0,0 +1,54 @@
1
+ # Simpler version of what the sibling DebugLogging library does. Included as a bauble.
2
+ #
3
+ # Automatically log Class.method(arguments) as they are called at runtime!
4
+ #
5
+ # NOTE: For a more advanced version see the debug_logging gem
6
+ # NOTE: The manner this is made to work for class methods is totally different than the way this is made to work for instance methods.
7
+ # NOTE: The instance method manner of logging works on Ruby 2.0+
8
+ # NOTE: The class method manner of logging works on Ruby 2.1+
9
+ class SimpleDebugLogging < Module
10
+ def initialize(i_methods: nil)
11
+ @instance_methods_to_log = Array(i_methods) if i_methods
12
+ end
13
+ def included(base)
14
+ instance_method_logger = InstanceMethodLoggerModulizer.to_mod(@instance_methods_to_log)
15
+ base.send(:prepend, instance_method_logger)
16
+ end
17
+ module ClassMethodLogger
18
+ def logged(*methods_to_log)
19
+ methods_to_log.each do |method_to_log|
20
+ original_method = method(method_to_log)
21
+ (class << self; self; end).class_eval do
22
+ define_method(method_to_log.to_sym) do |*args|
23
+ method_return_value = nil
24
+ invocation_id = " ~#{args.object_id}@#{Time.now.to_i}~" if args
25
+ puts "#{self}.#{method_to_log}(#{args.map {|x| x.inspect}.join(", ")})#{invocation_id}"
26
+ elapsed = Benchmark.realtime do
27
+ method_return_value = original_method.call(*args)
28
+ end
29
+ puts "#{self}.#{method_to_log} ~#{args.hash}~ complete in #{elapsed}s#{invocation_id}"
30
+ method_return_value
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ module InstanceMethodLoggerModulizer
37
+ def self.to_mod(methods_to_log = [])
38
+ Module.new do
39
+ Array(methods_to_log).each do |method_to_log|
40
+ define_method(method_to_log.to_sym) do |*args, &block|
41
+ method_return_value = nil
42
+ invocation_id = " ~#{args.object_id}@#{Time.now.to_i}~" if args
43
+ puts "#{self.class}##{method_to_log}(#{args.map {|x| x.inspect}.join(", ")})#{invocation_id}"
44
+ elapsed = Benchmark.realtime do
45
+ method_return_value = super(*args, &block)
46
+ end
47
+ puts "#{self.class}##{method_to_log} ~#{args.hash}~ complete in #{elapsed}s#{invocation_id}"
48
+ method_return_value
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: debug_logging
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter Boling
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-03-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec-pending_for
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.14'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: Automatically log Class.method(arguments) as they are called at runtime!
70
+ email:
71
+ - peter.boling@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - README.md
81
+ - Rakefile
82
+ - bin/console
83
+ - bin/setup
84
+ - debug_logging.gemspec
85
+ - lib/debug_logging.rb
86
+ - lib/debug_logging/argument_printer.rb
87
+ - lib/debug_logging/class_logger.rb
88
+ - lib/debug_logging/instance_logger.rb
89
+ - lib/debug_logging/instance_logger_modulizer.rb
90
+ - lib/debug_logging/version.rb
91
+ - lib/simple_debug_logging.rb
92
+ homepage: https://github.com/pboling/debug_logging
93
+ licenses: []
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.6.8
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Drop-in debug logging useful when a call stack gets unruly
115
+ test_files: []