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 Net:HTTP instrumentation adapter #187

Merged
merged 1 commit into from
Feb 28, 2020
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
8 changes: 8 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ commands:
bundle install --jobs=3 --retry=3
bundle exec appraisal install
bundle exec appraisal rake test
- run:
name: Bundle + CI (Adapters - Net::HTTP)
command: |
cd adapters/net_http
gem uninstall -aIx bundler
gem install --no-document bundler -v '~> 2.0.2'
bundle install --jobs=3 --retry=3
bundle exec rake test
- run:
name: Bundle + CI (Adapters - Redis)
command: |
Expand Down
6 changes: 6 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ GEM_INFO = {
OpenTelemetry::Adapters::Faraday::VERSION
}
},
"opentelemetry-adapters-net_http" => {
version_getter: ->() {
require './lib/opentelemetry/adapters/net/http/version.rb'
OpenTelemetry::Adapters::Net::HTTP::VERSION
}
},
"opentelemetry-adapters-redis" => {
version_getter: ->() {
require './lib/opentelemetry/adapters/redis/version.rb'
Expand Down
27 changes: 27 additions & 0 deletions adapters/net_http/.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-net-http.rb"
Style/FrozenStringLiteralComment:
Exclude:
- gemfiles/**/*
Style/ModuleFunction:
Enabled: false
Style/StringLiterals:
Exclude:
- gemfiles/**/*
15 changes: 15 additions & 0 deletions adapters/net_http/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/net_http/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
7 changes: 7 additions & 0 deletions adapters/net_http/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 'opentelemetry-adapters-net-http', path: '../../../adapters/net_http'
gem 'opentelemetry-api', path: '../../../api'
gem 'opentelemetry-sdk', path: '../../../sdk'
13 changes: 13 additions & 0 deletions adapters/net_http/example/net_http.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

require 'rubygems'
require 'bundler/setup'
require 'net/http'

Bundler.require

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

Net::HTTP.get(URI('http://example.com'))
7 changes: 7 additions & 0 deletions adapters/net_http/lib/opentelemetry-adapters-net-http.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/net_http/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/net/http'
20 changes: 20 additions & 0 deletions adapters/net_http/lib/opentelemetry/adapters/net/http.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

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

require 'opentelemetry'

module OpenTelemetry
module Adapters
module Net
# Contains the OpenTelemetry adapter for the Net::HTTP gem
module HTTP
end
end
end
end

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

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

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

present do
defined?(::Net::HTTP)
end

private

def require_dependencies
require_relative 'patches/instrumentation'
end

def patch
::Net::HTTP.prepend(Patches::Instrumentation)
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# frozen_string_literal: true

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

module OpenTelemetry
module Adapters
module Net
module HTTP
module Patches
# Module to prepend to Net::HTTP for instrumentation
module Instrumentation
HTTP_METHODS_TO_SPAN_NAMES = Hash.new { |h, k| h[k] = "HTTP #{k}" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little concerned about the lazy initialization here. I'd prefer to eagerly init this and freeze the hash. I'm sort of on the fence, so just flagging the concern.

USE_SSL_TO_SCHEME = { false => 'http', true => 'https' }.freeze

def request(req, body = nil, &block)
# Do not trace recursive call for starting the connection
return super(req, body, &block) unless started?

tracer.in_span(
HTTP_METHODS_TO_SPAN_NAMES[req.method],
attributes: {
'component' => 'http',
'http.method' => req.method,
'http.scheme' => USE_SSL_TO_SCHEME[use_ssl?],
'http.target' => req.path,
'peer.hostname' => @address,
'peer.port' => @port
},
kind: :client
) do |span|
OpenTelemetry.propagation.inject(req)

super(req, body, &block).tap do |response|
annotate_span_with_response!(span, response)
end
end
end

private

def annotate_span_with_response!(span, response)
return unless response&.code

status_code = response.code.to_i

span.set_attribute('http.status_code', status_code)
span.status = OpenTelemetry::Trace::Status.http_to_status(
status_code
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any semantic conventions around identifying errors based on response codes? Or are we only flagging spans as errors if an exception is raised?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are not semantic conventions for errors at all yet. Our Span#record_error method uses a set of currently proposed conventions, with the understanding that those could change. It's currently only used for unhandled exceptions. This does bring up a good point though and that is, do we want to synthesize errors based on response codes. If yes, we should probably do this across the board in our HTTP instrumentation adapters. I'll create an issue to discuss and track this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end

def tracer
Net::HTTP::Adapter.instance.tracer
end
end
end
end
end
end
end
15 changes: 15 additions & 0 deletions adapters/net_http/lib/opentelemetry/adapters/net/http/version.rb
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

module OpenTelemetry
module Adapters
module Net
module HTTP
VERSION = '0.0.0'
end
end
end
end
39 changes: 39 additions & 0 deletions adapters/net_http/opentelemetry-adapters-net-http.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

# Copyright 2020 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/net/http/version'

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

spec.summary = 'Net::HTTP instrumentation adapter for the OpenTelemetry framework'
spec.description = 'Net::HTTP 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 'minitest', '~> 5.0'
spec.add_development_dependency 'opentelemetry-sdk', '~> 0.0'
spec.add_development_dependency 'rake', '~> 13.0.1'
spec.add_development_dependency 'rubocop', '~> 0.73.0'
spec.add_development_dependency 'simplecov', '~> 0.17.1'
spec.add_development_dependency 'webmock', '~> 3.7.6'
spec.add_development_dependency 'yard', '~> 0.9'
spec.add_development_dependency 'yard-doctest', '~> 0.1.6'
end
4 changes: 4 additions & 0 deletions adapters/net_http/test/.rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
inherit_from: ../.rubocop.yml

Metrics/BlockLength:
Enabled: false
Loading