Skip to content

Commit 59be641

Browse files
committed
squash: reduce allocations
1 parent 6785956 commit 59be641

File tree

51 files changed

+710
-566
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+710
-566
lines changed

instrumentation/ethon/lib/opentelemetry/instrumentation/ethon.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ module Ethon
1515
end
1616
end
1717

18+
require_relative 'ethon/http_helper'
1819
require_relative 'ethon/instrumentation'
1920
require_relative 'ethon/version'
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# frozen_string_literal: true
2+
3+
# Copyright The OpenTelemetry Authors
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
module OpenTelemetry
8+
module Instrumentation
9+
module Ethon
10+
# Helper module for HTTP method normalization
11+
# @api private
12+
module HttpHelper
13+
# Lightweight struct to hold span creation attributes
14+
SpanCreationAttributes = Struct.new(:span_name, :normalized_method, :original_method, keyword_init: true)
15+
16+
# Pre-computed mapping to avoid string allocations during normalization
17+
METHOD_CACHE = {
18+
'CONNECT' => 'CONNECT',
19+
'DELETE' => 'DELETE',
20+
'GET' => 'GET',
21+
'HEAD' => 'HEAD',
22+
'OPTIONS' => 'OPTIONS',
23+
'PATCH' => 'PATCH',
24+
'POST' => 'POST',
25+
'PUT' => 'PUT',
26+
'TRACE' => 'TRACE',
27+
'connect' => 'CONNECT',
28+
'delete' => 'DELETE',
29+
'get' => 'GET',
30+
'head' => 'HEAD',
31+
'options' => 'OPTIONS',
32+
'patch' => 'PATCH',
33+
'post' => 'POST',
34+
'put' => 'PUT',
35+
'trace' => 'TRACE',
36+
:connect => 'CONNECT',
37+
:delete => 'DELETE',
38+
:get => 'GET',
39+
:head => 'HEAD',
40+
:options => 'OPTIONS',
41+
:patch => 'PATCH',
42+
:post => 'POST',
43+
:put => 'PUT',
44+
:trace => 'TRACE'
45+
}.freeze
46+
47+
# Pre-computed span names for old semantic conventions to avoid allocations
48+
OLD_SPAN_NAMES = {
49+
'CONNECT' => 'HTTP CONNECT',
50+
'DELETE' => 'HTTP DELETE',
51+
'GET' => 'HTTP GET',
52+
'HEAD' => 'HTTP HEAD',
53+
'OPTIONS' => 'HTTP OPTIONS',
54+
'PATCH' => 'HTTP PATCH',
55+
'POST' => 'HTTP POST',
56+
'PUT' => 'HTTP PUT',
57+
'TRACE' => 'HTTP TRACE'
58+
}.freeze
59+
60+
private_constant :METHOD_CACHE, :OLD_SPAN_NAMES
61+
62+
# Prepares all span data for the specified semantic convention in a single call
63+
# @param method [String, Symbol] The HTTP method
64+
# @param semconv [Symbol] The semantic convention to use (:stable or :old)
65+
# @return [SpanCreationAttributes] struct containing span_name, normalized_method, and original_method
66+
def self.span_attrs_for(method, semconv: :stable)
67+
normalized = METHOD_CACHE[method]
68+
if normalized
69+
span_name = semconv == :old ? OLD_SPAN_NAMES[normalized] : normalized
70+
SpanCreationAttributes.new(
71+
span_name: span_name,
72+
normalized_method: normalized,
73+
original_method: nil
74+
)
75+
else
76+
SpanCreationAttributes.new(
77+
span_name: 'HTTP',
78+
normalized_method: '_OTHER',
79+
original_method: method.to_s
80+
)
81+
end
82+
end
83+
end
84+
end
85+
end
86+
end

instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/dup/easy.rb

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
#
55
# SPDX-License-Identifier: Apache-2.0
66

7-
require_relative '../http_helper'
8-
97
module OpenTelemetry
108
module Instrumentation
119
module Ethon
@@ -18,7 +16,7 @@ module Easy
1816
HTTP_STATUS_SUCCESS_RANGE = (100..399)
1917

2018
def http_request(url, action_name, options = {})
21-
@otel_method = action_name.to_s.upcase
19+
@otel_method = action_name
2220
super
2321
end
2422

@@ -70,15 +68,11 @@ def reset
7068
end
7169

7270
def otel_before_request
73-
method = '_OTHER' # Could be GET or not HTTP at all
74-
method = @otel_method if instance_variable_defined?(:@otel_method) && !@otel_method.nil?
75-
76-
normalized_method, original_method = HttpHelper.normalize_method(method)
77-
span_name = HttpHelper.span_name_for_stable(normalized_method)
71+
span_data = HttpHelper.span_attrs_for(@otel_method)
7872

7973
@otel_span = tracer.start_span(
80-
span_name,
81-
attributes: span_creation_attributes(normalized_method, original_method),
74+
span_data.span_name,
75+
attributes: span_creation_attributes(span_data),
8276
kind: :client
8377
)
8478

