Skip to content
This repository was archived by the owner on Sep 17, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a7695f7
Don't trace if it's a http request made by the exporter
geobeau Aug 29, 2018
7d76498
fix lint
geobeau Aug 29, 2018
b59b175
Don't cover this part
geobeau Aug 29, 2018
dbe01ce
Handle response without span
geobeau Aug 29, 2018
e02e370
Change name of disable_tracing_url to disable_tracing_path
geobeau Sep 19, 2018
0edecbb
Add a blacklist system to prevent tracing specific hostnames
geobeau Sep 19, 2018
4252e1e
Revert "Change name of disable_tracing_url to disable_tracing_path"
geobeau Sep 19, 2018
bd94d97
Add integration with Flask and Django
geobeau Sep 19, 2018
7c78b42
Add integration with requests
geobeau Sep 19, 2018
04da048
Update documentation
geobeau Sep 19, 2018
b1e1295
Fix lint
geobeau Sep 19, 2018
1840cd8
Fix tests and lint
geobeau Sep 20, 2018
e354219
Add testing for blacklist hostname
geobeau Sep 21, 2018
cde4fa9
Merge branch 'master' into fix-recursion
geobeau Sep 25, 2018
3e6f14e
Merge branch 'master' into fix-recursion
geobeau Oct 12, 2018
e62fdb0
Merge branch 'master' into fix-recursion
geobeau Oct 15, 2018
ac5f824
Merge branch 'master' into fix-recursion
geobeau Oct 17, 2018
67d11c7
Merge branch 'master' into fix-recursion
geobeau Oct 18, 2018
1294563
Merge branch 'master' into fix-recursion
geobeau Oct 19, 2018
e1d4840
Merge branch 'master' into fix-recursion
geobeau Oct 29, 2018
7c88234
Merge branch 'master' into fix-recursion
c24t Oct 30, 2018
51f3a7d
Merge branch 'master' into fix-recursion
c24t Nov 2, 2018
0a30edd
Set mock tracer's propagator in test
c24t Nov 2, 2018
92769df
Merge branch 'master' into fix-recursion
c24t Nov 2, 2018
e6c95da
Merge branch 'master' into fix-recursion
c24t Nov 7, 2018
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
21 changes: 21 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,29 @@ method, and status will be collected.

You can enable Requests integration by specifying ``'requests'`` to ``trace_integrations``.

It's possible to configure a list of URL you don't want traced. By default the request to exporter
won't be traced. It's configurable by giving an array of hostname/port to the attribute
``blacklist_hostnames`` in OpenCensus context's attributes:

.. code:: python

execution_context.set_opencensus_attr('blacklist_hostnames',['hostname:port'])

Only the hostname must be specified if only the hostname is specified in the URL request.

.. _Requests package: https://pypi.python.org/pypi/requests

Httplib
~~~~~~~~

Census can trace HTTP requests made with the httplib library.

You can enable Requests integration by specifying ``'httplib'`` to ``trace_integrations``.

It's possible to configure a list of URL you don't want traced. See requests integration
for more information. The only difference is that you need to specify hostname and port
every time.

Google Cloud Client Libraries
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
1 change: 1 addition & 0 deletions opencensus/trace/ext/django/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
'ZIPKIN_EXPORTER_PORT': 9411,
'ZIPKIN_EXPORTER_PROTOCOL': 'http',
'OCAGENT_TRACE_EXPORTER_ENDPOINT': None,
'BLACKLIST_HOSTNAMES': None,
'TRANSPORT': 'opencensus.trace.exporters.transports.sync.SyncTransport',
}

Expand Down
8 changes: 8 additions & 0 deletions opencensus/trace/ext/django/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
ZIPKIN_EXPORTER_PORT = 'ZIPKIN_EXPORTER_PORT'
ZIPKIN_EXPORTER_PROTOCOL = 'ZIPKIN_EXPORTER_PROTOCOL'
OCAGENT_TRACE_EXPORTER_ENDPOINT = 'OCAGENT_TRACE_EXPORTER_ENDPOINT'
BLACKLIST_HOSTNAMES = 'BLACKLIST_HOSTNAMES'

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -161,6 +162,9 @@ def __init__(self, get_response=None):
else:
self.exporter = self._exporter(transport=transport)

self.blacklist_hostnames = settings.params.get(
BLACKLIST_HOSTNAMES, None)

# Initialize the propagator
self.propagator = self._propagator()

Expand All @@ -179,6 +183,10 @@ def process_request(self, request):
REQUEST_THREAD_LOCAL_KEY,
request)

execution_context.set_opencensus_attr(
'blacklist_hostnames',
self.blacklist_hostnames)

