1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
|
# frozen_string_literal: true
require "json"
require "rbconfig"
module Sentry
module Vernier
class Output
include Profiler::Helpers
attr_reader :profile
def initialize(profile, project_root:, in_app_pattern:, app_dirs_pattern:)
@profile = profile
@project_root = project_root
@in_app_pattern = in_app_pattern
@app_dirs_pattern = app_dirs_pattern
end
def to_h
@to_h ||= {
frames: frames,
stacks: stacks,
samples: samples,
thread_metadata: thread_metadata
}
end
private
def thread_metadata
profile.threads.map { |thread_id, thread_info|
[thread_id, { name: thread_info[:name] }]
}.to_h
end
def samples
profile.threads.flat_map { |thread_id, thread_info|
started_at = thread_info[:started_at]
samples, timestamps = thread_info.values_at(:samples, :timestamps)
samples.zip(timestamps).map { |stack_id, timestamp|
elapsed_since_start_ns = timestamp - started_at
next if elapsed_since_start_ns < 0
{
thread_id: thread_id.to_s,
stack_id: stack_id,
elapsed_since_start_ns: elapsed_since_start_ns.to_s
}
}.compact
}
end
def frames
funcs = stack_table_hash[:frame_table].fetch(:func)
lines = stack_table_hash[:func_table].fetch(:first_line)
funcs.map do |idx|
function, mod = split_module(stack_table_hash[:func_table][:name][idx])
abs_path = stack_table_hash[:func_table][:filename][idx]
in_app = in_app?(abs_path)
filename = compute_filename(abs_path, in_app)
{
function: function,
module: mod,
filename: filename,
abs_path: abs_path,
lineno: (lineno = lines[idx]) > 0 ? lineno : nil,
in_app: in_app
}.compact
end
end
def stacks
profile._stack_table.stack_count.times.map do |stack_id|
profile.stack(stack_id).frames.map(&:idx)
end
end
def stack_table_hash
@stack_table_hash ||= profile._stack_table.to_h
end
end
end
end
|