object_tracker 2.0.0 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a7d0b65299e8afcbd85241099ca20179d143b74
4
- data.tar.gz: 03425ae584ea22e6a94d928c9c566d42b3f2984d
3
+ metadata.gz: 3fc6c464b675df1affa9690508114fb9ac137606
4
+ data.tar.gz: f8a2e38b99381cab9cd899670bad36d3d14fab7f
5
5
  SHA512:
6
- metadata.gz: d6919b9db7a8442104f7b9caa0d388536d3ef368c876c65717ffaa9bd277152397e89ffaf0f86d609f24a54cb861453e8539b7d68cb60c1984ef6fb8d80ead79
7
- data.tar.gz: 6209b7936adf4326b0d0c61d24e018fc6bab9e8b1ce6cbd4445533cde6325c718dfc448dde3d687b1646666d24789e5b17878a767620a43469f72f2805c43b4c
6
+ metadata.gz: 1518da9f3f6c230a8caf600a6b6cc7403625a57bb0b2ad58d64d39cfc0d51d1ca48909ba957ab083bcb2e33b8be16130e06e75283b9e4bd05fd2f45c5d3f7c5b
7
+ data.tar.gz: 2dd55ed1e2aa7d4e96f4a5d86e0fa7dc37a21de24ed4c5c0e1931ff130dfb766bda5d784f345d740256294d9003cd133d1cd97b370ee4b063d19cafad9903ad0
@@ -1,19 +1,29 @@
1
+ require 'logger'
1
2
  require 'benchmark'
2
3
  require 'object_tracker/version'
3
4
 
4
5
  module ObjectTracker
5
6
  autoload :TrackerMethod, 'object_tracker/tracker_method'
7
+ autoload :LogFormatter, 'object_tracker/log_formatter'
6
8
 
7
9
  # @param method_names [Array<Symbol>] method names to track
8
10
  # @option :except [Array<Symbol>] method names to NOT track
9
- # @option :before [Proc] proc to call before method execution (e.g. ->(_name, _context, *_args) {})
10
- # @option :after [Proc] proc to call after method execution (e.g. ->(_name, _context, *_args) {})
11
+ # @option :before [Proc] proc to call before method execution (e.g. ->(name, context, args) {})
12
+ # @option :after [Proc] proc to call after method execution (e.g. ->(name, context, args, duration) {})
11
13
  def track_all!(method_names = [], **options)
12
14
  ObjectTracker.(self, method_names, **options)
13
15
  self
14
16
  end
15
17
 
16
18
  class << self
19
+ attr_writer :logger
20
+
21
+ def logger
22
+ @logger ||= Logger.new(STDOUT).tap do |config|
23
+ config.formatter = LogFormatter.new
24
+ end
25
+ end
26
+
17
27
  def reserved_tracker_methods
18
28
  @__reserved_methods ||= begin
19
29
  names = [:__send__]
@@ -32,94 +42,124 @@ module ObjectTracker
32
42
  # @param obj [Object] class or instance to track
33
43
  # @param method_names [Array<Symbol>] method names to track
34
44
  # @option :except [Array<Symbol>] method names to NOT track
35
- # @option :before [Proc] proc to call before method execution (e.g. ->(_name, _context, *_args) {})
36
- # @option :after [Proc] proc to call after method execution (e.g. ->(_name, _context, *_args) {})
45
+ # @option :before [Proc] proc to call before method execution (e.g. ->(name, context, args) {})
46
+ # @option :after [Proc] proc to call after method execution (e.g. ->(name, context, args, duration) {})
37
47
  def self.call(obj, method_names = [], except: [], **options)