try:
# Start tracing this request
span_context = self.propagator.from_headers(
Expand Down
5 changes: 5 additions & 0 deletions opencensus/trace/ext/flask/flask_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
ZIPKIN_EXPORTER_PORT = 'ZIPKIN_EXPORTER_PORT'
ZIPKIN_EXPORTER_PROTOCOL = 'ZIPKIN_EXPORTER_PROTOCOL'
OCAGENT_TRACE_EXPORTER_ENDPOINT = 'OCAGENT_TRACE_EXPORTER_ENDPOINT'
BLACKLIST_HOSTNAMES = 'BLACKLIST_HOSTNAMES'

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -165,6 +166,7 @@ def init_app(self, app):
else:
self.exporter = self.exporter(transport=transport)

self.blacklist_hostnames = params.get(BLACKLIST_HOSTNAMES, None)
# Initialize the propagator
if inspect.isclass(self.propagator):
self.propagator = self.propagator()
Expand Down Expand Up @@ -203,6 +205,9 @@ def _before_request(self):
tracer.add_attribute_to_current_span(
HTTP_METHOD, flask.request.method)
tracer.add_attribute_to_current_span(HTTP_URL, flask.request.url)
execution_context.set_opencensus_attr(
'blacklist_hostnames',
self.blacklist_hostnames)
except Exception: # pragma: NO COVER
log.error('Failed to trace request', exc_info=True)

Expand Down
9 changes: 8 additions & 1 deletion opencensus/trace/ext/httplib/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from opencensus.trace import attributes_helper
from opencensus.trace import execution_context
from opencensus.trace import span as span_module
from opencensus.trace.ext import utils

PYTHON2 = sys.version_info.major == 2

Expand Down Expand Up @@ -61,6 +62,12 @@ def wrap_httplib_request(request_func):

def call(self, method, url, body, headers, *args, **kwargs):
_tracer = execution_context.get_opencensus_tracer()
blacklist_hostnames = execution_context.get_opencensus_attr(
'blacklist_hostnames')
dest_url = '{}:{}'.format(self._dns_host, self.port)
if utils.disable_tracing_hostname(dest_url, blacklist_hostnames):
return request_func(self, method, url, body,
headers, *args, **kwargs)
_span = _tracer.start_span()
_span.span_kind = span_module.SpanKind.CLIENT
_span.name = '[httplib]{}'.format(request_func.__name__)
Expand Down Expand Up @@ -100,7 +107,7 @@ def call(self, *args, **kwargs):
span = _tracer.current_span()

# No corresponding request span is found, request not traced.
if span.span_id != current_span_id:
if not span or span.span_id != current_span_id:
return response_func(self, *args, **kwargs)

result = response_func(self, *args, **kwargs)
Expand Down
26 changes: 26 additions & 0 deletions opencensus/trace/ext/requests/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@
import logging
import requests
import wrapt
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse

from opencensus.trace import attributes_helper
from opencensus.trace import execution_context
from opencensus.trace import span as span_module
from opencensus.trace.ext import utils

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -56,6 +61,16 @@ def trace_integration(tracer=None):
def wrap_requests(requests_func):
"""Wrap the requests function to trace it."""
def call(url, *args, **kwargs):
blacklist_hostnames = execution_context.get_opencensus_attr(
'blacklist_hostnames')
parsed_url = urlparse(url)
if parsed_url.port is None:
dest_url = parsed_url.hostname
else:
dest_url = '{}:{}'.format(parsed_url.hostname, parsed_url.port)
if utils.disable_tracing_hostname(dest_url, blacklist_hostnames):
return requests_func(url, *args, **kwargs)

_tracer = execution_context.get_opencensus_tracer()
_span = _tracer.start_span()
_span.name = '[requests]{}'.format(requests_func.__name__)
Expand All @@ -80,6 +95,17 @@ def wrap_session_request(wrapped, instance, args, kwargs):
"""Wrap the session function to trace it."""
method = kwargs.get('method') or args[0]
url = kwargs.get('url') or args[1]

blacklist_hostnames = execution_context.get_opencensus_attr(
'blacklist_hostnames')
parsed_url = urlparse(url)
if parsed_url.port is None:
dest_url = parsed_url.hostname
else:
dest_url = '{}:{}'.format(parsed_url.hostname, parsed_url.port)
if utils.disable_tracing_hostname(dest_url, blacklist_hostnames):
return wrapped(*args, **kwargs)

_tracer = execution_context.get_opencensus_tracer()
_span = _tracer.start_span()

Expand Down
30 changes: 30 additions & 0 deletions opencensus/trace/ext/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import re

from opencensus.trace import execution_context

# By default the blacklist urls are not tracing, currently just include the
# health check url. The paths are literal string matched instead of regular
# expressions. Do not include the '/' at the beginning of the path.
Expand Down Expand Up @@ -63,3 +65,31 @@ def disable_tracing_url(url, blacklist_paths=None):
return True

return False


def disable_tracing_hostname(url, blacklist_hostnames=None):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can this be combined with the disable_tracing_url function in this file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am not sure. They both disable tracing but one is working on paths (blacklist path starting with an element from the list) and the other one with hostname (blacklist hostname/port exactly matching) with different default value. I think it's nice to have them separated for readability.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@liyanhui1228 Do you stand on your position on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's fine to separate them :)

