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

Add faraday instrumentation adapter #67 #148

Merged
merged 35 commits into from
Jan 9, 2020
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
079d98d
Add API OpenTelemetry::Adapter
Nov 9, 2019
5ac7d4e
Add faraday instrumentation adapter Gemfile/gemspec
duonoid Nov 8, 2019
3f7f6b0
Add faraday instrumentation adapter
duonoid Nov 11, 2019
ed31c85
Add faraday example with docker-compose service
duonoid Nov 8, 2019
22ccf4f
Avoid hard-dependency on faraday
duonoid Nov 12, 2019
7562579
Fix undefined method `version' for nil:NilClass
duonoid Nov 13, 2019
6987351
Doc: reminder to handle common use case
duonoid Nov 12, 2019
92ba1bc
Add explicit 'require' statements in faraday/adapter
duonoid Nov 13, 2019
60d41d6
Use in_span(attributes:) instead of set_attribute
duonoid Nov 13, 2019
33f28c0
Change SDK::Trace::TracerFactory to subclass API's TracerFactory
duonoid Nov 11, 2019
937cf6c
Add context propagation
duonoid Nov 13, 2019
d42721b
Fix occasional test failure in sdk batch_span_processor_test
duonoid Nov 13, 2019
0e0d69f
Merge remote-tracking branch 'upstream/master' into dd/wip--faraday-i…
duonoid Nov 14, 2019
814e330
Don't extract context, just inject
duonoid Nov 14, 2019
4ee20b1
Load tracer_version lazily
duonoid Nov 14, 2019
915b052
Allow auto-installer to inject a tracer
duonoid Nov 14, 2019
89e6453
Merge remote-tracking branch 'upstream/master' into faraday-instrumen…
duonoid Nov 18, 2019
89ba2cb
Fix circular loading issue
duonoid Nov 20, 2019
a45dac2
Avoid requiring changes to API (OpenTelemetry::Adapter)
duonoid Nov 23, 2019
a558f71
sig-feedback: remove name and version from config
Dec 4, 2019
00ad878
sig-feedback: Use the http text format for propagation
Dec 4, 2019
1658d2e
Tests: Change Gemfile, gemspec, add Rakefile
duonoid Nov 20, 2019
21c8ada
Add test_helper and first test
duonoid Nov 20, 2019
eb243a9
Add appraisals for running tests against multiple versions
duonoid Nov 20, 2019
cfcdf5f
Add Circle CI config
duonoid Nov 21, 2019
dd680bb
Add TracerMiddleware test
duonoid Nov 26, 2019
5808423
Add Adapter test
duonoid Nov 26, 2019
29346a0
Add/refine tests
duonoid Dec 12, 2019
bc9e879
Allow for easier overriding of TracerMiddleware for per-connection rules
duonoid Dec 19, 2019
73f6086
Fix failing circleci builds
duonoid Dec 20, 2019
fd66e7d
Fix failing circleci - jruby
duonoid Dec 30, 2019
4098dd4
Appraisal: add faraday-1.0.x
duonoid Jan 6, 2020
537b4c1
Merge branch 'master' into faraday-instrumentation--67
mwear Jan 9, 2020
36cfd8a
circleci: Remove appraisal support, use latest bundler
duonoid Jan 9, 2020
dc05f82
circleci: Workaround failing appraisal+bundler(2.1.x)+ruby-2.7 issue
duonoid Jan 9, 2020
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
11 changes: 11 additions & 0 deletions adapters/faraday/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

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

source 'https://rubygems.org'

gemspec

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

source 'https://rubygems.org'

gem 'faraday'
gem 'opentelemetry-api', path: '../../../api'
gem 'opentelemetry-sdk', path: '../../../sdk'
21 changes: 21 additions & 0 deletions adapters/faraday/example/faraday.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require 'rubygems'
require 'bundler/setup'

require 'faraday'
require 'opentelemetry/sdk'
require_relative '../lib/opentelemetry/adapters/faraday'

# Set preferred tracer implementation:
SDK = OpenTelemetry::SDK

factory = OpenTelemetry.tracer_factory = SDK::Trace::TracerFactory.new
factory.add_span_processor(
SDK::Trace::Export::SimpleSpanProcessor.new(
SDK::Trace::Export::ConsoleSpanExporter.new
)
)

OpenTelemetry::Adapters::Faraday.install(name: 'faraday-example', version: '1.0')

conn = Faraday.new('http://example.com')
conn.get '/'
14 changes: 14 additions & 0 deletions adapters/faraday/lib/opentelemetry/adapters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

# Copyright 2019 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
21 changes: 21 additions & 0 deletions adapters/faraday/lib/opentelemetry/adapters/faraday.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

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

module OpenTelemetry
module Adapters
module Faraday
module_function

TRACER_NAME = 'faraday'
TRACER_VERSION = Gem.loaded_specs[TRACER_NAME]&.version.to_s

def install(config = {name: TRACER_NAME, version: TRACER_VERSION})
duonoid marked this conversation as resolved.
Show resolved Hide resolved
require_relative 'faraday/adapter'
Faraday::Adapter.install(config)
end
end
end
end
38 changes: 38 additions & 0 deletions adapters/faraday/lib/opentelemetry/adapters/faraday/adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

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

# TODO: General Question: should adapters explicitly load the libraries they depend on?
# Or, should adapters assume that the libraries are already loaded by the caller/user?
require 'faraday'
require 'opentelemetry/adapter'

require_relative 'middlewares/tracer_middleware'
mwear marked this conversation as resolved.
Show resolved Hide resolved
require_relative 'patches/rack_builder'

module OpenTelemetry
module Adapters
module Faraday
class Adapter < OpenTelemetry::Adapter
def install
register_tracer_middleware
use_middleware_by_default
end

private

def register_tracer_middleware
::Faraday::Middleware.register_middleware(
open_telemetry: Middlewares::TracerMiddleware
)
end

def use_middleware_by_default
::Faraday::RackBuilder.prepend(Patches::RackBuilder)
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

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

module OpenTelemetry
module Adapters
module Faraday
module Middlewares
class TracerMiddleware < ::Faraday::Middleware
def call(env)
tracer.in_span(env.url.to_s,
fbogsany marked this conversation as resolved.
Show resolved Hide resolved
attributes: { 'component' => 'http',
duonoid marked this conversation as resolved.
Show resolved Hide resolved
'http.method' => env.method,
duonoid marked this conversation as resolved.
Show resolved Hide resolved
'http.url' => env.url.to_s },
kind: :client) do |span|
propagate_context(span, env)

duonoid marked this conversation as resolved.
Show resolved Hide resolved
app.call(env).on_complete { |resp| trace_response(span, resp) }
end
end

private

attr_reader :app

def propagate_context(span, env)
formatter.extract(env)
formatter.inject(span.context, env.request_headers)
duonoid marked this conversation as resolved.
Show resolved Hide resolved
end

def formatter
Faraday::Adapter.http_formatter
end

def tracer
Faraday::Adapter.tracer
end

def trace_response(span, response)
span.set_attribute('http.status_code', response.status)
span.set_attribute('http.status_text', response.reason_phrase)
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

# Copyright 2019 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0
require_relative '../middlewares/tracer_middleware'

module OpenTelemetry
module Adapters
module Faraday
module Patches
# Module to be prepended to force Faraday to use the middleware by
# default so the user doesn't have to call `use` for every connection.
module RackBuilder
def adapter(*args)
use(:open_telemetry) unless @handlers.any? do |handler|
handler.klass == Middlewares::TracerMiddleware
end

super
end
end
end
end
end
end
13 changes: 13 additions & 0 deletions adapters/faraday/lib/opentelemetry/adapters/faraday/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

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

module OpenTelemetry
module Adapters
module Faraday
VERSION = '0.0.0'
end
end
end
32 changes: 32 additions & 0 deletions adapters/faraday/opentelemetry-adapters-faraday.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

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

lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'opentelemetry/adapters/faraday/version'

Gem::Specification.new do |spec|
spec.name = 'opentelemetry-adapters-faraday'
spec.version = OpenTelemetry::Adapters::Faraday::VERSION
spec.authors = ['OpenTelemetry Authors']
spec.email = ['[email protected]']

spec.summary = 'Faraday instrumentation adapter for the OpenTelemetry framework'
spec.description = 'Faraday instrumentation adapter for the OpenTelemetry framework'
spec.homepage = 'https://github.com/open-telemetry/opentelemetry-ruby'
spec.license = 'Apache-2.0'

spec.files = ::Dir.glob('lib/**/*.rb') +
::Dir.glob('*.md') +
['LICENSE']
spec.require_paths = ['lib']
spec.required_ruby_version = '>= 2.4.0'

spec.add_dependency 'opentelemetry-api', '~> 0.0'

spec.add_development_dependency 'bundler', '>= 1.17'
spec.add_development_dependency 'faraday', '~> 0.17.0'
end
1 change: 1 addition & 0 deletions api/lib/opentelemetry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require 'logger'

require 'opentelemetry/error'
require 'opentelemetry/adapter'
require 'opentelemetry/context'
require 'opentelemetry/distributed_context'
require 'opentelemetry/internal'
Expand Down
27 changes: 27 additions & 0 deletions api/lib/opentelemetry/adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

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

module OpenTelemetry
# The basic interface for Adapter objects
class Adapter
class << self
attr_reader :config

def install(config = {})
@config = config
new.install
end

def http_formatter
OpenTelemetry.tracer_factory.http_text_format
end

def tracer
OpenTelemetry.tracer_factory.tracer(config[:name], config[:version])
end
end
end
end
4 changes: 4 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ services:
context: .
working_dir: /app

ex-adapter-faraday:
<<: *base
working_dir: /app/adapters/faraday/example

sdk:
<<: *base
working_dir: /app/sdk
Expand Down
2 changes: 1 addition & 1 deletion sdk/lib/opentelemetry/sdk/trace/tracer_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module OpenTelemetry
module SDK
module Trace
# {TracerFactory} is the SDK implementation of {OpenTelemetry::Trace::TracerFactory}.
class TracerFactory
class TracerFactory < OpenTelemetry::Trace::TracerFactory
Key = Struct.new(:name, :version)
private_constant(:Key)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,15 +221,15 @@ def to_span_data
end

describe 'normally' do
let(:exporter_sleeps_for_millis) { exporter_timeout_millis - 1 }
let(:exporter_sleeps_for_millis) { exporter_timeout_millis - 10 }

it 'exporter is not interrupted' do
_(exporter.state).must_equal(:not_interrupted)
end
end

describe 'when exporter runs too long' do
let(:exporter_sleeps_for_millis) { exporter_timeout_millis + 1 }
let(:exporter_sleeps_for_millis) { exporter_timeout_millis + 10 }

it 'is interrupted by a timeout' do
_(exporter.state).must_equal(:called)
Expand Down