-
Notifications
You must be signed in to change notification settings - Fork 226
feat: http semconv opt in files #1547
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
Changes from 4 commits
ca200a9
0cbb1c4
e6e970c
7e5f4ff
3f3ff4e
f1c9701
62ce61e
3cfcc1e
c990c28
8f91e28
b4f01bb
db05759
4f71d4b
577458f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,8 +10,9 @@ module HTTP | |
| # The Instrumentation class contains logic to detect and install the Http instrumentation | ||
| class Instrumentation < OpenTelemetry::Instrumentation::Base | ||
| install do |_config| | ||
| require_dependencies | ||
| patch | ||
| patch_type = determine_semconv | ||
| send(:"require_dependencies_#{patch_type}") | ||
| send(:"patch_#{patch_type}") | ||
| end | ||
|
|
||
| present do | ||
|
|
@@ -20,14 +21,45 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base | |
|
|
||
| option :span_name_formatter, default: nil, validate: :callable | ||
|
|
||
| def patch | ||
| ::HTTP::Client.prepend(Patches::Client) | ||
| ::HTTP::Connection.prepend(Patches::Connection) | ||
| def determine_semconv | ||
| case ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', nil) | ||
| when 'http/dup' | ||
|
||
| 'dup' | ||
| when 'http' | ||
| 'stable' | ||
| else | ||
| 'old' | ||
| end | ||
| end | ||
|
|
||
| def require_dependencies | ||
| require_relative 'patches/client' | ||
| require_relative 'patches/connection' | ||
| def patch_old | ||
| ::HTTP::Client.prepend(Patches::Old::Client) | ||
| ::HTTP::Connection.prepend(Patches::Old::Connection) | ||
| end | ||
|
|
||
| def patch_dup | ||
| ::HTTP::Client.prepend(Patches::Dup::Client) | ||
| ::HTTP::Connection.prepend(Patches::Dup::Connection) | ||
| end | ||
|
|
||
| def patch_stable | ||
| ::HTTP::Client.prepend(Patches::Stable::Client) | ||
| ::HTTP::Connection.prepend(Patches::Stable::Connection) | ||
| end | ||
|
|
||
| def require_dependencies_dup | ||
| require_relative 'patches/dup/client' | ||
| require_relative 'patches/dup/connection' | ||
| end | ||
|
|
||
| def require_dependencies_old | ||
| require_relative 'patches/old/client' | ||
| require_relative 'patches/old/connection' | ||
| end | ||
|
|
||
| def require_dependencies_stable | ||
| require_relative 'patches/stable/client' | ||
| require_relative 'patches/stable/connection' | ||
| end | ||
| end | ||
| end | ||
|
|
||
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| # Copyright The OpenTelemetry Authors | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| module OpenTelemetry | ||
| module Instrumentation | ||
| module HTTP | ||
| module Patches | ||
| # Module using old and stable HTTP semantic conventions | ||
| module Dup | ||
| # Module to prepend to HTTP::Client for instrumentation | ||
| module Client | ||
| # Constant for the HTTP status range | ||
| HTTP_STATUS_SUCCESS_RANGE = (100..399) | ||
|
|
||
| def perform(req, options) | ||
| uri = req.uri | ||
| request_method = req.verb.to_s.upcase | ||
| span_name = create_request_span_name(request_method, uri.path) | ||
|
|
||
| attributes = { | ||
| # old semconv | ||
| 'http.method' => request_method, | ||
| 'http.scheme' => uri.scheme, | ||
| 'http.target' => uri.path, | ||
| 'http.url' => "#{uri.scheme}://#{uri.host}", | ||
| 'net.peer.name' => uri.host, | ||
| 'net.peer.port' => uri.port, | ||
| # stable semconv | ||
| 'http.request.method' => request_method, | ||
| 'url.scheme' => uri.scheme, | ||
| 'url.path' => uri.path, | ||
| 'url.full' => "#{uri.scheme}://#{uri.host}", | ||
| 'server.address' => uri.host, | ||
| 'server.port' => uri.port | ||
| } | ||
| attributes['url.query'] = uri.query unless uri.query.nil? | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Queries weren't previously reported and can often be |
||
| attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) | ||
|
|
||
| tracer.in_span(span_name, attributes: attributes, kind: :client) do |span| | ||
| OpenTelemetry.propagation.inject(req.headers) | ||
| super.tap do |response| | ||
| annotate_span_with_response!(span, response) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def config | ||
| OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance.config | ||
| end | ||
|
|
||
| def annotate_span_with_response!(span, response) | ||
| return unless response&.status | ||
|
|
||
| status_code = response.status.to_i | ||
| span.set_attribute('http.status_code', status_code) # old semconv | ||
| span.set_attribute('http.response.status_code', status_code) # stable semconv | ||
| span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status_code) | ||
| end | ||
|
|
||
| def create_request_span_name(request_method, request_path) | ||
| if (implementation = config[:span_name_formatter]) | ||
| updated_span_name = implementation.call(request_method, request_path) | ||
| updated_span_name.is_a?(String) ? updated_span_name : "HTTP #{request_method}" | ||
| else | ||
| "HTTP #{request_method}" | ||
| end | ||
| rescue StandardError | ||
| "HTTP #{request_method}" | ||
| end | ||
|
|
||
| def tracer | ||
| HTTP::Instrumentation.instance.tracer | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| # Copyright The OpenTelemetry Authors | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| module OpenTelemetry | ||
| module Instrumentation | ||
| module HTTP | ||
| module Patches | ||
| # Module using old and stable HTTP semantic conventions | ||
| module Dup | ||
| # Module to prepend to HTTP::Connection for instrumentation | ||
| module Connection | ||
| def initialize(req, options) | ||
| attributes = { | ||
| # old semconv | ||
| 'net.peer.name' => req.uri.host, | ||
| 'net.peer.port' => req.uri.port, | ||
| # stable semconv | ||
| 'server.address' => req.uri.host, | ||
| 'server.port' => req.uri.port | ||
| }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) | ||
|
|
||
| tracer.in_span('HTTP CONNECT', attributes: attributes) do | ||
| super | ||
| end | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def tracer | ||
| HTTP::Instrumentation.instance.tracer | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| # Copyright The OpenTelemetry Authors | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| module OpenTelemetry | ||
| module Instrumentation | ||
| module HTTP | ||
| module Patches | ||
| # Module using old HTTP semantic conventions | ||
| module Old | ||
| # Module to prepend to HTTP::Client for instrumentation | ||
| module Client | ||
| # Constant for the HTTP status range | ||
| HTTP_STATUS_SUCCESS_RANGE = (100..399) | ||
|
|
||
| def perform(req, options) | ||
| uri = req.uri | ||
| request_method = req.verb.to_s.upcase | ||
| span_name = create_request_span_name(request_method, uri.path) | ||
|
|
||
| attributes = { | ||
| 'http.method' => request_method, | ||
| 'http.scheme' => uri.scheme, | ||
| 'http.target' => uri.path, | ||
| 'http.url' => "#{uri.scheme}://#{uri.host}", | ||
| 'net.peer.name' => uri.host, | ||
| 'net.peer.port' => uri.port | ||
| }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) | ||
|
|
||
| tracer.in_span(span_name, attributes: attributes, kind: :client) do |span| | ||
| OpenTelemetry.propagation.inject(req.headers) | ||
| super.tap do |response| | ||
| annotate_span_with_response!(span, response) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def config | ||
| OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance.config | ||
| end | ||
|
|
||
| def annotate_span_with_response!(span, response) | ||
| return unless response&.status | ||
|
|
||
| status_code = response.status.to_i | ||
| span.set_attribute('http.status_code', status_code) | ||
| span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status_code) | ||
| end | ||
|
|
||
| def create_request_span_name(request_method, request_path) | ||
| if (implementation = config[:span_name_formatter]) | ||
| updated_span_name = implementation.call(request_method, request_path) | ||
| updated_span_name.is_a?(String) ? updated_span_name : "HTTP #{request_method}" | ||
| else | ||
| "HTTP #{request_method}" | ||
| end | ||
| rescue StandardError | ||
| "HTTP #{request_method}" | ||
| end | ||
|
|
||
| def tracer | ||
| HTTP::Instrumentation.instance.tracer | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This approach gives us a fresh HTTP instance on each run. Without this, a single HTTP instance receives all patches.