debug_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.
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: []