Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: rspec integration #1234

Merged
merged 6 commits into from
Nov 13, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
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 @@ -1499,6 +1499,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.it'` |
jirikuncar marked this conversation as resolved.
Show resolved Hide resolved

### 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
60 changes: 60 additions & 0 deletions lib/ddtrace/contrib/rspec/example.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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]

trace_options = {
app: Ext::APP,
resource: "#{example_group}::#{description}",
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, description)
span.set_tag(Datadog::Ext::Test::TAG_SUITE, example_group)
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
41 changes: 41 additions & 0 deletions lib/ddtrace/contrib/rspec/integration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'ddtrace/contrib/integration'
require 'ddtrace/contrib/rspec/configuration/settings'
require 'ddtrace/contrib/rspec/patcher'
require 'ddtrace/contrib/integration'

module Datadog
module Contrib
module RSpec
# Description of RSpec integration
class Integration
include Contrib::Integration

MINIMUM_VERSION = Gem::Version.new('3.0.0')

register_as :rspec, auto_patch: true

def self.version
Gem.loaded_specs['rspec'] \
&& Gem.loaded_specs['rspec'].version
end

def self.loaded?
!defined?(::RSpec).nil? && !defined?(::RSpec::Core).nil? && \
!defined?(::RSpec::Core::Example).nil? && !defined?(::RSpec::Core::ExampleGroup).nil?
end

def self.compatible?
super && version >= MINIMUM_VERSION
end

def default_configuration
Configuration::Settings.new
end

def patcher
Patcher
end
end
end
end
end
Loading