From 6a6d46d6f686c7e8ed87acdbb6a2a733ead5abc0 Mon Sep 17 00:00:00 2001 From: Troels Thomsen Date: Sun, 16 Jun 2024 09:54:25 +0200 Subject: [PATCH] Adopt latest semantic conventions --- .../instrumentation/ethon/patches/easy.rb | 6 +++ .../ethon/instrumentation_test.rb | 21 ++++++++ .../excon/middlewares/tracer_middleware.rb | 8 ++- .../instrumentation/excon/patches/socket.rb | 4 +- .../excon/instrumentation_test.rb | 50 +++++++++++++++++-- .../faraday/middlewares/tracer_middleware.rb | 6 +++ .../middlewares/tracer_middleware_test.rb | 31 ++++++++++++ .../instrumentation/http/patches/client.rb | 8 ++- .../http/patches/connection.rb | 4 +- .../http/patches/client_test.rb | 36 +++++++++++++ .../http/patches/connection_test.rb | 3 ++ .../http_client/patches/client.rb | 8 ++- .../http_client/patches/session.rb | 3 +- .../http_client/patches/client_test.rb | 24 +++++++++ .../http_client/patches/session_test.rb | 1 + .../instrumentation/httpx/plugin.rb | 8 ++- .../test/instrumentation/httpx/plugin_test.rb | 23 +++++++++ .../net/http/patches/instrumentation.rb | 17 ++++++- .../net/http/instrumentation_test.rb | 45 +++++++++++++++++ 19 files changed, 294 insertions(+), 12 deletions(-) diff --git a/instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/easy.rb b/instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/easy.rb index 14f6b429d..e43454e17 100644 --- a/instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/easy.rb +++ b/instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/easy.rb @@ -41,6 +41,7 @@ def complete message = return_code ? ::Ethon::Curl.easy_strerror(return_code) : 'unknown reason' @otel_span.status = OpenTelemetry::Trace::Status.error("Request has failed: #{message}") else + @otel_span.set_attribute('http.response.status_code', response_code) @otel_span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response_code) @otel_span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(response_code.to_i) end @@ -85,12 +86,17 @@ def otel_span_started? def span_creation_attributes(method) instrumentation_attrs = { OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => method + 'http.request.method' => method } uri = _otel_cleanse_uri(url) if uri instrumentation_attrs[OpenTelemetry::SemanticConventions::Trace::HTTP_URL] = uri.to_s instrumentation_attrs[OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME] = uri.host if uri.host + instrumentation_attrs['server.address'] = uri.host if uri.host + instrumentation_attrs['server.port'] = uri.port if uri.port + instrumentation_attrs['url.full'] = uri.to_s + instrumentation_attrs['url.scheme'] = uri.scheme if uri.scheme end config = Ethon::Instrumentation.instance.config diff --git a/instrumentation/ethon/test/opentelemetry/instrumentation/ethon/instrumentation_test.rb b/instrumentation/ethon/test/opentelemetry/instrumentation/ethon/instrumentation_test.rb index 159564db2..3cf15cc01 100644 --- a/instrumentation/ethon/test/opentelemetry/instrumentation/ethon/instrumentation_test.rb +++ b/instrumentation/ethon/test/opentelemetry/instrumentation/ethon/instrumentation_test.rb @@ -69,9 +69,15 @@ _(span.name).must_equal 'HTTP N/A' _(span.attributes['http.method']).must_equal 'N/A' + _(span.attributes['http.request.method']).must_equal 'N/A' + _(span.attributes['http.response.status_code']).must_be_nil _(span.attributes['http.status_code']).must_be_nil _(span.attributes['http.url']).must_equal 'http://example.com/test' _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/test' + _(span.attributes['url.scheme']).must_equal 'http' end end end @@ -92,8 +98,11 @@ def stub_response(options) stub_response(response_code: 200) do _(span.name).must_equal 'HTTP N/A' _(span.attributes['http.method']).must_equal 'N/A' + _(span.attributes['http.request.method']).must_equal 'N/A' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.url']).must_equal 'http://example.com/test' + _(span.attributes['url.full']).must_equal 'http://example.com/test' _(easy.instance_eval { @otel_span }).must_be_nil _( easy.instance_eval { @otel_original_headers['traceparent'] } @@ -105,8 +114,11 @@ def stub_response(options) stub_response(response_code: 500) do _(span.name).must_equal 'HTTP N/A' _(span.attributes['http.method']).must_equal 'N/A' + _(span.attributes['http.request.method']).must_equal 'N/A' + _(span.attributes['http.response.status_code']).must_equal 500 _(span.attributes['http.status_code']).must_equal 500 _(span.attributes['http.url']).must_equal 'http://example.com/test' + _(span.attributes['url.full']).must_equal 'http://example.com/test' _(easy.instance_eval { @otel_span }).must_be_nil _( easy.instance_eval { @otel_original_headers['traceparent'] } @@ -118,8 +130,11 @@ def stub_response(options) stub_response(response_code: 0, return_code: :operation_timedout) do _(span.name).must_equal 'HTTP N/A' _(span.attributes['http.method']).must_equal 'N/A' + _(span.attributes['http.request.method']).must_equal 'N/A' + _(span.attributes['http.response.status_code']).must_be_nil _(span.attributes['http.status_code']).must_be_nil _(span.attributes['http.url']).must_equal 'http://example.com/test' + _(span.attributes['url.full']).must_equal 'http://example.com/test' _(span.status.code).must_equal( OpenTelemetry::Trace::Status::ERROR ) @@ -140,8 +155,10 @@ def stub_response(options) OpenTelemetry::Common::HTTP::ClientContext.with_attributes(client_context_attrs) do stub_response(response_code: 200) do _(span.attributes['http.method']).must_equal 'OVERRIDE' + _(span.attributes['http.request.method']).must_equal 'N/A' _(span.attributes['http.url']).must_equal 'http://example.com/test' _(span.attributes['test.attribute']).must_equal 'test.value' + _(span.attributes['url.full']).must_equal 'http://example.com/test' end end end @@ -278,8 +295,12 @@ def stub_response(options) _(exporter.finished_spans.size).must_equal 2 _(exporter.finished_spans[0].attributes['http.url']).must_be_nil _(exporter.finished_spans[0].attributes['net.peer.name']).must_be_nil + _(exporter.finished_spans[0].attributes['server.address']).must_be_nil + _(exporter.finished_spans[0].attributes['url.full']).must_be_nil _(exporter.finished_spans[1].attributes['http.url']).must_equal 'test' _(exporter.finished_spans[1].attributes['net.peer.name']).must_be_nil + _(exporter.finished_spans[1].attributes['server.address']).must_be_nil + _(exporter.finished_spans[1].attributes['url.full']).must_equal 'test' end end end diff --git a/instrumentation/excon/lib/opentelemetry/instrumentation/excon/middlewares/tracer_middleware.rb b/instrumentation/excon/lib/opentelemetry/instrumentation/excon/middlewares/tracer_middleware.rb index 7d7b5803f..da540f843 100644 --- a/instrumentation/excon/lib/opentelemetry/instrumentation/excon/middlewares/tracer_middleware.rb +++ b/instrumentation/excon/lib/opentelemetry/instrumentation/excon/middlewares/tracer_middleware.rb @@ -29,10 +29,15 @@ def request_call(datum) attributes = { OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => datum[:host], OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => http_method, + 'http.request.method' => http_method, OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => datum[:scheme], OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => datum[:path], OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => datum[:hostname], - OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => datum[:port] + OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => datum[:port], + 'server.address' => datum[:hostname], + 'server.port' => datum[:port], + 'url.full' => OpenTelemetry::Common::Utilities.cleanse_url(::Excon::Utils.request_uri(datum)), + 'url.scheme' => datum[:scheme] } peer_service = Excon::Instrumentation.instance.config[:peer_service] @@ -82,6 +87,7 @@ def handle_response(datum) if datum.key?(:response) response = datum[:response] + span.set_attribute('http.response.status_code', response[:status]) span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response[:status]) span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(response[:status].to_i) end diff --git a/instrumentation/excon/lib/opentelemetry/instrumentation/excon/patches/socket.rb b/instrumentation/excon/lib/opentelemetry/instrumentation/excon/patches/socket.rb index 0b97690ec..9e15160f9 100644 --- a/instrumentation/excon/lib/opentelemetry/instrumentation/excon/patches/socket.rb +++ b/instrumentation/excon/lib/opentelemetry/instrumentation/excon/patches/socket.rb @@ -25,7 +25,9 @@ def connect attributes = { OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => conn_address, - OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => conn_port + OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => conn_port, + 'server.address' => conn_address, + 'server.port' => conn_port }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) if is_a?(::Excon::SSLSocket) && @data[:proxy] diff --git a/instrumentation/excon/test/opentelemetry/instrumentation/excon/instrumentation_test.rb b/instrumentation/excon/test/opentelemetry/instrumentation/excon/instrumentation_test.rb index 4301f853a..3cac70247 100644 --- a/instrumentation/excon/test/opentelemetry/instrumentation/excon/instrumentation_test.rb +++ b/instrumentation/excon/test/opentelemetry/instrumentation/excon/instrumentation_test.rb @@ -50,9 +50,15 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.host']).must_equal 'example.com' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', @@ -63,6 +69,7 @@ specify 'after request with capital-letters HTTP method' do Excon.new('http://example.com/success').request(method: 'GET') + _(span.attributes['http.request.method']).must_equal 'GET' _(span.attributes['http.method']).must_equal 'GET' end @@ -73,9 +80,15 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.host']).must_equal 'example.com' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 500 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 500 _(span.attributes['http.target']).must_equal '/failure' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/failure' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/failure', @@ -92,8 +105,13 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.host']).must_equal 'example.com' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.target']).must_equal '/timeout' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/timeout' + _(span.attributes['url.scheme']).must_equal 'http' _(span.status.code).must_equal( OpenTelemetry::Trace::Status::ERROR ) @@ -121,10 +139,16 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.host']).must_equal 'example.com' _(span.attributes['http.method']).must_equal 'OVERRIDE' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 _(span.attributes['test.attribute']).must_equal 'test.value' + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', @@ -188,6 +212,9 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.host']).must_equal 'example.com' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 end it 'creates a span on connect for a non-ignored request' do @@ -200,6 +227,8 @@ _(span.kind).must_equal(:internal) _(span.attributes['net.peer.name']).must_equal('example.com') _(span.attributes['net.peer.port']).must_equal(80) + _(span.attributes['server.address']).must_equal('example.com') + _(span.attributes['server.port']).must_equal(80) end end @@ -234,8 +263,11 @@ _(span.attributes['net.peer.name']).must_equal('localhost') _(span.attributes['net.peer.port']).wont_be_nil _(span.attributes['net.peer.port']).must_equal(port) + _(span.attributes['server.address']).must_equal('localhost') + _(span.attributes['server.port']).wont_be_nil + _(span.attributes['server.port']).must_equal(port) - assert_http_spans(target: '/example', exception: 'Excon::Error::Timeout') + assert_http_spans(port: port, target: '/example', exception: 'Excon::Error::Timeout') end it 'captures errors' do @@ -245,13 +277,15 @@ _(span.name).must_equal 'connect' _(span.attributes['net.peer.name']).must_equal('invalid.com') _(span.attributes['net.peer.port']).must_equal(99_999) + _(span.attributes['server.address']).must_equal('invalid.com') + _(span.attributes['server.port']).must_equal(99_999) span_event = span.events.first _(span_event.name).must_equal 'exception' # Depending on the Ruby and Excon Version this will be a SocketError, Socket::ResolutionError or Resolv::ResolvError _(span_event.attributes['exception.type']).must_match(/(Socket|Resolv)/) - assert_http_spans(host: 'invalid.com', target: '/example') + assert_http_spans(host: 'invalid.com', port: 99_999, target: '/example') end it '[BUG] fails to emit an HTTP CONNECT span when connecting through an SSL proxy for an HTTP service' do @@ -262,6 +296,8 @@ _(span.kind).must_equal(:internal) _(span.attributes['net.peer.name']).must_equal('localhost') _(span.attributes['net.peer.port']).must_equal(443) + _(span.attributes['server.address']).must_equal('localhost') + _(span.attributes['server.port']).must_equal(443) assert_http_spans end @@ -274,6 +310,8 @@ _(span.kind).must_equal(:client) _(span.attributes['net.peer.name']).must_equal('localhost') _(span.attributes['net.peer.port']).must_equal(443) + _(span.attributes['server.address']).must_equal('localhost') + _(span.attributes['server.port']).must_equal(443) assert_http_spans(scheme: 'https') end @@ -286,6 +324,8 @@ _(span.kind).must_equal(:internal) _(span.attributes['net.peer.name']).must_equal('localhost') _(span.attributes['net.peer.port']).must_equal(443) + _(span.attributes['server.address']).must_equal('localhost') + _(span.attributes['server.port']).must_equal(443) assert_http_spans(exception: 'Excon::Error::Socket') end @@ -299,13 +339,17 @@ end end - def assert_http_spans(scheme: 'http', host: 'localhost', target: '/', exception: nil) + def assert_http_spans(scheme: 'http', host: 'localhost', port: nil, target: '/', exception: nil) exporter.finished_spans[1..].each do |http_span| _(http_span.name).must_equal 'HTTP GET' _(http_span.attributes['http.host']).must_equal host _(http_span.attributes['http.method']).must_equal 'GET' + _(http_span.attributes['http.request.method']).must_equal 'GET' _(http_span.attributes['http.scheme']).must_equal scheme _(http_span.attributes['http.target']).must_equal target + _(http_span.attributes['server.address']).must_equal host + _(http_span.attributes['url.full']).must_equal "#{scheme}://#{host}#{port&.to_s&.prepend(':')}#{target}" + _(http_span.attributes['url.scheme']).must_equal scheme _(http_span.status.code).must_equal( OpenTelemetry::Trace::Status::ERROR ) diff --git a/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb b/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb index f7bf04abb..69fa6e326 100644 --- a/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb +++ b/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb @@ -48,11 +48,16 @@ def call(env) def span_creation_attributes(http_method:, url:, config:) instrumentation_attrs = { OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => http_method, + 'http.request.method' => http_method, OpenTelemetry::SemanticConventions::Trace::HTTP_URL => OpenTelemetry::Common::Utilities.cleanse_url(url.to_s), + 'url.full' => OpenTelemetry::Common::Utilities.cleanse_url(url.to_s), + 'url.scheme' => url.scheme, 'faraday.adapter.name' => app.class.name } instrumentation_attrs[OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME] = url.host if url.host instrumentation_attrs[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = config[:peer_service] if config[:peer_service] + instrumentation_attrs['server.address'] = url.host if url.host + instrumentation_attrs['server.port'] = url.port if url.port instrumentation_attrs.merge!( OpenTelemetry::Common::HTTP::ClientContext.attributes @@ -67,6 +72,7 @@ def tracer end def trace_response(span, status) + span.set_attribute('http.response.status_code', status) span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, status) span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(status.to_i) end diff --git a/instrumentation/faraday/test/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware_test.rb b/instrumentation/faraday/test/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware_test.rb index acedc19d2..d1a4a371e 100644 --- a/instrumentation/faraday/test/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware_test.rb +++ b/instrumentation/faraday/test/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware_test.rb @@ -48,9 +48,15 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.url']).must_equal 'http://example.com/success' _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' _(response.env.request_headers['Traceparent']).must_equal( "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" ) @@ -61,9 +67,15 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 404 _(span.attributes['http.status_code']).must_equal 404 _(span.attributes['http.url']).must_equal 'http://example.com/not_found' _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/not_found' + _(span.attributes['url.scheme']).must_equal 'http' _(response.env.request_headers['Traceparent']).must_equal( "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" ) @@ -74,9 +86,15 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 500 _(span.attributes['http.status_code']).must_equal 500 _(span.attributes['http.url']).must_equal 'http://example.com/failure' _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/failure' + _(span.attributes['url.scheme']).must_equal 'http' _(response.env.request_headers['Traceparent']).must_equal( "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" ) @@ -92,10 +110,16 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'OVERRIDE' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.url']).must_equal 'http://example.com/success' _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 _(span.attributes['test.attribute']).must_equal 'test.value' + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' _(response.env.request_headers['Traceparent']).must_equal( "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" ) @@ -153,6 +177,7 @@ client.run_request(:get, 'http://username:password@example.com/success', nil, {}) _(span.attributes['http.url']).must_equal 'http://example.com/success' + _(span.attributes['url.full']).must_equal 'http://example.com/success' end end @@ -170,8 +195,13 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.url']).must_equal 'http:/success' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http:/success' + _(span.attributes['url.scheme']).must_equal 'http' _(span.attributes).wont_include('net.peer.name') _(response.env.request_headers['Traceparent']).must_equal( "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" @@ -194,6 +224,7 @@ client.get('/not_found') end + _(span.attributes['http.response.status_code']).must_equal 404 _(span.attributes['http.status_code']).must_equal 404 _(span.status.code).must_equal OpenTelemetry::Trace::Status::ERROR end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb index 3ceafcdba..873ff8bd3 100644 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb @@ -17,11 +17,16 @@ def perform(req, options) attributes = { OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_method, + 'http.request.method' => request_method, OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => uri.scheme, OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => uri.path, OpenTelemetry::SemanticConventions::Trace::HTTP_URL => "#{uri.scheme}://#{uri.host}", OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => uri.host, - OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port + OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port, + 'server.address' => uri.host, + 'server.port' => uri.port, + 'url.full' => OpenTelemetry::Common::Utilities.cleanse_url(uri.to_s), + 'url.scheme' => uri.scheme }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) tracer.in_span(span_name, attributes: attributes, kind: :client) do |span| @@ -42,6 +47,7 @@ def annotate_span_with_response!(span, response) return unless response&.status status_code = response.status.to_i + span.set_attribute('http.response.status_code', status_code) span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, status_code) span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(status_code.to_i) end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/connection.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/connection.rb index 9efba7b45..93c5346e0 100644 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/connection.rb +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/connection.rb @@ -13,7 +13,9 @@ module Connection def initialize(req, options) attributes = { OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => req.uri.host, - OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => req.uri.port + OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => req.uri.port, + 'server.address' => req.uri.host, + 'server.port' => req.uri.port }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) tracer.in_span('HTTP CONNECT', attributes: attributes) do diff --git a/instrumentation/http/test/instrumentation/http/patches/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/client_test.rb index 8d62a5b07..03c459afc 100644 --- a/instrumentation/http/test/instrumentation/http/patches/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/client_test.rb @@ -47,11 +47,17 @@ _(exporter.finished_spans.size).must_equal(1) _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', @@ -65,11 +71,17 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP POST' _(span.attributes['http.method']).must_equal 'POST' + _(span.attributes['http.request.method']).must_equal 'POST' + _(span.attributes['http.response.status_code']).must_equal 500 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 500 _(span.attributes['http.target']).must_equal '/failure' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/failure' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :post, 'http://example.com/failure', @@ -85,11 +97,17 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_be_nil _(span.attributes['http.scheme']).must_equal 'https' _(span.attributes['http.status_code']).must_be_nil _(span.attributes['http.target']).must_equal '/timeout' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 443 + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 443 + _(span.attributes['url.full']).must_equal 'https://example.com/timeout' + _(span.attributes['url.scheme']).must_equal 'https' _(span.status.code).must_equal( OpenTelemetry::Trace::Status::ERROR ) @@ -111,12 +129,18 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 _(span.attributes['peer.service']).must_equal 'foo' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', @@ -140,12 +164,18 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP GET /success miniswan' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 _(span.attributes['peer.service']).must_equal 'foo' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', @@ -169,12 +199,18 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 _(span.attributes['peer.service']).must_equal 'foo' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', diff --git a/instrumentation/http/test/instrumentation/http/patches/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/connection_test.rb index fe7e1caa1..a20acdcf1 100644 --- a/instrumentation/http/test/instrumentation/http/patches/connection_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/connection_test.rb @@ -41,6 +41,9 @@ _(span.attributes['net.peer.name']).must_equal('localhost') _(span.attributes['net.peer.port']).wont_be_nil _(span.attributes['net.peer.port']).must_equal(port) + _(span.attributes['server.address']).must_equal('localhost') + _(span.attributes['server.port']).wont_be_nil + _(span.attributes['server.port']).must_equal(port) ensure WebMock.disable_net_connect! end diff --git a/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/client.rb b/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/client.rb index cd743c596..793f1ba14 100644 --- a/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/client.rb +++ b/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/client.rb @@ -19,11 +19,16 @@ def do_get_block(req, proxy, conn, &block) attributes = { OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_method, + 'http.request.method' => request_method, OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => uri.scheme, OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => uri.path, OpenTelemetry::SemanticConventions::Trace::HTTP_URL => url, OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => uri.host, - OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port + OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port, + 'server.address' => uri.host, + 'server.port' => uri.port, + 'url.full' => OpenTelemetry::Common::Utilities.cleanse_url(uri.to_s), + 'url.scheme' => uri.scheme }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) tracer.in_span("HTTP #{request_method}", attributes: attributes, kind: :client) do |span| @@ -41,6 +46,7 @@ def annotate_span_with_response!(span, response) status_code = response.status_code.to_i + span.set_attribute('http.response.status_code', status_code) span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, status_code) span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(status_code.to_i) end diff --git a/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/session.rb b/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/session.rb index c29b6b8be..5dc832cbc 100644 --- a/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/session.rb +++ b/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/session.rb @@ -15,7 +15,8 @@ def connect url = site.addr attributes = { - OpenTelemetry::SemanticConventions::Trace::HTTP_URL => url + OpenTelemetry::SemanticConventions::Trace::HTTP_URL => url, + 'url.full' => url }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) tracer.in_span('HTTP CONNECT', attributes: attributes) do super diff --git a/instrumentation/http_client/test/instrumentation/http_client/patches/client_test.rb b/instrumentation/http_client/test/instrumentation/http_client/patches/client_test.rb index d71d2555c..de4c00da2 100644 --- a/instrumentation/http_client/test/instrumentation/http_client/patches/client_test.rb +++ b/instrumentation/http_client/test/instrumentation/http_client/patches/client_test.rb @@ -41,11 +41,17 @@ _(exporter.finished_spans.size).must_equal(1) _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', @@ -61,11 +67,17 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP POST' _(span.attributes['http.method']).must_equal 'POST' + _(span.attributes['http.request.method']).must_equal 'POST' + _(span.attributes['http.response.status_code']).must_equal 500 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 500 _(span.attributes['http.target']).must_equal '/failure' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/failure' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :post, 'http://example.com/failure', @@ -83,11 +95,17 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_be_nil _(span.attributes['http.scheme']).must_equal 'https' _(span.attributes['http.status_code']).must_be_nil _(span.attributes['http.target']).must_equal '/timeout' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 443 + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 443 + _(span.attributes['url.full']).must_equal 'https://example.com/timeout' + _(span.attributes['url.scheme']).must_equal 'https' _(span.status.code).must_equal( OpenTelemetry::Trace::Status::ERROR ) @@ -111,12 +129,18 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 _(span.attributes['peer.service']).must_equal 'foo' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', diff --git a/instrumentation/http_client/test/instrumentation/http_client/patches/session_test.rb b/instrumentation/http_client/test/instrumentation/http_client/patches/session_test.rb index d38bd7a72..a79bcc304 100644 --- a/instrumentation/http_client/test/instrumentation/http_client/patches/session_test.rb +++ b/instrumentation/http_client/test/instrumentation/http_client/patches/session_test.rb @@ -39,6 +39,7 @@ _(exporter.finished_spans.size).must_equal(2) _(span.name).must_equal 'HTTP CONNECT' _(span.attributes['http.url']).must_match(%r{http://localhost:}) + _(span.attributes['url.full']).must_match(%r{http://localhost:}) ensure WebMock.disable_net_connect! end diff --git a/instrumentation/httpx/lib/opentelemetry/instrumentation/httpx/plugin.rb b/instrumentation/httpx/lib/opentelemetry/instrumentation/httpx/plugin.rb index 137fca976..6f75bc7af 100644 --- a/instrumentation/httpx/lib/opentelemetry/instrumentation/httpx/plugin.rb +++ b/instrumentation/httpx/lib/opentelemetry/instrumentation/httpx/plugin.rb @@ -25,11 +25,16 @@ def call attributes = { OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => uri.host, OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_method, + 'http.request.method' => request_method, OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => uri.scheme, OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => uri.path, OpenTelemetry::SemanticConventions::Trace::HTTP_URL => "#{uri.scheme}://#{uri.host}", OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => uri.host, - OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port + OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port, + 'server.address' => uri.host, + 'server.port' => uri.port, + 'url.full' => OpenTelemetry::Common::Utilities.cleanse_url(uri.to_s), + 'url.scheme' => uri.scheme } config = HTTPX::Instrumentation.instance.config attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = config[:peer_service] if config[:peer_service] @@ -53,6 +58,7 @@ def finish(response) @span.record_exception(response.error) @span.status = Trace::Status.error("Unhandled exception of type: #{response.error.class}") else + @span.set_attribute('http.response.status_code', response.status) @span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response.status) @span.status = Trace::Status.error unless (100..399).cover?(response.status) end diff --git a/instrumentation/httpx/test/instrumentation/httpx/plugin_test.rb b/instrumentation/httpx/test/instrumentation/httpx/plugin_test.rb index d285cb70f..7632550b3 100644 --- a/instrumentation/httpx/test/instrumentation/httpx/plugin_test.rb +++ b/instrumentation/httpx/test/instrumentation/httpx/plugin_test.rb @@ -40,9 +40,15 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.host']).must_equal 'example.com' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', @@ -57,9 +63,15 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.host']).must_equal 'example.com' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 500 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 500 _(span.attributes['http.target']).must_equal '/failure' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/failure' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/failure', @@ -76,8 +88,13 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.host']).must_equal 'example.com' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.target']).must_equal '/timeout' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/timeout' + _(span.attributes['url.scheme']).must_equal 'http' _(span.status.code).must_equal( OpenTelemetry::Trace::Status::ERROR ) @@ -104,10 +121,16 @@ _(span.name).must_equal 'HTTP GET' _(span.attributes['http.host']).must_equal 'example.com' _(span.attributes['http.method']).must_equal 'OVERRIDE' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 _(span.attributes['test.attribute']).must_equal 'test.value' + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', diff --git a/instrumentation/net_http/lib/opentelemetry/instrumentation/net/http/patches/instrumentation.rb b/instrumentation/net_http/lib/opentelemetry/instrumentation/net/http/patches/instrumentation.rb index 725d4c546..06f5fddc1 100644 --- a/instrumentation/net_http/lib/opentelemetry/instrumentation/net/http/patches/instrumentation.rb +++ b/instrumentation/net_http/lib/opentelemetry/instrumentation/net/http/patches/instrumentation.rb @@ -4,6 +4,8 @@ # # SPDX-License-Identifier: Apache-2.0 +require 'uri' + module OpenTelemetry module Instrumentation module Net @@ -13,6 +15,7 @@ module Patches module Instrumentation HTTP_METHODS_TO_SPAN_NAMES = Hash.new { |h, k| h[k] = "HTTP #{k}" } USE_SSL_TO_SCHEME = { false => 'http', true => 'https' }.freeze + USE_SSL_TO_URI = { false => URI::HTTP, true => URI::HTTPS }.freeze def request(req, body = nil, &block) # Do not trace recursive call for starting the connection @@ -20,12 +23,19 @@ def request(req, body = nil, &block) return super if untraced? + url = URI.join(USE_SSL_TO_URI[use_ssl?].build(host: @address, port: @port), req.path) + attributes = { OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => req.method, + 'http.request.method' => req.method, OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => USE_SSL_TO_SCHEME[use_ssl?], OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => req.path, OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => @address, - OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => @port + OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => @port, + 'server.address' => @address, + 'server.port' => @port, + 'url.full' => OpenTelemetry::Common::Utilities.cleanse_url(url.to_s), + 'url.scheme' => USE_SSL_TO_SCHEME[use_ssl?] }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) tracer.in_span( @@ -56,7 +66,9 @@ def connect attributes = { OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => conn_address, - OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => conn_port + OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => conn_port, + 'server.address' => conn_address, + 'server.port' => conn_port }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) if use_ssl? && proxy? @@ -77,6 +89,7 @@ def annotate_span_with_response!(span, response) status_code = response.code.to_i + span.set_attribute('http.response.status_code', status_code) span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, status_code) span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(status_code.to_i) end diff --git a/instrumentation/net_http/test/opentelemetry/instrumentation/net/http/instrumentation_test.rb b/instrumentation/net_http/test/opentelemetry/instrumentation/net/http/instrumentation_test.rb index 0d7b162b7..915ed4cf4 100644 --- a/instrumentation/net_http/test/opentelemetry/instrumentation/net/http/instrumentation_test.rb +++ b/instrumentation/net_http/test/opentelemetry/instrumentation/net/http/instrumentation_test.rb @@ -45,11 +45,17 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal '/success' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', @@ -63,11 +69,17 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP POST' _(span.attributes['http.method']).must_equal 'POST' + _(span.attributes['http.request.method']).must_equal 'POST' + _(span.attributes['http.response.status_code']).must_equal 500 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 500 _(span.attributes['http.target']).must_equal '/failure' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/failure' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :post, 'http://example.com/failure', @@ -83,11 +95,17 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_be_nil _(span.attributes['http.scheme']).must_equal 'https' _(span.attributes['http.status_code']).must_be_nil _(span.attributes['http.target']).must_equal '/timeout' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 443 + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 443 + _(span.attributes['url.full']).must_equal 'https://example.com/timeout' + _(span.attributes['url.scheme']).must_equal 'https' _(span.status.code).must_equal( OpenTelemetry::Trace::Status::ERROR ) @@ -109,18 +127,32 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['http.response.status_code']).must_equal 200 _(span.attributes['http.scheme']).must_equal 'http' _(span.attributes['http.status_code']).must_equal 200 _(span.attributes['http.target']).must_equal 'REDACTED' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 _(span.attributes['peer.service']).must_equal 'foo' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.full']).must_equal 'http://example.com/success' + _(span.attributes['url.scheme']).must_equal 'http' assert_requested( :get, 'http://example.com/success', headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } ) end + + it 'includes the query string' do + stub_request(:get, 'http://example.com/success?ok=true').to_return(status: 200) + + Net::HTTP.get('example.com', '/success?ok=true') + + _(span.attributes['url.full']).must_equal 'http://example.com/success?ok=true' + end end describe 'untraced?' do @@ -163,7 +195,9 @@ _(exporter.finished_spans.size).must_equal 1 _(span.name).must_equal 'HTTP GET' _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.request.method']).must_equal 'GET' _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['server.address']).must_equal 'example.com' end it 'creates a span on connect for a non-ignored request' do @@ -176,6 +210,8 @@ _(span.kind).must_equal(:internal) _(span.attributes['net.peer.name']).must_equal('example.com') _(span.attributes['net.peer.port']).must_equal(80) + _(span.attributes['server.address']).must_equal('example.com') + _(span.attributes['server.port']).must_equal(80) end end @@ -228,6 +264,9 @@ _(span.attributes['net.peer.name']).must_equal('localhost') _(span.attributes['net.peer.port']).wont_be_nil _(span.attributes['net.peer.port']).must_equal(port) + _(span.attributes['server.address']).must_equal('localhost') + _(span.attributes['server.port']).wont_be_nil + _(span.attributes['server.port']).must_equal(port) ensure WebMock.disable_net_connect! end @@ -243,6 +282,8 @@ _(span.name).must_equal 'connect' _(span.attributes['net.peer.name']).must_equal('invalid.com') _(span.attributes['net.peer.port']).must_equal(99_999) + _(span.attributes['server.address']).must_equal('invalid.com') + _(span.attributes['server.port']).must_equal(99_999) span_event = span.events.first @@ -273,6 +314,8 @@ _(span.kind).must_equal(:client) _(span.attributes['net.peer.name']).must_equal('localhost') _(span.attributes['net.peer.port']).must_equal(443) + _(span.attributes['server.address']).must_equal('localhost') + _(span.attributes['server.port']).must_equal(443) ensure WebMock.disable_net_connect! end @@ -297,6 +340,8 @@ _(span.kind).must_equal(:internal) _(span.attributes['net.peer.name']).must_equal('localhost') _(span.attributes['net.peer.port']).must_equal(443) + _(span.attributes['server.address']).must_equal('localhost') + _(span.attributes['server.port']).must_equal(443) ensure WebMock.disable_net_connect! end