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 hook to set custom span name in requests instrumentation #158

Merged
merged 5 commits into from
Nov 17, 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- Add span name callback
([#158](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/158))

## Version 0.15b0

Released 2020-11-02
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@

# pylint: disable=unused-argument
# pylint: disable=R0915
def _instrument(tracer_provider=None, span_callback=None):
def _instrument(tracer_provider=None, span_callback=None, name_callback=None):
"""Enables tracing of all requests calls that go through
:code:`requests.session.Session.request` (this includes
:code:`requests.get`, etc.)."""
Expand Down Expand Up @@ -124,7 +124,11 @@ def _instrumented_requests_call(
# See
# https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#http-client
method = method.upper()
span_name = "HTTP {}".format(method)
span_name = ""
if name_callback is not None:
span_name = name_callback()
if not span_name or not isinstance(span_name, str):
span_name = get_default_span_name(method)

recorder = RequestsInstrumentor().metric_recorder

Expand Down Expand Up @@ -217,6 +221,11 @@ def _uninstrument_from(instr_root, restore_as_bound_func=False):
setattr(instr_root, instr_func_name, original)


def get_default_span_name(method):
"""Default implementation for name_callback, returns HTTP {method_name}."""
return "HTTP {}".format(method).strip()


class RequestsInstrumentor(BaseInstrumentor, MetricMixin):
"""An instrumentor for requests
See `BaseInstrumentor`
Expand All @@ -229,10 +238,14 @@ def _instrument(self, **kwargs):
**kwargs: Optional arguments
``tracer_provider``: a TracerProvider, defaults to global
``span_callback``: An optional callback invoked before returning the http response. Invoked with Span and requests.Response
``name_callback``: Callback which calculates a generic span name for an
outgoing HTTP request based on the method and url.
Optional: Defaults to get_default_span_name.
"""
_instrument(
tracer_provider=kwargs.get("tracer_provider"),
span_callback=kwargs.get("span_callback"),
name_callback=kwargs.get("name_callback"),
)
self.init_metrics(
__name__, __version__,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,30 @@ def test_basic(self):
self.assertEqual(view_data.aggregator.current.count, 1)
self.assertGreaterEqual(view_data.aggregator.current.sum, 0)

def test_name_callback(self):
def name_callback():
return "test_name"

RequestsInstrumentor().uninstrument()
RequestsInstrumentor().instrument(name_callback=name_callback)
result = self.perform_request(self.URL)
self.assertEqual(result.text, "Hello!")
span = self.assert_span()

self.assertEqual(span.name, "test_name")

def test_name_callback_default(self):
def name_callback():
return 123

RequestsInstrumentor().uninstrument()
RequestsInstrumentor().instrument(name_callback=name_callback)
result = self.perform_request(self.URL)
self.assertEqual(result.text, "Hello!")
span = self.assert_span()

self.assertEqual(span.name, "HTTP GET")

def test_not_foundbasic(self):
url_404 = "http://httpbin.org/status/404"
httpretty.register_uri(
Expand Down