38
- class_methods = []
39
- inst_methods = []
40
- reserved = obj.respond_to?(:reserved_tracker_methods) ? obj.reserved_tracker_methods : ObjectTracker.reserved_tracker_methods
41
- obj_instance = obj.respond_to?(:allocate) ? obj.allocate : obj
42
- if Array(method_names).any?
43
- Array(method_names).each do |method_name|
44
- if obj.methods.include?(method_name)
45
- class_methods << TrackerMethod.new(obj, method_name)
46
- elsif obj.respond_to?(:instance_method)
47
- inst_methods << TrackerMethod.new(obj_instance, method_name)
48
- end
49
- end
50
- else
51
- if obj.respond_to?(:instance_methods)
52
- (obj.instance_methods - reserved - Array(except)).each do |method_name|
53
- inst_methods << TrackerMethod.new(obj_instance, method_name)
54
- end
55
- end
56
- (obj.methods - reserved - Array(except)).each do |method_name|
57
- class_methods << TrackerMethod.new(obj, method_name)
58
- end
59
- end
48
+ class_methods, inst_methods = ObjectTracker.build_tracker_methods(obj, method_names, except: except)
49
+ name = obj.to_s
60
50
  obj.send :extend, ObjectTracker.define_tracker_mod(obj, :TrackerExt, ObjectTracker.build_tracker_mod(class_methods, options))
61
51
  if inst_methods.any?
62
- obj.send :prepend, ObjectTracker.define_tracker_mod(obj, :InstanceTrackerExt, ObjectTracker.build_tracker_mod(inst_methods, options))
52
+ # Silence all the noise about comparing class name and checking object behavior
53
+ ObjectTracker.with_error_logging do
54
+ obj.send :prepend, ObjectTracker.define_tracker_mod(obj, :InstanceTrackerExt, ObjectTracker.build_tracker_mod(inst_methods, options))
55
+ end
63
56
  end
57
+ logger.info { "following #{name}" }
64
58
  obj
65
59
  end
66
60
 
67
61
  def self.define_tracker_mod(context, name, mod)
68
62
  context = context.class unless context.respond_to?(:const_set)
63
+ if context.const_defined?(name, false)
64
+ context.send :remove_const, name
65
+ end
69
66
  context.const_set name, mod
70
67
  end
71
68
 
72
69
  # @param trackers [Array<TrackerMethod>]
73
70
  # @option :mod [Module] module to add tracking to, will be mixed into self
74
- # @option :before [Proc] proc to call before method execution (e.g. ->(_name, _context, *_args) {})
75
- # @option :after [Proc] proc to call after method execution (e.g. ->(_name, _context, *_args) {})
71
+ # @option :before [Proc] proc to call before method execution (e.g. ->(name, context, args) {})
72
+ # @option :after [Proc] proc to call after method execution (e.g. ->(name, context, args, duration) {})
76
73
  def self.build_tracker_mod(trackers, mod: Module.new, before: nil, after: nil)
77
74
  ObjectTracker.tracker_hooks[:before] << before if before
78
75
  ObjectTracker.tracker_hooks[:after] << after if after
79
76
  Array(trackers).each do |tracker|
80
77
  mod.module_eval <<-RUBY, __FILE__, __LINE__
81
78
  def #{tracker.name}(*args)
82
- ObjectTracker.call_tracker_hooks(:before, "#{tracker.display_name}", self, *args)
83
- result, message = ObjectTracker.call_with_tracking("#{tracker.display_name}", args, "#{tracker.source}") { super }
84
- puts message
79
+ ObjectTracker.call_tracker_hooks(:before, "#{tracker.display_name}", self, args)
80
+ result, message, duration = ObjectTracker.call_with_tracking("#{tracker.display_name}", args, "#{tracker.source}") { super }
81
+ ObjectTracker.logger.debug { message + " (%.5f)" % duration }
85
82
  result
86
83
  ensure
87
- ObjectTracker.call_tracker_hooks(:after, "#{tracker.display_name}", self, *args)
84
+ ObjectTracker.call_tracker_hooks(:after, "#{tracker.display_name}", self, args, duration)
88
85
  end
89
86
  RUBY
90
87
  end
91
88
  mod
92
89
  end
93
90
 
