TracePoint를 사용한 Ruby 호출 경로 분석

6909 단어 ruby
최근 진단 분석 연습 중에 변경되는 단일 옵션을 기반으로 수행되는 추가 "작업"이 있는지 확인해야 했습니다. Ruby는 개발자를 위한 수많은 생산성 도구를 제공하므로 일대다 작업에 대한 전체 호출 스택을 쉽게 생성하는 메커니즘이 존재한다는 것은 놀라운 일이 아닙니다.

아래 코드는 MongoDB Ruby DriverMongoid ODM $sample 명령줄에서 전달된 Read Preference이 있는 단일 문서에 사용하고 있습니다. 컬렉션은 존재하지 않을 가능성이 높지만 이 분석의 목표는 단순히 읽기 기본 설정이 어떤 차이를 드러내는지 확인하는 것이었습니다.

분석을 위해 수행되는 "작업"의 양에 차이가 있을 수 있는 "어디"를 확인하기 위해 두 개의 호출 스택diff을 생성하려고 했습니다. 이를 위해 첫 번째 단계는 TracePoint을 통해 계측을 도입하는 것이었습니다.

# test.rb
# ruby test.rb [primary|secondary]
require 'bundler/inline'
gemfile do
  source 'https://rubygems.org'

  gem 'mongoid', '7.0.4'
  gem 'mongo', '2.11.1'
end

Mongoid.configure do |config|
  config.clients.default = { uri: "mongodb+srv://..." }
end

class Sample
  include Mongoid::Document
end

def with_tracepoint
  trace = []
  tp = TracePoint.new(:call) do |x|
    trace << "#{x.defined_class}##{x.method_id.to_s} @ #{x.path}"
  end
  tp.enable
  yield
  return trace
ensure
  tp.disable unless tp.nil?
end

# first argument to symbol
read_pref = ARGV[0].nil? ? :primary : ARGV[0].to_sym
# run first command to establish a connection
Sample.collection.aggregate([{ :'$sample' => { size: 1 } }], read: { mode: read_pref }).first
trace = with_tracepoint do
  Sample.collection.aggregate([{ :'$sample' => { size: 1 } }], read: { mode: read_pref }).first
end

puts trace


위의 코드는 블록 내에서 실행되는 모든 Ruby 메서드 호출을 추적하고 이를 배열로 푸시합니다. 다른 옵션으로 위의 스크립트를 두 번 실행하고 결과를 diff 도구(예: icdiff )에 공급하여 호출 스택이 어떻게 다른지 시각적으로 표시할 수 있습니다.

icdiff -N <(ruby test.rb primary) <(ruby test.rb secondary) | less




(새 탭에서 스크린샷을 열면 더 잘 보입니다.)

위 스크립트의 with_tracepoint 헬퍼 메서드는 :call 에 대해서만 필터링하지만 특정 요구 사항에 따라 필터링하도록 쉽게 수정할 수 있습니다(전체 목록은 TracePoint Events 참조).

이 접근 방식이 특정 문제를 해결하거나 흥미로운 결함을 식별하는 데 도움이 되었는지 알려주십시오.

행복한 코딩!

좋은 웹페이지 즐겨찾기