@@ -95,13 +89,12 @@ def otel_span_started?
9589

9690
private
9791

98-
def span_creation_attributes(normalized_method, original_method)
99-
http_method = (normalized_method == '_OTHER' ? 'N/A' : normalized_method)
92+
def span_creation_attributes(span_data)
10093
instrumentation_attrs = {
101-
'http.method' => http_method,
102-
'http.request.method' => normalized_method
94+
'http.method' => span_data.normalized_method,
95+
'http.request.method' => span_data.normalized_method
10396
}
104-
instrumentation_attrs['http.request.method_original'] = original_method if original_method
97+
instrumentation_attrs['http.request.method_original'] = span_data.original_method if span_data.original_method
10598

10699
uri = _otel_cleanse_uri(url)
107100
if uri

instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/http_helper.rb

Lines changed: 0 additions & 41 deletions
This file was deleted.

instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/old/easy.rb

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
#
55
# SPDX-License-Identifier: Apache-2.0
66

7-
require_relative '../http_helper'
8-
97
module OpenTelemetry
108
module Instrumentation
119
module Ethon
@@ -18,7 +16,7 @@ module Easy
1816
HTTP_STATUS_SUCCESS_RANGE = (100..399)
1917

2018
def http_request(url, action_name, options = {})
21-
@otel_method = action_name.to_s.upcase
19+
@otel_method = action_name
2220
super
2321
end
2422

@@ -69,15 +67,11 @@ def reset
6967
end
7068

7169
def otel_before_request
72-
method = '_OTHER' # Could be GET or not HTTP at all
73-
method = @otel_method if instance_variable_defined?(:@otel_method) && !@otel_method.nil?
74-
75-
normalized_method, _original_method = HttpHelper.normalize_method(method)
76-
span_name = HttpHelper.span_name_for_old(normalized_method)
70+
span_data = HttpHelper.span_attrs_for(@otel_method, semconv: :old)
7771

7872
@otel_span = tracer.start_span(
79-
span_name,
80-
attributes: span_creation_attributes(normalized_method),
73+
span_data.span_name,
74+
attributes: span_creation_attributes(span_data),
8175
kind: :client
8276
)
8377

@@ -94,9 +88,9 @@ def otel_span_started?
9488

9589
private
9690

97-
def span_creation_attributes(normalized_method)
91+
def span_creation_attributes(span_data)
9892
instrumentation_attrs = {
99-
'http.method' => normalized_method
93+
'http.method' => span_data.normalized_method
10094
}
10195

10296
uri = _otel_cleanse_uri(url)

instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/stable/easy.rb

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
#
55
# SPDX-License-Identifier: Apache-2.0
66

7-
require_relative '../http_helper'
8-
97
module OpenTelemetry
108
module Instrumentation
119
module Ethon
@@ -18,7 +16,7 @@ module Easy
1816
HTTP_STATUS_SUCCESS_RANGE = (100..399)
1917

2018
def http_request(url, action_name, options = {})
21-
@otel_method = action_name.to_s.upcase
19+
@otel_method = action_name
2220
super
2321
end
2422

@@ -69,15 +67,11 @@ def reset
6967
end
7068

7169
def otel_before_request
72-
method = '_OTHER' # Could be GET or not HTTP at all
73-
method = @otel_method if instance_variable_defined?(:@otel_method) && !@otel_method.nil?
74-
75-
normalized_method, original_method = HttpHelper.normalize_method(method)
76-
span_name = HttpHelper.span_name_for_stable(normalized_method)
70+
span_data = HttpHelper.span_attrs_for(@otel_method)
7771

7872
@otel_span = tracer.start_span(
79-
span_name,
80-
attributes: span_creation_attributes(normalized_method, original_method),
73+
span_data.span_name,
74+
attributes: span_creation_attributes(span_data),
8175
kind: :client
8276
)
8377

@@ -94,11 +88,11 @@ def otel_span_started?
9488

9589
private
9690

97-
def span_creation_attributes(normalized_method, original_method)
91+
def span_creation_attributes(span_data)
9892
instrumentation_attrs = {
99-
'http.request.method' => normalized_method
93+
'http.request.method' => span_data.normalized_method
10094
}
101-
instrumentation_attrs['http.request.method_original'] = original_method if original_method
95+
instrumentation_attrs['http.request.method_original'] = span_data.original_method if span_data.original_method
10296

10397
uri = _otel_cleanse_uri(url)
10498
if uri

instrumentation/ethon/test/opentelemetry/instrumentation/ethon/dup/instrumentation_test.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
easy.perform
7272

