Skip to content

Commit

Permalink
Merge pull request #2368 from DataDog/add-roda-rebase
Browse files Browse the repository at this point in the history
  • Loading branch information
marcotc authored Mar 15, 2023
2 parents 79a2c7e + 3682891 commit 4e51eae
Show file tree
Hide file tree
Showing 12 changed files with 785 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ namespace :spec do
:rake,
:redis,
:resque,
:roda,
:rest_client,
:semantic_logger,
:sequel,
Expand Down Expand Up @@ -314,6 +315,7 @@ task :ci do
declare '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ jruby' => 'bundle exec appraisal contrib rake spec:rake'
declare '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ jruby' => 'bundle exec appraisal contrib rake spec:resque'
declare '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ jruby' => 'bundle exec appraisal contrib rake spec:rest_client'
declare '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ jruby' => 'bundle exec appraisal contrib rake spec:roda'
declare '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ jruby' => 'bundle exec appraisal contrib rake spec:rspec'
declare '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ jruby' => 'bundle exec appraisal contrib rake spec:semantic_logger'
declare '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ jruby' => 'bundle exec appraisal contrib rake spec:sequel'
Expand Down
35 changes: 35 additions & 0 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ To contribute, check out the [contribution guidelines][contribution docs] and [d
- [Redis](#redis)
- [Resque](#resque)
- [Rest Client](#rest-client)
- [Roda](#roda)
- [RSpec](#rspec)
- [Sequel](#sequel)
- [Shoryuken](#shoryuken)
Expand Down Expand Up @@ -515,6 +516,7 @@ For a list of available integrations, and their configuration options, please re
| Redis | `redis` | `>= 3.2` | `>= 3.2` | *[Link](#redis)* | *[Link](https://github.com/redis/redis-rb)* |
| Resque | `resque` | `>= 1.0` | `>= 1.0` | *[Link](#resque)* | *[Link](https://github.com/resque/resque)* |
| Rest Client | `rest-client` | `>= 1.8` | `>= 1.8` | *[Link](#rest-client)* | *[Link](https://github.com/rest-client/rest-client)* |
| Roda | `roda` | `>= 2.1, <4` | `>= 2.1, <4` | *[Link](#roda)* | *[Link](https://github.com/jeremyevans/roda)* |
| Sequel | `sequel` | `>= 3.41` | `>= 3.41` | *[Link](#sequel)* | *[Link](https://github.com/jeremyevans/sequel)* |
| Shoryuken | `shoryuken` | `>= 3.2` | `>= 3.2` | *[Link](#shoryuken)* | *[Link](https://github.com/phstc/shoryuken)* |
| Sidekiq | `sidekiq` | `>= 3.5.4` | `>= 3.5.4` | *[Link](#sidekiq)* | *[Link](https://github.com/mperham/sidekiq)* |
Expand Down Expand Up @@ -1873,6 +1875,39 @@ end
| `service_name` | Service name for `rest_client` instrumentation. | `'rest_client'` |
| `split_by_domain` | Uses the request domain as the service name when set to `true`. | `false` |

### Roda

The Roda integration traces requests.

The **Roda** integration can be enabled through `Datadog.configure`. It is recommended to use this integration with **Rack** through `use Datadog::Tracing::Contrib::Rack::TraceMiddleware` for distributed tracing.

```ruby
require "roda"
require "ddtrace"
class SampleApp < Roda
use Datadog::Tracing::Contrib::Rack::TraceMiddleware
Datadog.configure do |c|
c.tracing.instrument :roda, **options
end
route do |r|
r.root do
r.get do
'Hello World!'
end
end
end
end
```

`options` are the following keyword arguments:

| Key | Description | Default |
| --- | ----------- | ------- |
| `service_name` | Service name for `roda` instrumentation. | `'nil'` |

### RSpec

RSpec integration will trace all executions of example groups and examples when using `rspec` test framework.
Expand Down
1 change: 1 addition & 0 deletions lib/datadog/tracing/contrib.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ module Contrib
require_relative 'contrib/redis/integration'
require_relative 'contrib/resque/integration'
require_relative 'contrib/rest_client/integration'
require_relative 'contrib/roda/integration'
require_relative 'contrib/semantic_logger/integration'
require_relative 'contrib/sequel/integration'
require_relative 'contrib/shoryuken/integration'
Expand Down
34 changes: 34 additions & 0 deletions lib/datadog/tracing/contrib/roda/configuration/settings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

require_relative '../../configuration/settings'
require_relative '../ext'

module Datadog
module Tracing
module Contrib
module Roda
module Configuration
# Custom settings for the Roda 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, false) }
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
end
end
end
end
end
end
18 changes: 18 additions & 0 deletions lib/datadog/tracing/contrib/roda/ext.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module Datadog
module Tracing
module Contrib
module Roda
# Roda integration constants
module Ext
APP = 'roda'
ENV_ENABLED = 'DD_TRACE_RODA_ENABLED'
ENV_ANALYTICS_ENABLED = 'DD_RODA_ANALYTICS_ENABLED'
ENV_ANALYTICS_SAMPLE_RATE = 'DD_RODA_ANALYTICS_SAMPLE_RATE'
SPAN_REQUEST = 'roda.request'
end
end
end
end
end
76 changes: 76 additions & 0 deletions lib/datadog/tracing/contrib/roda/instrumentation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# frozen_string_literal: true

require_relative '../../metadata/ext'
require_relative 'ext'
require_relative '../analytics'

module Datadog
module Tracing
module Contrib
module Roda
# Instrumentation for Roda
module Instrumentation
def _roda_handle_main_route
instrument(Ext::SPAN_REQUEST) { super }
end

def call
instrument(Ext::SPAN_REQUEST) { super }
end

private

def instrument(span_name, &block)
Tracing.trace(span_name) do |span|
begin
request_method = request.request_method.to_s.upcase

span.service = configuration[:service_name] if configuration[:service_name]

span.span_type = Tracing::Metadata::Ext::HTTP::TYPE_INBOUND

# Using the http method as a resource, since the URL/path can trigger
# a possibly infinite number of resources.
span.resource = request_method

span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL, request.path)
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, request_method)

# Add analytics tag to the span
if Contrib::Analytics.enabled?(configuration[:analytics_enabled])
Contrib::Analytics.set_sample_rate(span, configuration[:analytics_sample_rate])
end

# Measure service stats
Contrib::Analytics.set_measured(span)
ensure
begin
response = yield
rescue StandardError
# The status code is unknown to Roda and decided by the upstream web runner.
# In this case, spans default to status code 500 rather than a blank status code.
default_error_status = '500'
span.resource = "#{request_method} #{default_error_status}"
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, default_error_status)
raise
end
end

status_code = response[0]

# Adds status code to the resource name once the resource comes back
span.resource = "#{request_method} #{status_code}"
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, status_code)
span.status = 1 if status_code.to_s.start_with?('5')
response
end
end

def configuration
Datadog.configuration.tracing[:roda]
end
end
end
end
end
end
45 changes: 45 additions & 0 deletions lib/datadog/tracing/contrib/roda/integration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

# typed: false

require_relative '../integration'
require_relative 'configuration/settings'
require_relative 'patcher'

module Datadog
module Tracing
module Contrib
module Roda
# Description of Roda integration
class Integration
include Contrib::Integration

MINIMUM_VERSION = Gem::Version.new('2.0.0')
MAXIMUM_VERSION = Gem::Version.new('4.0.0')

register_as :roda

def self.version
Gem.loaded_specs['roda'] && Gem.loaded_specs['roda'].version
end

def self.loaded?
!defined?(::Roda).nil?
end

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

def new_configuration
Configuration::Settings.new
end

def patcher
Patcher
end
end
end
end
end
end
30 changes: 30 additions & 0 deletions lib/datadog/tracing/contrib/roda/patcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

# typed: ignore

require_relative 'patcher'
require_relative 'ext'
require_relative 'instrumentation'

module Datadog
module Tracing
module Contrib
module Roda
# Patcher enables patching of 'roda'
module Patcher
include Contrib::Patcher

module_function

def target_version
Integration.version
end

def patch
::Roda.prepend(Instrumentation)
end
end
end
end
end
end
61 changes: 61 additions & 0 deletions spec/datadog/tracing/contrib/roda/instrumentation_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# typed: false

require_relative './shared_examples'
require 'roda'
require 'ddtrace'
require 'datadog/tracing/contrib/roda/instrumentation'
require 'datadog/tracing/contrib/roda/ext'
require 'datadog/tracing/contrib/support/spec_helper'
require 'datadog/tracing/contrib/support/tracer_helpers'

RSpec.describe Datadog::Tracing::Contrib::Roda::Instrumentation do
describe 'when implemented in Roda' do
let(:configuration_options) { {} }

before do
Datadog.configure do |c|
c.tracing.instrument :roda, configuration_options
end
end

after do
Datadog.registry[:roda].reset_configuration!
end

describe 'When using automatic instrumentation' do
let(:env) { { REQUEST_METHOD: 'GET' } }
context 'configuring roda' do
context 'with default settings' do
it 'enables the tracer' do
expect(Datadog.configuration.tracing.enabled).to eq(true)
end

it 'does not have a default service name (left up to global configuration)' do
expect(Datadog.configuration.tracing[:roda].service_name).to eq(nil)
expect(Datadog.configuration.service).to eq('rspec')
end

context 'with a custom service name' do
let(:custom_service_name) { 'custom_service_name' }
let(:configuration_options) { { service_name: custom_service_name } }

it 'sets a custom service name' do
expect(Datadog.configuration.service).to eq('rspec')
expect(Datadog.configuration.tracing[:roda].service_name).to eq(custom_service_name)
end
end
end
end
end

describe 'when application calls on the instrumented method' do
context 'using #call' do
it_behaves_like 'shared examples for roda', :call
end

context 'using #_roda_handle_main_route' do
it_behaves_like 'shared examples for roda', :_roda_handle_main_route
end
end
end
end
Loading

0 comments on commit 4e51eae

Please sign in to comment.