ruby-production-breakpoints 0.0.5 → 0.0.6

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
  SHA256:
3
- metadata.gz: 393332e205830e98423e4e80256b91d0a5619b2459dade719e22e9a90a507b34
4
- data.tar.gz: 255897924c095642d81a0efbfb4cb98acf384f99bc37d3ccc6b699729682410a
3
+ metadata.gz: c667c558395ef7da2130c3085956a438366a9ae49c9531b97ab08f994a90e157
4
+ data.tar.gz: 946c38475edf95386ac832e82815e5a5cb0efeb1a7f1d9a05300939dbc6fab94
5
5
  SHA512:
6
- metadata.gz: 65d5ef0836703f22a47344931525028b506d74f396d1185c7213e4db6d426cf3c33ba0c873474abd486bbb5e287976f4c7ec3a0006c22975ac93fe613e43be32
7
- data.tar.gz: f37633bf6107dfac1eccfe872069012af57ab1c85ce05a4211aa22dfff5ec5d47333dae2d5327f6ab1f85291d06fb2284a4ae56a20aa7c47df08ccfdadea340b
6
+ metadata.gz: 0146b4b990c9a9ac018eb4b3dc365891cfb9b55b0b8b9fc902ebfb4bb9ab50eeb548e3536d9a02d5ffd5568eb5c47dfb2d735f5c6339ee0153ae1f3412cf54c8
7
+ data.tar.gz: 4ed8781d90ea4351d1ff980726aac868198e46bbadcb820c88de0b6057464d8a255f9ba9a010919049e6ab8c746e0274dfb5a85828d93f3c9f1d0100a9681c05
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'unmixer'
4
+ using Unmixer
5
+
6
+ module ProductionBreakpoints
7
+ module Breakpoints
8
+ class Base
9
+ TRACEPOINT_TYPES = [].freeze
10
+
11
+ attr_reader :provider_name, :name, :tracepoint
12
+
13
+ def initialize(source_file, start_line, end_line, trace_id: 1)
14
+ @injector_module = nil
15
+ @source_file = source_file
16
+ @start_line = start_line
17
+ @end_line = end_line
18
+ @trace_id = trace_id
19
+ @method = self.class.name.split('::').last.downcase
20
+ @parser = ProductionBreakpoints::Parser.new(@source_file)
21
+ @node = @parser.find_definition_node(@start_line, @end_line)
22
+ @method_override = ProductionBreakpoints::MethodOverride.new(@parser, start_line, end_line)
23
+ @ns = Object.const_get(@parser.find_definition_namespace(@node)) # FIXME: error handling, if not found
24
+ @provider_name = File.basename(@source_file).gsub('.', '_')
25
+ @name = "#{@method}_#{@trace_id}"
26
+ @tracepoint = StaticTracing::Tracepoint.new(@provider_name, @name, *self.class.const_get('TRACEPOINT_TYPES'))
27
+ end
28
+
29
+ def install
30
+ @injector_module = build_redefined_definition_module(@node)
31
+ @ns.prepend(@injector_module)
32
+ end
33
+
34
+ # FIXME: saftey if already uninstalled
35
+ def uninstall
36
+ @ns.instance_eval { unprepend(@injector_module) }
37
+ @injector_module = nil
38
+ end
39
+
40
+ def load
41
+ @tracepoint.provider.enable
42
+ end
43
+
44
+ def unload
45
+ @tracepoint.provider.disable
46
+ end
47
+
48
+ # Allows for specific handling of the selected lines
49
+ def handle(caller_binding)
50
+ eval(@method_override.handler_src.join, caller_binding)
51
+ end
52
+
53
+ def resume(caller_binding)
54
+ eval(@method_override.resume_src.join, caller_binding) if @method_override.resume_src
55
+ end
56
+
57
+ private
58
+
59
+ # A custom module we'll prepend in order to override
60
+ # us to keep the expected binding for the wrapped code, and remainder of the method
61
+ def build_redefined_definition_module(node)
62
+ # This is the metaprogramming to inject our breakpoint handle
63
+ handler = "ProductionBreakpoints.installed_breakpoints[:#{@trace_id}].handle(Kernel.binding)"
64
+
65
+ # This injects our handler at the end of the original source code
66
+ injected = @parser.inject_metaprogramming_handlers(handler, node.first_lineno, node.last_lineno)
67
+ # ProductionBreakpoints.config.logger.debug(injected)
68
+ Module.new { module_eval { eval(injected); eval('def production_breakpoint_enabled?; true; end;') } }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProductionBreakpoints
4
+ module Breakpoints
5
+ # Inspect result of the last evaluated expression
6
+ class Inspect < Base
7
+ TRACEPOINT_TYPES = [String].freeze
8
+
9
+ def handle(caller_binding, &block)
10
+ return super(caller_binding, &block) unless @tracepoint.enabled?
11
+
12
+ val = super(caller_binding, &block)
13
+ @tracepoint.fire(val.inspect)
14
+
15
+ resume(caller_binding, &block) || val
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProductionBreakpoints
4
+ module Breakpoints
5
+ # Exposes nanosecond the latency of executing the selected lines
6
+ class Latency < Base # FIXME: refactor a bunch of these idioms into Base
7
+ TRACEPOINT_TYPES = [Integer].freeze
8
+
9
+ def handle(caller_binding, &block)
10
+ return super(caller_binding, &block) unless @tracepoint.enabled?
11
+
12
+ start_time = StaticTracing.nsec
13
+ val = super(caller_binding, &block)
14
+ duration = StaticTracing.nsec - start_time
15
+ @tracepoint.fire(duration)
16
+ resume(caller_binding, &block) || val
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProductionBreakpoints
4
+ module Breakpoints
5
+ # Show local variables and their values
6
+ class Locals < Base # FIXME: refactor a bunch of these idioms into Base
7
+ TRACEPOINT_TYPES = [String].freeze
8
+
9
+ def handle(caller_binding, &block)
10
+ return super(caller_binding, &block) unless @tracepoint.enabled?
11
+
12
+ val = super(caller_binding, &block)
13
+ locals = caller_binding.local_variables
14
+ locals.delete(:local_bind)
15
+ vals = locals.map { |v| [v, caller_binding.local_variable_get(v)] }.to_h
16
+ @tracepoint.fire(vals.to_json)
17
+ resume(caller_binding, &block) || val
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,74 @@
1
+ # # frozen_string_literal: true
2
+
3
+ # module ProductionBreakpoints
4
+ # module Breakpoints
5
+ # # Show local variables and their values
6
+ # class Ustack < Base
7
+ # TRACEPOINT_TYPES = [String, String, String,
8
+ # String, String, String].freeze
9
+ # MAX_STACK_STR_SIZE = MAX_USDT_STR_SIZE * TRACEPOINT_TYPES.size
10
+
11
+ # def initialize(*args, &block)
12
+ # super(*args, &block)
13
+ # get_ruby_stack_str = <<-EOS
14
+ # caller.map { |l| l.split(":in ") }.to_h
15
+ # EOS
16
+ # @handler_iseq = RubyVM::InstructionSequence.compile(get_ruby_stack_str)
17
+ # end
18
+
19
+ # def handle(vm_tracepoint)
20
+ # return unless @tracepoint.enabled?
21
+
22
+ # stack_map = @handler_iseq.eval(vm_tracepoint.binding)
23
+
24
+ # shortened_map = {}
25
+ # stack_map.each do |k,v|
26
+ # newkey = k
27
+ # #if k.include?('gems')
28
+ # # newkey = k[k.rindex('gems')..-1].split(File::SEPARATOR)[1..-1]
29
+ # # .join(File::SEPARATOR)
30
+ # #elsif k.include?('lib')
31
+ # # newkey = k[k.rindex('lib')..-1].split(File::SEPARATOR)[1..-1]
32
+ # # .join(File::SEPARATOR)
33
+ # #end
34
+ # # FIXME lots of context is lost this way, as the above methods
35
+ # # consistently exceed the max size.
36
+ # # Need to find a more optimal way to shorten the stack here, to
37
+ # # pack it into the 1200 bytes available
38
+ # newkey = File.basename(k)
39
+ # shortened_map[newkey] = v
40
+ # end
41
+ # # ProductionBreakpoints.logger.debug(shortened_map.inspect)
42
+
43
+ # stack_str = shortened_map.to_json
44
+
45
+ # if stack_str.size > (MAX_STACK_STR_SIZE)
46
+ # ProductionBreakpoints.logger.error("Stack exceeds #{MAX_STACK_STR_SIZE}")
47
+ # # Truncate because i'm lazy
48
+ # stack_str = stack_str[0..MAX_STACK_STR_SIZE]
49
+ # end
50
+
51
+ # slices = stack_str.chars.each_slice(MAX_USDT_STR_SIZE).map(&:join)
52
+
53
+ # case slices.size
54
+
55
+ # when 1
56
+ # @tracepoint.fire(slices[0], "", "", "", "", "")
57
+ # when 2
58
+ # @tracepoint.fire(slices[0], slices[1], "", "", "", "")
59
+ # when 3
60
+ # @tracepoint.fire(slices[0], slices[1], slices[2], "", "", "")
61
+ # when 4
62
+ # @tracepoint.fire(slices[0], slices[1], slices[2], slices[3], "", "")
63
+ # when 5
64
+ # @tracepoint.fire(slices[0], slices[1], slices[2], slices[3],
65
+ # slices[4], "")
66
+ # when 6
67
+ # @tracepoint.fire(slices[0], slices[1], slices[2], slices[3],
68
+ # slices[4], slices[5])
69
+
70
+ # end
71
+ # end
72
+ # end
73
+ # end
74
+ # end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby-production-breakpoints/breakpoints/base'
4
+ require 'ruby-production-breakpoints/breakpoints/latency'
5
+ require 'ruby-production-breakpoints/breakpoints/inspect'
6
+ require 'ruby-production-breakpoints/breakpoints/locals'
7
+ require 'ruby-production-breakpoints/breakpoints/ustack'
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module ProductionBreakpoints
6
+ class Configuration
7
+ # Modes of operation for tracers
8
+ module Modes
9
+ ON = 'ON'
10
+ OFF = 'OFF'
11
+ SIGNAL = 'SIGNAL'
12
+
13
+ module SIGNALS
14
+ SIGURG = 'URG'
15
+ end
16
+ end
17
+
18
+ attr_reader :mode, :signal, :configured_breakpoints, :logger
19
+ attr_accessor :path
20
+
21
+ # A new configuration instance
22
+ def initialize
23
+ @mode = Modes::SIGNAL
24
+ @signal = Modes::SIGNALS::SIGURG
25
+ @logger = Logger.new(STDERR)
26
+ end
27
+
28
+ def finish!
29
+ if File.exist?(path)
30
+ @configured_breakpoints = JSON.load(File.read(path))
31
+ enable_trap
32
+ else
33
+ logger.error("Config file #{path} not found")
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ # Disables trap handler
40
+ def disable_trap
41
+ Signal.trap(@signal, 'DEFAULT')
42
+ end
43
+
44
+ # Enables a new trap handler
45
+ def enable_trap
46
+ # ProductionBreakpoints.config.logger.debug("trap handler enabled for #{@signal}")
47
+ Signal.trap(@signal) { ProductionBreakpoints.sync! }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,5 @@
1
+
2
+ # frozen_string_literal: true
3
+
4
+ class NotConfiguredError < StandardError
5
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProductionBreakpoints
4
+ # Extract valueable parts of the method
5
+ class MethodOverride
6
+ def initialize(parser, start_line, end_line)
7
+ @parser = parser
8
+ @source_lines = parser.source_lines
9
+ @node = parser.find_definition_node(start_line, end_line)
10
+ @start_line = start_line
11
+ @end_line = end_line
12
+ end
13
+
14
+ def unmodified_src
15
+ return if @start_line - @node.first_lineno <= 1 # if smaller or equal to one that means we are at the beginning of the method
16
+
17
+ @source_lines[(@node.first_lineno)..(@start_line - 2)]
18
+ end
19
+
20
+ def handler_src
21
+ @source_lines[@start_line - 1..@end_line - 1]
22
+ end
23
+
24
+ def resume_src
25
+ return if @node.last_lineno - @end_line <= 1 # if smaller or equal to one that means we are at the end of the method
26
+
27
+ @source_lines[@end_line..(@node.last_lineno - 2)]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProductionBreakpoints
4
+ # FIXME: this class is a mess, figure out interface and properly separate private / public
5
+ class Parser
6
+ attr_reader :root_node, :source_lines
7
+
8
+ def initialize(source_file)
9
+ @root_node = RubyVM::AbstractSyntaxTree.parse_file(source_file)
10
+ @source_lines = File.read(source_file).lines
11
+ @logger = ProductionBreakpoints.config.logger
12
+ end
13
+
14
+ # FIXME: set a max depth here to pretent unbounded recursion? probably should
15
+ def find_node(node, type, first, last, depth: 0)
16
+ child_nodes = node.children.select { |c| c.is_a?(RubyVM::AbstractSyntaxTree::Node) }
17
+ # @logger.debug("D: #{depth} #{node.type} has #{child_nodes.size} children and spans #{node.first_lineno}:#{node.first_column} to #{node.last_lineno}:#{node.last_column}")
18
+
19
+ if node.type == type && first >= node.first_lineno && last <= node.last_lineno
20
+ return node
21
+ end
22
+
23
+ child_nodes.map { |n| find_node(n, type, first, last, depth: depth + 1) }.flatten
24
+ end
25
+
26
+ def find_lineage(target)
27
+ lineage = _find_lineage(@root_node, target)
28
+ lineage.pop # FIXME: verify leafy node is equal to target or throw an error?
29
+ lineage
30
+ end
31
+
32
+ def find_definition_namespace(target)
33
+ lineage = find_lineage(target)
34
+
35
+ namespaces = []
36
+ lineage.each do |n|
37
+ next unless n.type == :MODULE || n.type == :CLASS
38
+
39
+ symbols = n.children.select { |c| c.is_a?(RubyVM::AbstractSyntaxTree::Node) && c.type == :COLON2 }
40
+ if symbols.size != 1
41
+ @logger.error("Couldn't determine symbol location for parent namespace")
42
+ end
43
+ symbol = symbols.first
44
+
45
+ symstr = @source_lines[symbol.first_lineno - 1][symbol.first_column..symbol.last_column].strip
46
+ namespaces << symstr
47
+ end
48
+
49
+ namespaces.join('::')
50
+ end
51
+
52
+ def find_definition_symbol(start_line, end_line)
53
+ def_node = _find_definition_node(@root_node, start_line, end_line)
54
+ def_column_start = def_node.first_column
55
+ def_column_end = _find_args_start(def_node).first_column
56
+ @source_lines[def_node.first_lineno - 1][(def_column_start + 3 + 1)..def_column_end].strip.to_sym
57
+ end
58
+
59
+ def find_definition_node(start_line, end_line)
60
+ _find_definition_node(@root_node, start_line, end_line)
61
+ end
62
+
63
+ # This method is a litle weird and pretty deep into metaprogramming, so i'll try to explain it
64
+ #
65
+ # Given the source method some_method, and a range of lines to apply the breakpoint to, we will inject
66
+ # calls two breakpoint methods. We will pass these calls the string representation of the original source code.
67
+ # If the string of original source is part of the "handle" block, it will run withing the binding
68
+ # of the method up to that point, and allow for us to run our custom handler method to apply our debugging automation.
69
+ #
70
+ # Any remaining code in the method also needs to be eval'd, as we want it to be recognized in the original binding,
71
+ # and the same binding as we've used for evaluating our handler. This allows us to keep local variables persisted
72
+ # "between blocks", as we want our breakpoint code to have no impact to the original bindings and source code.
73
+ #
74
+ # A generated breakpoint is shown below, the resulting string. is what will be evaluated on the method
75
+ # that we will prepend to the original parent in order to initiate our override.
76
+ #
77
+ # def some_method
78
+ # a = 1
79
+ # sleep 0.5
80
+ # b = a + 1
81
+ # ProductionBreakpoints.installed_breakpoints[:test_breakpoint_install].handle(Kernel.binding)
82
+ # end
83
+ #
84
+ def inject_metaprogramming_handlers(handler, def_start, def_end)
85
+ source = @source_lines.dup
86
+
87
+ source.insert(def_end - 1, "#{handler}\n") # FIXME: columns? and indenting?
88
+ source[(def_start - 1)..(def_end)].join
89
+ end
90
+
91
+ def ruby_source(start_line, end_line)
92
+ @source_lines[(start_line - 1)..(end_line - 1)].join
93
+ end
94
+
95
+ private
96
+
97
+ def _find_lineage(node, target, depth: 0)
98
+ child_nodes = node.children.select { |c| c.is_a?(RubyVM::AbstractSyntaxTree::Node) }
99
+ # @logger.debug("D: #{depth} #{node.type} has #{child_nodes.size} children and spans #{node.first_lineno}:#{node.first_column} to #{node.last_lineno}:#{node.last_column}")
100
+
101
+ if node.type == target.type &&
102
+
103
+ target.first_lineno >= node.first_lineno &&
104
+ target.last_lineno <= node.last_lineno
105
+ return [node]
106
+ end
107
+
108
+ parents = []
109
+ child_nodes.each do |n|
110
+ res = _find_lineage(n, target, depth: depth + 1)
111
+ unless res.empty?
112
+ res.unshift(n)
113
+ parents = res
114
+ end
115
+ end
116
+
117
+ parents.flatten
118
+ end
119
+
120
+ # FIXME: better error handling
121
+ def _find_definition_node(node, start_line, end_line)
122
+ defs = find_node(node, :DEFN, start_line, end_line)
123
+
124
+ if defs.size > 1
125
+ @logger.error('WHaaat? Multiple definitions found?! Bugs will probably follow')
126
+ end
127
+ defs.first
128
+ end
129
+
130
+ # FIXME: better error handling
131
+ def _find_args_start(def_node)
132
+ args = find_node(def_node, :ARGS, def_node.first_lineno, def_node.first_lineno)
133
+
134
+ if args.size > 1
135
+ @logger.error("I didn't think this was possible, I must have been wrong")
136
+ end
137
+ args.first
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProductionBreakpoints
4
+ # Platform detection for ruby-static-tracing
5
+ module Platform
6
+ module_function
7
+
8
+ # Returns true if platform is linux
9
+ def linux?
10
+ /linux/.match(RUBY_PLATFORM)
11
+ end
12
+
13
+ # Returns true if platform is darwin
14
+ def darwin?
15
+ /darwin/.match(RUBY_PLATFORM)
16
+ end
17
+
18
+ # Returns true if platform is known to be supported
19
+ def supported_platform?
20
+ linux? || darwin?
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProductionBreakpoints
4
+ # Validate that start line and end line point to code into the file
5
+ # At the momemt it will be valid if both start and end line points to valid ruby code
6
+ module StartEndLineValidator
7
+ module_function
8
+
9
+ def call(source_file, start_line, end_line)
10
+ source_lines = File.read(source_file).lines
11
+
12
+ !source_lines[start_line - 1].strip.empty? && !source_lines[end_line - 1].strip.empty?
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProductionBreakpoints
4
+ # The current version of this gem
5
+ VERSION = '0.0.6'
6
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ require 'ruby-static-tracing'
6
+
7
+ require 'ruby-production-breakpoints/version'
8
+ require 'ruby-production-breakpoints/platform'
9
+ require 'ruby-production-breakpoints/errors'
10
+ require 'ruby-production-breakpoints/breakpoints'
11
+ require 'ruby-production-breakpoints/configuration'
12
+ require 'ruby-production-breakpoints/parser'
13
+ require 'ruby-production-breakpoints/method_override'
14
+ require 'ruby-production-breakpoints/start_end_line_validator'
15
+
16
+ module ProductionBreakpoints
17
+ extend self
18
+
19
+ attr_accessor :installed_breakpoints
20
+
21
+ self.installed_breakpoints = {} # FIXME: namespace by provider, to allow multiple BP per file
22
+
23
+ def configure
24
+ @configuration = Configuration.new
25
+ yield @configuration
26
+ @configuration.finish!
27
+ end
28
+
29
+ def config
30
+ unless defined?(@configuration)
31
+ raise NotConfiguredError
32
+ end
33
+
34
+ @configuration
35
+ end
36
+
37
+ # For now add new types here
38
+ def install_breakpoint(type, source_file, start_line, end_line, trace_id: 1)
39
+ # Hack to check if there is a supported breakpoint of this type for now
40
+ case type.name
41
+ when 'ProductionBreakpoints::Breakpoints::Latency'
42
+ when 'ProductionBreakpoints::Breakpoints::Inspect'
43
+ when 'ProductionBreakpoints::Breakpoints::Locals'
44
+ # logger.debug("Creating latency tracer")
45
+ # now rewrite source to call this created breakpoint through parser
46
+ else
47
+ config.logger.error("Unsupported breakpoint type #{type}")
48
+ end
49
+
50
+ breakpoint = type.new(source_file, start_line, end_line, trace_id: trace_id)
51
+ installed_breakpoints[trace_id.to_sym] = breakpoint
52
+ breakpoint.install
53
+ breakpoint.load
54
+ end
55
+
56
+ def disable_breakpoint(trace_id)
57
+ breakpoint = installed_breakpoints.delete(trace_id)
58
+ breakpoint.unload
59
+ breakpoint.uninstall
60
+ end
61
+
62
+ def disable!
63
+ installed_breakpoints.each do |trace_id, _bp|
64
+ disable_breakpoint(trace_id)
65
+ end
66
+ end
67
+
68
+ def sync!
69
+ # FIXME: don't just install, also remove - want to 'resync'
70
+ # logger.debug("Resync initiated")
71
+ desired = config.configured_breakpoints['breakpoints']
72
+
73
+ desired_trace_ids = desired.map { |bp| bp['trace_id'] }
74
+ installed_trace_ids = installed_breakpoints.keys
75
+
76
+ to_install_tids = desired_trace_ids - installed_trace_ids
77
+ to_remove_tids = installed_trace_ids - desired_trace_ids
78
+ to_install = desired.select { |bp| to_install_tids.include?(bp['trace_id']) }
79
+ # logger.debug("Will install #{to_install.size} breakpoints")
80
+ # logger.debug("Will remove #{to_remove_tids.size} breakpoints")
81
+ to_install.each do |bp|
82
+ handler = breakpoint_constant_for_type(bp)
83
+ unless valid_start_line_end_line?(bp['source_file'], bp['start_line'], bp['end_line'])
84
+ msg = <<~MSG
85
+ Skipping #{handler} for #{bp['source_file']}. start line and end line do not point to any code on the file.
86
+ MSG
87
+ config.logger.warn(msg)
88
+ next
89
+ end
90
+ install_breakpoint(handler, bp['source_file'], bp['start_line'], bp['end_line'], trace_id: bp['trace_id'])
91
+ end
92
+
93
+ to_remove_tids.each do |trace_id|
94
+ disable_breakpoint(trace_id)
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def valid_start_line_end_line?(source_file, start_line, end_line)
101
+ StartEndLineValidator.call(source_file, start_line, end_line)
102
+ end
103
+
104
+ def breakpoint_constant_for_type(bp)
105
+ symstr = "ProductionBreakpoints::Breakpoints::#{bp['type'].capitalize}"
106
+ Object.const_get(symstr)
107
+ rescue NameError
108
+ config.logger.error("Could not find breakpoint handler for #{symstr}")
109
+ end
110
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-production-breakpoints
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dale Hamel
@@ -143,7 +143,21 @@ email: dale.hamel@srvthe.net
143
143
  executables: []
144
144
  extensions: []
145
145
  extra_rdoc_files: []
146
- files: []
146
+ files:
147
+ - lib/ruby-production-breakpoints.rb
148
+ - lib/ruby-production-breakpoints/breakpoints.rb
149
+ - lib/ruby-production-breakpoints/breakpoints/base.rb
150
+ - lib/ruby-production-breakpoints/breakpoints/inspect.rb
151
+ - lib/ruby-production-breakpoints/breakpoints/latency.rb
152
+ - lib/ruby-production-breakpoints/breakpoints/locals.rb
153
+ - lib/ruby-production-breakpoints/breakpoints/ustack.rb
154
+ - lib/ruby-production-breakpoints/configuration.rb
155
+ - lib/ruby-production-breakpoints/errors.rb
156
+ - lib/ruby-production-breakpoints/method_override.rb
157
+ - lib/ruby-production-breakpoints/parser.rb
158
+ - lib/ruby-production-breakpoints/platform.rb
159
+ - lib/ruby-production-breakpoints/start_end_line_validator.rb
160
+ - lib/ruby-production-breakpoints/version.rb
147
161
  homepage: https://github.com/dalehamel/ruby-production-breakpoints
148
162
  licenses:
149
163
  - MIT