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
9 changes: 9 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ commands:
command: "cd exporters/jaeger && bundle exec rake"
rake-test-appraisal:
steps:
- run:
name: Bundle + CI (Adapters - excon)
command: |
cd adapters/excon
gem uninstall -aIx bundler
gem install --no-document bundler -v '~> 2.0.2'
bundle install --jobs=3 --retry=3
bundle exec appraisal install
bundle exec appraisal rake test
- run:
name: Bundle + CI (Adapters - Faraday)
command: |
Expand Down
6 changes: 6 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ GEM_INFO = {
OpenTelemetry::Exporters::Jaeger::VERSION
}
},
"opentelemetry-adapters-excon" => {
version_getter: ->() {
require './lib/opentelemetry/adapters/excon/version.rb'
OpenTelemetry::Adapters::Excon::VERSION
}
},
"opentelemetry-adapters-faraday" => {
version_getter: ->() {
require './lib/opentelemetry/adapters/faraday/version.rb'
Expand Down
27 changes: 27 additions & 0 deletions adapters/excon/.rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
AllCops:
TargetRubyVersion: '2.4.0'

Bundler/OrderedGems:
Exclude:
- gemfiles/**/*
Lint/UnusedMethodArgument:
Enabled: false
Metrics/AbcSize:
Max: 18
Metrics/LineLength:
Enabled: false
Metrics/MethodLength:
Max: 20
Metrics/ParameterLists:
Enabled: false
Naming/FileName:
Exclude:
- "lib/opentelemetry-adapters-excon.rb"
Style/FrozenStringLiteralComment:
Exclude:
- gemfiles/**/*
Style/ModuleFunction:
Enabled: false
Style/StringLiterals:
Exclude:
- gemfiles/**/*
9 changes: 9 additions & 0 deletions adapters/excon/Appraisals
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

appraise 'excon-0.71' do
gem 'excon', '~> 0.71.0'
end

appraise 'excon-0.64' do
gem 'excon', '~> 0.64.0'
end
15 changes: 15 additions & 0 deletions adapters/excon/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

# Copyright 2020 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

source 'https://rubygems.org'

gemspec

gem 'opentelemetry-api', path: '../../api'

group :test do
gem 'opentelemetry-sdk', path: '../../sdk'
end
28 changes: 28 additions & 0 deletions adapters/excon/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

# Copyright 2020 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

require 'bundler/gem_tasks'
require 'rake/testtask'
require 'yard'
require 'rubocop/rake_task'

RuboCop::RakeTask.new

Rake::TestTask.new :test do |t|
t.libs << 'test'
t.libs << 'lib'
t.test_files = FileList['test/**/*_test.rb']
end

YARD::Rake::YardocTask.new do |t|
t.stats_options = ['--list-undoc']
end

if RUBY_ENGINE == 'truffleruby'
task default: %i[test]
else
task default: %i[test rubocop yard]
end
8 changes: 8 additions & 0 deletions adapters/excon/example/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

source 'https://rubygems.org'

gem 'excon'
gem 'opentelemetry-adapters-excon', path: '../../../adapters/excon'
gem 'opentelemetry-api', path: '../../../api'
gem 'opentelemetry-sdk', path: '../../../sdk'
12 changes: 12 additions & 0 deletions adapters/excon/example/excon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

require 'rubygems'
require 'bundler/setup'

Bundler.require

OpenTelemetry::SDK.configure do |c|
c.use 'OpenTelemetry::Adapters::Excon'
end

Excon.get('http://example.com')
12 changes: 12 additions & 0 deletions adapters/excon/gemfiles/excon_0.64.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "opentelemetry-api", path: "../../../api"
gem "excon", "~> 0.64.0"

group :test do
gem "opentelemetry-sdk", path: "../../../sdk"
end

gemspec path: "../"
12 changes: 12 additions & 0 deletions adapters/excon/gemfiles/excon_0.71.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "opentelemetry-api", path: "../../../api"
gem "excon", "~> 0.71.0"

group :test do
gem "opentelemetry-sdk", path: "../../../sdk"
end

gemspec path: "../"
7 changes: 7 additions & 0 deletions adapters/excon/lib/opentelemetry-adapters-excon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

# Copyright 2020 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

require_relative './opentelemetry/adapters'
16 changes: 16 additions & 0 deletions adapters/excon/lib/opentelemetry/adapters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

# Copyright 2020 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

module OpenTelemetry
# "Instrumentation adapters" are specified by
# https://github.com/open-telemetry/opentelemetry-specification/blob/57714f7547fe4dcb342ad0ad10a80d86118431c7/specification/overview.md#instrumentation-adapters
#
# Adapters should be able to handle the case when the library is not installed on a user's system.
module Adapters
end
end

require_relative './adapters/excon'
18 changes: 18 additions & 0 deletions adapters/excon/lib/opentelemetry/adapters/excon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

# Copyright 2020 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

require 'opentelemetry'

module OpenTelemetry
module Adapters
# Contains the OpenTelemetry adapter for the Excon gem
module Excon
end
end
end

require_relative './excon/adapter'
require_relative './excon/version'
35 changes: 35 additions & 0 deletions adapters/excon/lib/opentelemetry/adapters/excon/adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

# Copyright 2020 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

module OpenTelemetry
module Adapters
module Excon
# The Adapter class contains logic to detect and install the Excon
# instrumentation adapter
class Adapter < OpenTelemetry::Instrumentation::Adapter
install do |_config|
require_dependencies
add_middleware
end

present do
defined?(::Excon)
end

private

def require_dependencies
require_relative 'middlewares/tracer_middleware'
end

def add_middleware
::Excon.defaults[:middlewares] =
Middlewares::TracerMiddleware.around_default_stack
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# frozen_string_literal: true

# Copyright 2020 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

module OpenTelemetry
module Adapters
module Excon
module Middlewares
# Excon middleware for instrumentation
class TracerMiddleware < ::Excon::Middleware::Base
HTTP_METHODS_SYMBOL_TO_STRING = {
connect: 'CONNECT',
delete: 'DELETE',
get: 'GET',
head: 'HEAD',
options: 'OPTIONS',
patch: 'PATCH',
post: 'POST',
put: 'PUT',
trace: 'TRACE'
}.freeze

def request_call(datum) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
begin
unless datum.key?(:otel_span)
http_method = HTTP_METHODS_SYMBOL_TO_STRING[datum[:method]]

tracer.start_span(
"HTTP #{http_method}",
attributes: {
'component' => 'http',
'http.host' => datum[:host],
'http.method' => http_method,
'http.scheme' => datum[:scheme],
'http.target' => datum[:path]
},
kind: :client
).tap do |span|
datum[:otel_span] = span
tracer.with_span(span) do
OpenTelemetry.propagation.inject(datum[:headers])
end
end
end
rescue StandardError => e
OpenTelemetry.logger.debug(e.message)
end

@stack.request_call(datum)
end

def response_call(datum)
@stack.response_call(datum).tap do |d|
handle_response(d)
end
end

def error_call(datum)
handle_response(datum)
@stack.error_call(datum)
end

# Returns a copy of the default stack with the trace middleware injected
def self.around_default_stack
::Excon.defaults[:middlewares].dup.tap do |default_stack|
# If the default stack contains a version of the trace middleware already...
existing_trace_middleware = default_stack.find { |m| m <= TracerMiddleware }
default_stack.delete(existing_trace_middleware) if existing_trace_middleware

# Inject after the ResponseParser middleware
response_middleware_index = default_stack.index(::Excon::Middleware::ResponseParser).to_i
default_stack.insert(response_middleware_index + 1, self)
end
end

private

def handle_response(datum) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
if datum.key?(:otel_span)
datum[:otel_span].tap do |span|
return span if span.end_timestamp

if datum.key?(:response)
response = datum[:response]
span.set_attribute('http.status_code', response[:status])
span.set_attribute('http.status_text', response[:reason_phrase])
span.status = OpenTelemetry::Trace::Status.http_to_status(
response[:status]
)
end

if datum.key?(:error)
span.status = OpenTelemetry::Trace::Status.new(
OpenTelemetry::Trace::Status::UNKNOWN_ERROR,
description: "Request has failed: #{datum[:error]}"
)
end

span.finish
datum.delete(:otel_span)
end
end
rescue StandardError => e
OpenTelemetry.logger.debug(e.message)
end

def tracer
Excon::Adapter.instance.tracer
end
end
end
end
end
end
13 changes: 13 additions & 0 deletions adapters/excon/lib/opentelemetry/adapters/excon/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

# Copyright 2020 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

module OpenTelemetry
module Adapters
module Excon
VERSION = '0.0.0'
end
end
end
Loading