object_tracker 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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