"""Disable tracing for the provided blacklist URLs, by default not tracing
the exporter url.

If the url path starts with the blacklisted path, return True.

:type blacklist_hostnames: list
:param blacklist_hostnames: URL that not tracing.

:rtype: bool
:returns: True if not tracing, False if tracing.
"""
if blacklist_hostnames is None:
# Exporter host_name are not traced by default
_tracer = execution_context.get_opencensus_tracer()
try:
blacklist_hostnames = [
'{}:{}'.format(
_tracer.exporter.host_name,
_tracer.exporter.port
)
]
except(AttributeError):
blacklist_hostnames = []

return url in blacklist_hostnames
1 change: 1 addition & 0 deletions tests/unit/trace/ext/django/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def test__set_default_configs(self):
'ZIPKIN_EXPORTER_PORT': 9411,
'ZIPKIN_EXPORTER_PROTOCOL': 'http',
'OCAGENT_TRACE_EXPORTER_ENDPOINT': None,
'BLACKLIST_HOSTNAMES': None,
'TRANSPORT':
'opencensus.trace.exporters.transports.sync.SyncTransport',
}
Expand Down
80 changes: 79 additions & 1 deletion tests/unit/trace/ext/httplib/test_httplib_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,85 @@ def test_wrap_httplib_request(self):
self.assertEqual(expected_attributes,
mock_tracer.span.attributes)
self.assertEqual(expected_name, mock_tracer.span.name)
self.assertEqual(span_module.SpanKind.CLIENT, mock_tracer.span.span_kind)
self.assertEqual(span_module.SpanKind.CLIENT, mock_tracer.span.span_kind)

def test_wrap_httplib_request_blacklist_ok(self):
mock_span = mock.Mock()
span_id = '1234'
mock_span.span_id = span_id
mock_tracer = MockTracer(mock_span)
mock_request_func = mock.Mock()
mock_request_func.__name__ = 'request'

patch_tracer = mock.patch(
'opencensus.trace.ext.requests.trace.execution_context.'
'get_opencensus_tracer',
return_value=mock_tracer)
patch_attr = mock.patch(
'opencensus.trace.ext.requests.trace.execution_context.'
'get_opencensus_attr',
return_value=None)

wrapped = trace.wrap_httplib_request(mock_request_func)

mock_self = mock.Mock()
method = 'GET'
url = 'http://localhost:8080'
body = None
headers = {}

with patch_tracer, patch_attr:
wrapped(mock_self, method, url, body, headers)

expected_attributes = {
'http.url': url,
'http.method': method}
expected_name = '[httplib]request'

mock_request_func.assert_called_with(
mock_self, method, url, body, {
'traceparent': '00-123-456-01',
}
)

def test_wrap_httplib_request_blacklist_nok(self):
mock_span = mock.Mock()
span_id = '1234'
mock_span.span_id = span_id
mock_tracer = MockTracer(mock_span)
mock_request_func = mock.Mock()
mock_request_func.__name__ = 'request'

patch_tracer = mock.patch(
'opencensus.trace.ext.requests.trace.execution_context.'
'get_opencensus_tracer',
return_value=mock_tracer)
patch_attr = mock.patch(
'opencensus.trace.ext.requests.trace.execution_context.'
'get_opencensus_attr',
return_value=['localhost:8080'])

wrapped = trace.wrap_httplib_request(mock_request_func)

mock_self = mock.Mock()
mock_self._dns_host = 'localhost'
mock_self.port = '8080'
method = 'GET'
url = 'http://{}:{}'.format(mock_self._dns_host, mock_self.port)
body = None
headers = {}

with patch_tracer, patch_attr:
wrapped(mock_self, method, url, body, headers)

expected_attributes = {
'http.url': url,
'http.method': method}
expected_name = '[httplib]request'

mock_request_func.assert_called_with(
mock_self, method, url, body, {}
)

def test_wrap_httplib_response(self):
mock_span = mock.Mock()
Expand Down
Loading