Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Steepfile
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ target :datadog do
# References `RubyVM::YJIT`, which does not have type information.
ignore 'lib/datadog/core/environment/yjit.rb'

library 'bundler'
library 'pathname'
library 'cgi'
library 'logger', 'monitor'
Expand Down
21 changes: 15 additions & 6 deletions lib/datadog/profiling/collectors/code_provenance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ def initialize(
@libraries_by_path = {}
@seen_files = Set.new
@seen_libraries = Set.new
@executable_paths = [Gem.bindir, (Bundler.bin_path.to_s if defined?(Bundler))].uniq.compact.freeze

record_library(
Library.new(
kind: "standard library",
name: "stdlib",
version: RUBY_VERSION,
path: standard_library_path,
extra_path: ruby_native_filename,
extra_paths: [ruby_native_filename],
)
)
end
Expand All @@ -51,7 +52,8 @@ def generate_json
:libraries_by_name,
:libraries_by_path,
:seen_files,
:seen_libraries
:seen_libraries,
:executable_paths

def record_library(library)
libraries_by_name[library.name] = library
Expand Down Expand Up @@ -79,13 +81,20 @@ def record_loaded_specs(loaded_specs)
loaded_specs.each do |spec|
next if libraries_by_name.key?(spec.name)

extra_paths = [(spec.extension_dir if spec.extensions.any?)]
spec.executables&.each do |executable|
executable_paths.each do |path|
extra_paths << File.join(path, executable)
end
end

record_library(
Library.new(
kind: "library",
name: spec.name,
version: spec.version,
path: spec.gem_dir,
extra_path: (spec.extension_dir if spec.extensions.any?),
extra_paths: extra_paths,
)
)
recorded_library = true
Expand Down Expand Up @@ -118,12 +127,12 @@ def record_loaded_files(loaded_files)
class Library
attr_reader :kind, :name, :version

def initialize(kind:, name:, version:, path:, extra_path: nil)
extra_path = nil if extra_path&.empty?
def initialize(kind:, name:, version:, path:, extra_paths:)
extra_paths = Array(extra_paths).compact.reject(&:empty?).map { |p| p.dup.freeze }
@kind = kind.freeze
@name = name.dup.freeze
@version = version.to_s.dup.freeze
@paths = [path.dup.freeze, extra_path.dup.freeze].compact.freeze
@paths = [path.dup.freeze, *extra_paths].freeze
freeze
end

Expand Down
3 changes: 2 additions & 1 deletion sig/datadog/profiling/collectors/code_provenance.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module Datadog
attr_reader libraries_by_path: Hash[String, Library]
attr_reader seen_files: Set[String]
attr_reader seen_libraries: Set[Library]
attr_reader executable_paths: Array[String]

def record_library: (Library) -> void
def sort_libraries_by_longest_path_first: () -> void
Expand All @@ -24,7 +25,7 @@ module Datadog
@version: String
@paths: Array[String]

def initialize: (kind: String, name: String, version: String, path: String, ?extra_path: String?) -> void
def initialize: (kind: String, name: String, version: String, path: String, extra_paths: Array[String?]) -> void

def kind: -> String
def name: -> String
Expand Down
30 changes: 27 additions & 3 deletions spec/datadog/profiling/collectors/code_provenance_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,16 @@
kind: "library",
name: "datadog",
version: Datadog::VERSION::STRING,
paths: contain_exactly(start_with("/"), include("extensions").and(include(RUBY_PLATFORM))),
paths: contain_exactly(
start_with("/"),
include("extensions").and(include(RUBY_PLATFORM)),
"#{Gem.bindir}/ddprofrb",
"#{Bundler.bin_path}/ddprofrb",
),
},
{
kind: "library",
name: "rspec-core",
name: "rspec",
version: start_with("3."), # This will one day need to be bumped for RSpec 4
paths: contain_exactly(start_with("/")),
},
Expand All @@ -59,6 +64,20 @@
)
end

it "includes the executables for gems with executables" do
refresh

expect(generate_result.find { |it| it[:name] == "rspec-core" }.fetch(:paths)).to contain_exactly(
Gem.loaded_specs.fetch("rspec-core").gem_dir,
"#{Gem.bindir}/rspec",
"#{Bundler.bin_path}/rspec",
)

# Sanity checks
expect(Gem.bindir).to start_with("/")
expect(Bundler.bin_path.to_s).to start_with("/")
end

it "records the correct path for datadog" do
refresh

Expand All @@ -78,13 +97,15 @@
version: "not_loaded_version",
gem_dir: "/not_loaded/",
extensions: [],
executables: [],
),
instance_double(
Gem::Specification,
name: "is_loaded",
version: "is_loaded_version",
gem_dir: "/is_loaded/",
extensions: [],
executables: [],
)
],
)
Expand Down Expand Up @@ -131,13 +152,15 @@
version: "1.2.3",
gem_dir: "/dd-trace-rb",
extensions: [],
executables: [],
),
instance_double(
Gem::Specification,
name: "byebug",
version: "4.5.6",
gem_dir: "/dd-trace-rb/vendor/bundle/ruby/2.7.0/gems/byebug-11.1.3",
extensions: [],
executables: [],
)
],
)
Expand Down Expand Up @@ -288,6 +311,7 @@
kind: "library",
version: "1.2.3",
path: "/example/path/to/datadog/gem",
extra_paths: ["/example/path/to/datadog/extensions"],
)

serialized_without_to_json = YAML.dump(instance)
Expand All @@ -298,7 +322,7 @@
"name" => "datadog",
"kind" => "library",
"version" => "1.2.3",
"paths" => ["/example/path/to/datadog/gem"],
"paths" => ["/example/path/to/datadog/gem", "/example/path/to/datadog/extensions"],
)
end
end
Expand Down
3 changes: 3 additions & 0 deletions vendor/rbs/bundler/0/bundler.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module Bundler
def self.bin_path: () -> Pathname
end
1 change: 1 addition & 0 deletions vendor/rbs/gem/0/gem.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ class Gem::BasicSpecification
def gem_dir: () -> String
def extension_dir: () -> String
def extensions: () -> Array[String]
def executables: () -> Array[String]?
end