Module: Flare::SourceLocation
- Defined in:
- lib/flare/source_location.rb
Overview
Utility for finding the source location (file, line, method) of app code that triggered a database query or other instrumented operation.
Constant Summary collapse
- MAX_TRACE_LINES =
How many app code lines to capture for the backtrace
8- IGNORE_PATTERNS =
Patterns to filter out from backtraces (gems, framework code)
[ /\/gems\//, /\/ruby\//, /\/rubygems\//, /lib\/active_record/, /lib\/active_support/, /lib\/action_/, /opentelemetry/, /flare/, /<internal:/, /\/bin\//, ].freeze
Class Method Summary collapse
-
.add_to_attributes(attrs) ⇒ Object
Add source location attributes to a hash (for span attributes).
- .app_code?(line) ⇒ Boolean
- .clean_backtrace_line(line) ⇒ Object
- .clean_path(path) ⇒ Object
-
.find ⇒ Object
Find the first app source location from the current backtrace Returns a hash with :filepath, :lineno, :function or nil.
-
.find_trace ⇒ Object
Find multiple app source locations from the current backtrace Returns an array of cleaned backtrace lines (up to MAX_TRACE_LINES).
- .parse_backtrace_line(line) ⇒ Object
Class Method Details
.add_to_attributes(attrs) ⇒ Object
Add source location attributes to a hash (for span attributes)
54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/flare/source_location.rb', line 54 def add_to_attributes(attrs) location = find return attrs unless location attrs["code.filepath"] = location[:filepath] attrs["code.lineno"] = location[:lineno] attrs["code.function"] = location[:function] if location[:function] # Add full trace as a single string attribute trace = find_trace attrs["code.stacktrace"] = trace.join("\n") if trace.any? attrs end |
.app_code?(line) ⇒ Boolean
69 70 71 72 73 74 |
# File 'lib/flare/source_location.rb', line 69 def app_code?(line) # Must contain /app/ (Rails convention) and not match ignore patterns return false unless line.include?("/app/") IGNORE_PATTERNS.none? { |pattern| line.match?(pattern) } end |
.clean_backtrace_line(line) ⇒ Object
93 94 95 96 97 98 99 100 101 102 |
# File 'lib/flare/source_location.rb', line 93 def clean_backtrace_line(line) # Parse and reformat: "app/models/user.rb:42:in `find_by_email'" if line =~ /\A(.+):(\d+):in [`'](.+)'\z/ "#{clean_path($1)}:#{$2} in `#{$3}'" elsif line =~ /\A(.+):(\d+)\z/ "#{clean_path($1)}:#{$2}" else clean_path(line) end end |
.clean_path(path) ⇒ Object
104 105 106 107 108 109 110 111 |
# File 'lib/flare/source_location.rb', line 104 def clean_path(path) # Remove Rails.root prefix if present if defined?(Rails) && Rails.respond_to?(:root) && Rails.root path.sub(/\A#{Regexp.escape(Rails.root.to_s)}\//, "") else path end end |
.find ⇒ Object
Find the first app source location from the current backtrace Returns a hash with :filepath, :lineno, :function or nil
28 29 30 31 32 33 34 35 36 37 |
# File 'lib/flare/source_location.rb', line 28 def find backtrace = caller(2, 50) return nil unless backtrace # Find the first line that's app code (not gems/framework) app_line = backtrace.find { |line| app_code?(line) } return nil unless app_line parse_backtrace_line(app_line) end |
.find_trace ⇒ Object
Find multiple app source locations from the current backtrace Returns an array of cleaned backtrace lines (up to MAX_TRACE_LINES)
41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/flare/source_location.rb', line 41 def find_trace backtrace = caller(2, 100) return [] unless backtrace # Filter to only app code lines app_lines = backtrace.select { |line| app_code?(line) } return [] if app_lines.empty? # Clean and format each line, limit to MAX_TRACE_LINES app_lines.first(MAX_TRACE_LINES).map { |line| clean_backtrace_line(line) } end |
.parse_backtrace_line(line) ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/flare/source_location.rb', line 76 def parse_backtrace_line(line) # Parse: /path/to/file.rb:123:in `method_name' if line =~ /\A(.+):(\d+):in [`'](.+)'\z/ { filepath: clean_path($1), lineno: $2.to_i, function: $3 } elsif line =~ /\A(.+):(\d+)\z/ { filepath: clean_path($1), lineno: $2.to_i, function: nil } end end |