7373
_(span.name).must_equal 'HTTP'
74-
_(span.attributes['http.method']).must_equal 'N/A'
74+
_(span.attributes['http.method']).must_equal '_OTHER'
7575
_(span.attributes['http.status_code']).must_be_nil
7676
_(span.attributes['http.url']).must_equal 'http://example.com/test'
7777
_(span.attributes['net.peer.name']).must_equal 'example.com'
@@ -92,7 +92,7 @@
9292
# NOTE: check the finished spans since we expect to have closed it
9393
span = exporter.finished_spans.first
9494
_(span.name).must_equal 'HTTP'
95-
_(span.attributes['http.method']).must_equal 'N/A'
95+
_(span.attributes['http.method']).must_equal '_OTHER'
9696
_(span.attributes['http.status_code']).must_be_nil
9797
_(span.attributes['http.url']).must_equal 'http://example.com/test'
9898
_(span.attributes['http.request.method']).must_equal '_OTHER'
@@ -121,7 +121,7 @@ def stub_response(options)
121121
it 'when response is successful' do
122122
stub_response(response_code: 200) do
123123
_(span.name).must_equal 'HTTP'
124-
_(span.attributes['http.method']).must_equal 'N/A'
124+
_(span.attributes['http.method']).must_equal '_OTHER'
125125
_(span.attributes['http.request.method']).must_equal '_OTHER'
126126
_(span.attributes['http.status_code']).must_equal 200
127127
_(span.attributes['http.response.status_code']).must_equal 200
@@ -137,7 +137,7 @@ def stub_response(options)
137137
it 'when response is not successful' do
138138
stub_response(response_code: 500) do
139139
_(span.name).must_equal 'HTTP'
140-
_(span.attributes['http.method']).must_equal 'N/A'
140+
_(span.attributes['http.method']).must_equal '_OTHER'
141141
_(span.attributes['http.request.method']).must_equal '_OTHER'
142142
_(span.attributes['http.status_code']).must_equal 500
143143
_(span.attributes['http.response.status_code']).must_equal 500
@@ -153,7 +153,7 @@ def stub_response(options)
153153
it 'when request times out' do
154154
stub_response(response_code: 0, return_code: :operation_timedout) do
155155
_(span.name).must_equal 'HTTP'
156-
_(span.attributes['http.method']).must_equal 'N/A'
156+
_(span.attributes['http.method']).must_equal '_OTHER'
157157
_(span.attributes['http.request.method']).must_equal '_OTHER'
158158
_(span.attributes['http.status_code']).must_be_nil
159159
_(span.attributes['http.response.status_code']).must_be_nil
@@ -232,7 +232,7 @@ def stub_response(options)
232232
end
233233

234234
it 'cleans up @otel_method' do
235-
_(easy.instance_eval { @otel_method }).must_equal 'PUT'
235+
_(easy.instance_eval { @otel_method }).must_equal :put
236236

237237
easy.reset
238238

@@ -274,10 +274,10 @@ def stub_response(options)
274274
stub_response(response_code: 200) do
275275
_(exporter.finished_spans.size).must_equal 1
276276
_(span.name).must_equal 'HTTP'
277-
_(span.attributes['http.method']).must_equal 'N/A'
277+
_(span.attributes['http.method']).must_equal '_OTHER'
278278
_(span.attributes['http.url']).must_equal 'http://example.com/purge'
279279
_(span.attributes['http.request.method']).must_equal '_OTHER'
280-
_(span.attributes['http.request.method_original']).must_equal 'PURGE'
280+
_(span.attributes['http.request.method_original']).must_equal 'purge'
281281
_(span.attributes['url.full']).must_equal 'http://example.com/purge'
282282
end
283283
end

instrumentation/ethon/test/opentelemetry/instrumentation/ethon/old/instrumentation_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def stub_response(options)
214214
end
215215

216216
it 'cleans up @otel_method' do
217-
_(easy.instance_eval { @otel_method }).must_equal 'PUT'
217+
_(easy.instance_eval { @otel_method }).must_equal :put
218218

219219
easy.reset
220220

instrumentation/ethon/test/opentelemetry/instrumentation/ethon/stable/instrumentation_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ def stub_response(options)
215215
end
216216

217217
it 'cleans up @otel_method' do
218-
_(easy.instance_eval { @otel_method }).must_equal 'PUT'
218+
_(easy.instance_eval { @otel_method }).must_equal :put
219219

220220
easy.reset
221221

@@ -258,7 +258,7 @@ def stub_response(options)
258258
_(exporter.finished_spans.size).must_equal 1
259259
_(span.name).must_equal 'HTTP'
260260
_(span.attributes['http.request.method']).must_equal '_OTHER'
261-
_(span.attributes['http.request.method_original']).must_equal 'PURGE'
261+
_(span.attributes['http.request.method_original']).must_equal 'purge'
262262
_(span.attributes['url.full']).must_equal 'http://example.com/purge'
263263
end
264264
end

instrumentation/excon/lib/opentelemetry/instrumentation/excon.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ module Excon
1515
end
1616
end
1717

18+
require_relative 'excon/http_helper'
1819
require_relative 'excon/instrumentation'
1920
require_relative 'excon/version'

0 commit comments

Comments
 (0)