Skip to content

Commit

Permalink
Merge pull request #1234 from DataDog/jirikuncar/rspec
Browse files Browse the repository at this point in the history
feature: rspec integration
  • Loading branch information
ericmustin authored Nov 13, 2020
2 parents d8d265a + 4bc4d9e commit 762f720
Show file tree
Hide file tree
Showing 13 changed files with 431 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ elsif Gem::Version.new('2.0.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'redis', '< 4.0'
gem 'rest-client'
gem 'resque', '< 2.0'
gem 'rspec', '>= 3.0.0'
gem 'sequel', '~> 4.0', '< 4.37'
gem 'sidekiq', '~> 3.5.4'
gem 'sinatra', '1.4.5'
Expand Down Expand Up @@ -219,6 +220,7 @@ elsif Gem::Version.new('2.1.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'rest-client'
gem 'resque', '< 2.0'
gem 'ruby-kafka', '>= 0.7.10'
gem 'rspec', '>= 3.0.0'
gem 'sequel', '~> 4.0', '< 4.37'
gem 'shoryuken'
gem 'sidekiq', '~> 3.5.4'
Expand Down Expand Up @@ -397,6 +399,7 @@ elsif Gem::Version.new('2.2.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'rest-client'
gem 'resque', '< 2.0'
gem 'ruby-kafka', '>= 0.7.10'
gem 'rspec', '>= 3.0.0'
gem 'sequel'
gem 'shoryuken'
gem 'sidekiq'
Expand Down Expand Up @@ -589,6 +592,7 @@ elsif Gem::Version.new('2.3.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'rest-client'
gem 'resque'
gem 'ruby-kafka', '>= 0.7.10'
gem 'rspec', '>= 3.0.0'
gem 'sequel'
gem 'shoryuken'
gem 'sidekiq'
Expand Down Expand Up @@ -691,6 +695,7 @@ elsif Gem::Version.new('2.4.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'rest-client'
gem 'resque'
gem 'ruby-kafka', '>= 0.7.10'
gem 'rspec', '>= 3.0.0'
gem 'sequel'
gem 'shoryuken'
gem 'sidekiq'
Expand Down Expand Up @@ -842,6 +847,7 @@ elsif Gem::Version.new('2.5.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'rest-client'
gem 'resque'
gem 'ruby-kafka', '>= 0.7.10'
gem 'rspec', '>= 3.0.0'
gem 'sequel'
gem 'shoryuken'
gem 'sidekiq'
Expand Down Expand Up @@ -981,6 +987,7 @@ elsif Gem::Version.new('2.6.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'rest-client'
gem 'resque'
gem 'ruby-kafka', '>= 0.7.10'
gem 'rspec', '>= 3.0.0'
gem 'sequel'
gem 'shoryuken'
gem 'sidekiq'
Expand Down Expand Up @@ -1123,6 +1130,7 @@ elsif Gem::Version.new('2.7.0') <= Gem::Version.new(RUBY_VERSION)
gem 'rest-client'
gem 'resque'
gem 'ruby-kafka', '>= 0.7.10'
gem 'rspec', '>= 3.0.0'
gem 'sequel'
gem 'shoryuken'
gem 'sidekiq'
Expand Down
9 changes: 9 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ namespace :spec do
:redis,
:resque,
:rest_client,
:rspec,
:sequel,
:shoryuken,
:sidekiq,
Expand Down Expand Up @@ -235,6 +236,7 @@ task :ci do
declare 'bundle exec appraisal contrib-old rake spec:redis'
declare 'bundle exec appraisal contrib-old rake spec:resque'
declare 'bundle exec appraisal contrib-old rake spec:rest_client'
declare 'bundle exec appraisal contrib-old rake spec:rspec'
declare 'bundle exec appraisal contrib-old rake spec:sequel'
declare 'bundle exec appraisal contrib-old rake spec:sidekiq'
declare 'bundle exec appraisal contrib-old rake spec:sinatra'
Expand Down Expand Up @@ -290,6 +292,7 @@ task :ci do
declare 'bundle exec appraisal contrib-old rake spec:redis'
declare 'bundle exec appraisal contrib-old rake spec:resque'
declare 'bundle exec appraisal contrib-old rake spec:rest_client'
declare 'bundle exec appraisal contrib-old rake spec:rspec'
declare 'bundle exec appraisal contrib-old rake spec:sequel'
declare 'bundle exec appraisal contrib-old rake spec:sidekiq'
declare 'bundle exec appraisal contrib-old rake spec:sinatra'
Expand Down Expand Up @@ -357,6 +360,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:redis'
declare 'bundle exec appraisal contrib rake spec:resque'
declare 'bundle exec appraisal contrib rake spec:rest_client'
declare 'bundle exec appraisal contrib rake spec:rspec'
declare 'bundle exec appraisal contrib rake spec:sequel'
declare 'bundle exec appraisal contrib rake spec:shoryuken'
declare 'bundle exec appraisal contrib rake spec:sidekiq'
Expand Down Expand Up @@ -430,6 +434,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:redis'
declare 'bundle exec appraisal contrib rake spec:resque'
declare 'bundle exec appraisal contrib rake spec:rest_client'
declare 'bundle exec appraisal contrib rake spec:rspec'
declare 'bundle exec appraisal contrib rake spec:sequel'
declare 'bundle exec appraisal contrib rake spec:shoryuken'
declare 'bundle exec appraisal contrib rake spec:sidekiq'
Expand Down Expand Up @@ -510,6 +515,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:redis'
declare 'bundle exec appraisal contrib rake spec:resque'
declare 'bundle exec appraisal contrib rake spec:rest_client'
declare 'bundle exec appraisal contrib rake spec:rspec'
declare 'bundle exec appraisal contrib rake spec:sequel'
declare 'bundle exec appraisal contrib rake spec:shoryuken'
declare 'bundle exec appraisal contrib rake spec:sidekiq'
Expand Down Expand Up @@ -578,6 +584,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:redis'
declare 'bundle exec appraisal contrib rake spec:resque'
declare 'bundle exec appraisal contrib rake spec:rest_client'
declare 'bundle exec appraisal contrib rake spec:rspec'
declare 'bundle exec appraisal contrib rake spec:sequel'
declare 'bundle exec appraisal contrib rake spec:shoryuken'
declare 'bundle exec appraisal contrib rake spec:sidekiq'
Expand Down Expand Up @@ -658,6 +665,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:redis'
declare 'bundle exec appraisal contrib rake spec:resque'
declare 'bundle exec appraisal contrib rake spec:rest_client'
declare 'bundle exec appraisal contrib rake spec:rspec'
declare 'bundle exec appraisal contrib rake spec:sequel'
declare 'bundle exec appraisal contrib rake spec:shoryuken'
declare 'bundle exec appraisal contrib rake spec:sidekiq'
Expand Down Expand Up @@ -738,6 +746,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:redis'
declare 'bundle exec appraisal contrib rake spec:resque'
declare 'bundle exec appraisal contrib rake spec:rest_client'
declare 'bundle exec appraisal contrib rake spec:rspec'
declare 'bundle exec appraisal contrib rake spec:sequel'
declare 'bundle exec appraisal contrib rake spec:shoryuken'
declare 'bundle exec appraisal contrib rake spec:sidekiq'
Expand Down
25 changes: 25 additions & 0 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,31 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| `distributed_tracing` | Enables [distributed tracing](#distributed-tracing) | `true` |
| `service_name` | Service name for `rest_client` instrumentation. | `'rest_client'` |

## RSpec

RSpec integration will trace all executions of example groups and examples when using `rspec` test framework.

To activate your integration, use the `Datadog.configure` method:

```ruby
require 'rspec'
require 'ddtrace'

# Configure default RSpec integration
Datadog.configure do |c|
c.use :rspec, options
end
```

Where `options` is an optional `Hash` that accepts the following parameters:

| Key | Description | Default |
| --- | ----------- | ------- |
| `analytics_enabled` | Enable analytics for spans produced by this integration. `true` for on, `nil` to defer to global setting, `false` for off. | `true` |
| `enabled` | Defines whether RSpec tests should be traced. Useful for temporarily disabling tracing. `true` or `false` | `true` |
| `service_name` | Service name used for `rspec` instrumentation. | `'rspec'` |
| `operation_name` | Operation name used for `rspec` instrumentation. Useful if you want rename automatic trace metrics e.g. `trace.#{operation_name}.errors`. | `'rspec.example'` |

### Sequel

The Sequel integration traces queries made to your database.
Expand Down
1 change: 1 addition & 0 deletions lib/ddtrace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ module Datadog
require 'ddtrace/contrib/redis/integration'
require 'ddtrace/contrib/resque/integration'
require 'ddtrace/contrib/rest_client/integration'
require 'ddtrace/contrib/rspec/integration'
require 'ddtrace/contrib/sequel/integration'
require 'ddtrace/contrib/shoryuken/integration'
require 'ddtrace/contrib/sidekiq/integration'
Expand Down
38 changes: 38 additions & 0 deletions lib/ddtrace/contrib/rspec/configuration/settings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'ddtrace/contrib/configuration/settings'
require 'ddtrace/contrib/rspec/ext'

module Datadog
module Contrib
module RSpec
module Configuration
# Custom settings for the RSpec integration
class Settings < Contrib::Configuration::Settings
option :enabled do |o|
o.default { env_to_bool(Ext::ENV_ENABLED, true) }
o.lazy
end

option :analytics_enabled do |o|
o.default { env_to_bool(Ext::ENV_ANALYTICS_ENABLED, true) }
o.lazy
end

option :analytics_sample_rate do |o|
o.default { env_to_float(Ext::ENV_ANALYTICS_SAMPLE_RATE, 1.0) }
o.lazy
end

option :service_name do |o|
o.default { Datadog.configuration.service || Ext::SERVICE_NAME }
o.lazy
end

option :operation_name do |o|
o.default { ENV.key?(Ext::ENV_OPERATION_NAME) ? ENV[Ext::ENV_OPERATION_NAME] : Ext::OPERATION_NAME }
o.lazy
end
end
end
end
end
end
61 changes: 61 additions & 0 deletions lib/ddtrace/contrib/rspec/example.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
module Datadog
module Contrib
module RSpec
# Instrument RSpec::Core::Example
module Example
def self.included(base)
base.send(:prepend, InstanceMethods)
end

# Instance methods for configuration
module InstanceMethods
def run(example_group_instance, reporter)
configuration = Datadog.configuration[:rspec]
return super unless configuration[:enabled]

test_name = "#{example_group.description}::#{description}"
trace_options = {
app: Ext::APP,
resource: test_name,
service: configuration[:service_name],
span_type: Datadog::Ext::AppTypes::TEST,
tags: example_group.instance_variable_get(:@tags).merge(Datadog.configuration.tags)
}

configuration[:tracer].trace(configuration[:operation_name], trace_options) do |span|
span.set_tag(Datadog::Ext::Test::TAG_FRAMEWORK, Ext::FRAMEWORK)
span.set_tag(Datadog::Ext::Test::TAG_NAME, test_name)
span.set_tag(Datadog::Ext::Test::TAG_SUITE, example_group.file_path)
span.set_tag(Datadog::Ext::Test::TAG_TYPE, Ext::TEST_TYPE)
span.set_tag(Datadog::Ext::Test::TAG_SPAN_KIND, Datadog::Ext::AppTypes::TEST)

# Set analytics sample rate
if Datadog::Contrib::Analytics.enabled?(configuration[:analytics_enabled])
Datadog::Contrib::Analytics.set_sample_rate(span, configuration[:analytics_sample_rate])
end

# Measure service stats
Contrib::Analytics.set_measured(span)

result = super

case execution_result.status
when :passed
span.set_tag(Datadog::Ext::Test::TAG_STATUS, Datadog::Ext::Test::Status::PASS)
when :failed
span.status = 1
span.set_tag(Datadog::Ext::Test::TAG_STATUS, Datadog::Ext::Test::Status::FAIL)
span.set_error(execution_result.exception)
else
if execution_result.example_skipped?
span.set_tag(Datadog::Ext::Test::TAG_STATUS, Datadog::Ext::Test::Status::SKIP)
end
end
result
end
end
end
end
end
end
end
61 changes: 61 additions & 0 deletions lib/ddtrace/contrib/rspec/example_group.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
module Datadog
module Contrib
module RSpec
# Instrument RSpec::Core::ExampleGroup
module ExampleGroup
def self.included(base)
base.singleton_class.send(:prepend, ClassMethods)
end

# Class methods for configuration
module ClassMethods
def run(reporter = ::RSpec::Core::NullReporter)
configuration = Datadog.configuration[:rspec]
return super unless configuration[:enabled]

trace_options = {
app: Ext::APP,
resource: description,
service: configuration[:service_name],
span_type: Datadog::Ext::AppTypes::TEST,
tags: tags.merge(Datadog.configuration.tags)
}

configuration[:tracer].trace(Ext::EXAMPLE_GROUP_OPERATION_NAME, trace_options) do |span|
span.set_tag(Datadog::Ext::Test::TAG_FRAMEWORK, Ext::FRAMEWORK)
span.set_tag(Datadog::Ext::Test::TAG_NAME, description)
span.set_tag(Datadog::Ext::Test::TAG_SUITE, file_path)
span.set_tag(Datadog::Ext::Test::TAG_TYPE, Ext::TEST_TYPE)
span.set_tag(Datadog::Ext::Test::TAG_SPAN_KIND, Datadog::Ext::AppTypes::TEST)

# Set analytics sample rate
if Datadog::Contrib::Analytics.enabled?(configuration[:analytics_enabled])
Datadog::Contrib::Analytics.set_sample_rate(span, configuration[:analytics_sample_rate])
end

# Measure service stats
Contrib::Analytics.set_measured(span)

result = super

if ::RSpec.world.wants_to_quit
span.status = 1
span.set_tag(Datadog::Ext::Test::TAG_STATUS, Datadog::Ext::Test::Status::FAIL)
else
span.set_tag(Datadog::Ext::Test::TAG_STATUS, Datadog::Ext::Test::Status::PASS)
end

result
end
end

private

def tags
@tags ||= Datadog::Ext::CI.tags(ENV)
end
end
end
end
end
end
19 changes: 19 additions & 0 deletions lib/ddtrace/contrib/rspec/ext.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Datadog
module Contrib
module RSpec
# RSpec integration constants
module Ext
APP = 'rspec'.freeze
ENV_ANALYTICS_ENABLED = 'DD_TRACE_RSPEC_ANALYTICS_ENABLED'.freeze
ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_RSPEC_ANALYTICS_SAMPLE_RATE'.freeze
ENV_ENABLED = 'DD_TRACE_RSPEC_ENABLED'.freeze
ENV_OPERATION_NAME = 'DD_TRACE_RSPEC_OPERATION_NAME'.freeze
FRAMEWORK = 'rspec'.freeze
OPERATION_NAME = 'rspec.example'.freeze
EXAMPLE_GROUP_OPERATION_NAME = 'rspec.example_group'.freeze
SERVICE_NAME = 'rspec'.freeze
TEST_TYPE = 'test'.freeze
end
end
end
end
Loading

0 comments on commit 762f720

Please sign in to comment.