91
+ #
92
+ # Private
93
+ #
94
+
95
+ def self.build_tracker_methods(obj, method_names, except: [])
96
+ class_methods, inst_methods = [], []
97
+ reserved = obj.respond_to?(:reserved_tracker_methods) ? obj.reserved_tracker_methods : ObjectTracker.reserved_tracker_methods
98
+ obj_instance = obj.respond_to?(:allocate) ? obj.allocate : obj
99
+ if Array(method_names).any?
100
+ Array(method_names).each do |method_name|
101
+ if obj.methods.include?(method_name)
102
+ class_methods << TrackerMethod.new(obj, method_name)
103
+ elsif obj.respond_to?(:instance_method)
104
+ inst_methods << TrackerMethod.new(obj_instance, method_name)
105
+ end
106
+ end
107
+ else
108
+ if obj.respond_to?(:instance_methods)
109
+ (obj.instance_methods - reserved - Array(except)).each do |method_name|
110
+ inst_methods << TrackerMethod.new(obj_instance, method_name)
111
+ end
112
+ end
113
+ (obj.methods - reserved - Array(except)).each do |method_name|
114
+ class_methods << TrackerMethod.new(obj, method_name)
115
+ end
116
+ end
117
+ return class_methods, inst_methods
118
+ end
119
+
94
120
  # @note If we don't rescue, watch out for segfaults o.0
95
- def self.call_tracker_hooks(key, method_name, context, *args)
121
+ def self.call_tracker_hooks(key, method_name, context, args, duration = nil)
96
122
  tracker_hooks[key].each do |hook|
97
- hook.call(context, method_name, *args) rescue nil
123
+ begin
124
+ if duration
125
+ hook.call(context, method_name, args, duration)
126
+ else
127
+ hook.call(context, method_name, args)
128
+ end
129
+ rescue Exception
130
+ next
131
+ end
98
132
  end
99
133
  end
100
134
 
101
- def self.call_with_tracking(method_name, args, source)
135
+ def self.call_with_tracking(msg, args, source)
102
136
  result = nil
103
- msg = %Q( * called "#{method_name}" )
104
- msg << "with " << ObjectTracker.format_args(args) unless args.empty?
105
- msg << "[#{source}]"
137
+ msg += ObjectTracker.format_args(args) unless args.empty?
138
+ msg += " [#{source}]"
106
139
  bm = Benchmark.measure do
107
140
  result = yield rescue nil
108
141
  end
109
- [result, msg << " (%.5f)" % bm.real]
142
+ [result, msg, bm.real]
110
143
  end
111
144
 
112
145
  def self.format_args(args)
113
- result = "["
146
+ result = " with ["
114
147
  args.each do |arg|
115
148
  result << (arg ? arg.to_s : "nil")
116
149
  result << ", "
117
150
  end
118
151
  result.sub! /,\s\z/, ""
119
- result << "] "
152
+ result << "]"
120
153
  end
121
154
 
122
155
  def self.tracker_hooks
123
156
  @__tracker_hooks ||= Hash.new { |me, key| me[key] = [] }
124
157
  end
158
+
159
+ def self.with_error_logging
160
+ old_log_level, logger.level = logger.level, Logger::ERROR
161
+ yield
162
+ ensure
163
+ logger.level = old_log_level if old_log_level
164
+ end
125
165
  end
@@ -0,0 +1,9 @@
1
+ module ObjectTracker
2
+ class LogFormatter < Logger::Formatter
3
+ FORMAT = "[%s] %5s -- ObjectTracker: %s\n".freeze
4
+
5
+ def call(severity, time, _progname, msg)
6
+ FORMAT % [format_datetime(time), severity, msg2str(msg)]
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module ObjectTracker
2
- VERSION = '2.0.0'.freeze
2
+ VERSION = '2.1.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: object_tracker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Buckley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-10 00:00:00.000000000 Z
11
+ date: 2017-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -47,6 +47,7 @@ extensions: []
47
47
  extra_rdoc_files: []
48
48
  files:
49
49
  - lib/object_tracker.rb
50
+ - lib/object_tracker/log_formatter.rb
50
51
  - lib/object_tracker/tracker_method.rb
51
52
  - lib/object_tracker/version.rb
52
53
  - object_tracker.gemspec