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

aiohttp client tracing #1372

Closed
wants to merge 169 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
169 commits
Select commit Hold shift + click to select a range
907a086
Merge remote-tracking branch 'DataDog/master'
thehesiod Apr 12, 2017
ca55ba4
work on adding support for aiopg + aiobotocore + context patching
thehesiod Apr 12, 2017
26b708b
work on adding unittests
thehesiod Apr 12, 2017
cd7e57f
fix aiopg patching
thehesiod Apr 12, 2017
1bb231a
flake fixes
thehesiod Apr 12, 2017
837e8c2
fix comments
thehesiod Apr 12, 2017
4ebcc16
add distributed tracing support
thehesiod Apr 13, 2017
ad585cd
asyncio fixes
thehesiod Apr 13, 2017
79d71be
set span.error
thehesiod Apr 13, 2017
a7da295
add support for minimum response status to be considered an error
thehesiod Apr 13, 2017
e715c9f
add support for distributed aiobotocore spans
thehesiod Apr 13, 2017
7649d89
move to helpers
thehesiod Apr 13, 2017
c0ab3df
add ability to specify tracer and pep fixes
thehesiod Apr 14, 2017
d5562e1
wrap read method
thehesiod Apr 14, 2017
7b82dfc
populate read span's info
thehesiod Apr 14, 2017
8cc236e
add support for truncating arg values
thehesiod Apr 14, 2017
2b7c8f1
attempt to fix tests
thehesiod Apr 14, 2017
ca15385
bugfix
thehesiod Apr 14, 2017
ef9a5a0
fix unittests
thehesiod Apr 15, 2017
2c4fe87
fix unittest
thehesiod Apr 15, 2017
da5dc97
fix unittests
thehesiod Apr 15, 2017
9a5508e
flake fix
thehesiod Apr 15, 2017
df29727
fix tests
thehesiod Apr 15, 2017
13f8536
fix tests
thehesiod Apr 15, 2017
8c29099
fix aiopg unittests
thehesiod Apr 15, 2017
93c13a7
bugfix
thehesiod Apr 15, 2017
98480dd
remove await syntax support
thehesiod Apr 15, 2017
d3e49be
add flask dep
thehesiod Apr 15, 2017
0ce4b56
fix unittests
thehesiod Apr 15, 2017
b9ade72
Merge remote-tracking branch 'DataDog/master' into thehesiod-aio-utils
thehesiod May 4, 2017
28c67b6
Merge remote-tracking branch 'DataDog/master'
thehesiod May 4, 2017
64e71aa
aiohttp enhancements
thehesiod May 4, 2017
90b65e3
Merge remote-tracking branch 'DataDog/master'
thehesiod May 15, 2017
950d65c
Merge remote-tracking branch 'DataDog/master' into thehesiod-aio-utils
thehesiod May 15, 2017
064e4d4
add support for base parent span IDs
thehesiod May 15, 2017
5afcdc0
better asyncio task chaining
thehesiod May 16, 2017
b1257cc
add support for patterns
thehesiod May 16, 2017
78445de
add support for patterns
thehesiod May 16, 2017
69d59a9
set_traceback already sets this
thehesiod May 16, 2017
34bb4c9
set_traceback already sets this
thehesiod May 16, 2017
f82f666
bugfix
thehesiod May 17, 2017
8ec719d
bugfix
thehesiod May 17, 2017
f385deb
remove unused code
thehesiod May 19, 2017
79ed2e0
remove unused code
thehesiod May 19, 2017
e21d3ae
remove bad change
thehesiod May 19, 2017
c58b95b
remove bad change
thehesiod May 19, 2017
0107224
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp
thehesiod May 19, 2017
ecd49de
Merge remote-tracking branch 'DataDog/master' into thehesiod-aio-utils
thehesiod May 19, 2017
517d0be
Merge remote-tracking branch 'DataDog/master'
thehesiod May 25, 2017
2f1085e
Merge remote-tracking branch 'DataDog/master' into thehesiod-aio-utils
thehesiod May 25, 2017
3f7aa11
updates
thehesiod May 25, 2017
14823c3
Merge remote-tracking branch 'DataDog/master' into thehesiod-aio-utils
thehesiod May 31, 2017
8402096
Merge remote-tracking branch 'DataDog/master'
thehesiod May 31, 2017
4b29d60
Merge remote-tracking branch 'DataDog/master' into thehesiod-aio-utils
thehesiod Jun 7, 2017
77fdcc5
fix merge change
thehesiod Jun 7, 2017
3b7ce2f
Merge remote-tracking branch 'DataDog/master'
thehesiod Jun 8, 2017
efb5e08
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp
thehesiod Jun 8, 2017
766609a
Merge remote-tracking branch 'DataDog/master'
thehesiod Jun 14, 2017
a74ff3d
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp
thehesiod Jun 14, 2017
2285b98
Merge remote-tracking branch 'DataDog/master'
thehesiod Jun 20, 2017
c54c031
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp
thehesiod Jun 20, 2017
421e88d
changes based on slack chat w/ manu
thehesiod Jun 21, 2017
45b3f1b
remove whitespace
thehesiod Jun 21, 2017
2885f9b
Merge branch 'thehesiod-aiohttp' into thehesiod-aiohttp-client
thehesiod Jun 21, 2017
984eb96
add aiohttp client tracing support
thehesiod Jun 22, 2017
cb0e6a7
Merge remote-tracking branch 'DataDog/master' into thehesiod-aio-utils
thehesiod Jun 22, 2017
e977aa1
add aiohttp client tracing support
thehesiod Jun 22, 2017
260e54b
fix unittests
thehesiod Jun 22, 2017
f212020
fix unittests
thehesiod Jun 22, 2017
4eadc04
Merge branch 'thehesiod-aio-utils' into thehesiod-aiohttp
thehesiod Jun 22, 2017
249eea4
Revert "Merge branch 'thehesiod-aio-utils' into thehesiod-aiohttp"
thehesiod Jun 22, 2017
378c404
fix unittests
thehesiod Jun 23, 2017
1f71ae9
avoid unnecessary stringification
thehesiod Jun 23, 2017
caf025e
Merge branch 'thehesiod-aiohttp' into thehesiod-aiohttp-client
thehesiod Jun 23, 2017
71511f3
updates
thehesiod Jun 23, 2017
2e86f11
fix spacing
thehesiod Jun 23, 2017
e5924e7
we have to manually set the service
thehesiod Jun 24, 2017
5a39ced
add length
thehesiod Jun 24, 2017
eb046ce
ensure trace_headers applies to retries
thehesiod Jun 26, 2017
d1eca92
fix check
thehesiod Jun 26, 2017
e285168
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp-…
thehesiod Jul 2, 2017
e572209
revert changes
thehesiod Jul 2, 2017
e9d8056
revert more changes
thehesiod Jul 2, 2017
d823662
Merge remote-tracking branch 'DataDog/master'
thehesiod Jul 2, 2017
dd47c2c
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp-…
thehesiod Jul 3, 2017
8a7ce47
fix
thehesiod Jul 3, 2017
a019984
add parity with middleware
thehesiod Jul 3, 2017
c3b2cd9
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp-…
thehesiod Jul 6, 2017
ea3ba40
fix for parent spans
thehesiod Jul 6, 2017
c0ede6e
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp-…
thehesiod Nov 14, 2017
69739aa
switch to new mechanism
thehesiod Nov 20, 2017
0c0f379
cleanup
thehesiod Nov 20, 2017
aa03185
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp-…
thehesiod Jan 8, 2018
8ebd4a2
changes based on review
thehesiod Jan 8, 2018
5d747ba
update based on review
thehesiod Jan 8, 2018
be038a9
fix bug and unittests
thehesiod Jan 9, 2018
8b8c769
Merge remote-tracking branch 'DataDog/master'
thehesiod Jan 9, 2018
0f8e82c
ver bump
thehesiod Jan 9, 2018
58f78db
add short-circuit ability
thehesiod Jan 9, 2018
f3845d6
set error code on error like httplib
thehesiod Jan 9, 2018
09813da
missed a spot
thehesiod Jan 9, 2018
534d553
add missing aenter/aexit
thehesiod Jan 16, 2018
839e5dd
bugfix
thehesiod Jan 16, 2018
a6ab0c9
Merge remote-tracking branch 'DataDog/master'
thehesiod Jan 23, 2018
5af9b51
Merge remote-tracking branch 'DataDog/master'
thehesiod Feb 3, 2018
af07ff9
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp-…
thehesiod Feb 3, 2018
3f53e27
add connector tracing
thehesiod Feb 3, 2018
99fb053
fix port
thehesiod Feb 8, 2018
d3bc98e
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp-…
thehesiod Mar 10, 2018
ae9521c
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp-…
thehesiod Jun 14, 2018
2232332
bugfix
thehesiod Aug 10, 2018
e90a0a8
fix warnings
thehesiod Sep 19, 2018
d3b687d
flake fixes
thehesiod Oct 13, 2018
3aca41e
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp-…
thehesiod Oct 13, 2018
4e4e7e3
revert change
thehesiod Oct 13, 2018
50c487a
pull in changes from aio-utils
thehesiod Oct 13, 2018
6619697
add missing change
thehesiod Oct 13, 2018
3021151
tweak
thehesiod Oct 13, 2018
e13fb26
flake fixes
thehesiod Oct 13, 2018
d776869
Merge branch 'master' of https://github.com/DataDog/dd-trace-py
thehesiod Apr 4, 2019
550b804
Merge branch 'master' into thehesiod-aiohttp-client
thehesiod Apr 4, 2019
f2beee9
cherry pick 3982991dd8b8eaa4a537c3026e73c64e0463574c
thehesiod Apr 4, 2019
528bac5
fix merge
thehesiod Apr 4, 2019
3f169fa
flake fix
thehesiod Apr 4, 2019
ffeb9d3
fix flake
thehesiod Apr 4, 2019
ce78aad
fix tests
thehesiod Apr 4, 2019
51979e8
bugfix
thehesiod Apr 4, 2019
689c708
revert change
thehesiod Apr 8, 2019
304c40a
Merge branch 'master' of https://github.com/DataDog/dd-trace-py
thehesiod Apr 27, 2019
e8d93c4
Merge branch 'master' into thehesiod-aiohttp-client
thehesiod Apr 27, 2019
ed8996d
fix patch
thehesiod Jun 14, 2019
14a266f
Merge remote-tracking branch 'DataDog/master' into thehesiod-aiohttp-…
thehesiod Feb 27, 2020
dae156e
Merge remote-tracking branch 'hesiod/thehesiod-aiohttp-client' into a…
Kyle-Verhoog Mar 26, 2020
5da14d7
format and update tests
Kyle-Verhoog Mar 26, 2020
ff3e8f6
Merge remote-tracking branch 'DataDog/master' into aiohttp
thehesiod Apr 16, 2020
0f2a247
cleanup
thehesiod Apr 16, 2020
31df275
thehesiod aiohttp branch work (#1368)
thehesiod Apr 17, 2020
0028703
Merge remote-tracking branch 'origin/master' into aiohttp
Kyle-Verhoog Apr 17, 2020
c86cf18
Merge remote-tracking branch 'DataDog/aiohttp' into thehesiod/aiohttp
thehesiod Apr 17, 2020
6dfb0b0
merge fixes and ensure async tests are not skipped
thehesiod Apr 17, 2020
7566eb1
fix one more test
thehesiod Apr 17, 2020
1315c93
down to one failure
thehesiod Apr 17, 2020
85fa0cc
fix last test
thehesiod Apr 17, 2020
535cb59
bugfix
thehesiod Apr 17, 2020
1239e95
pull in fix from chrisb
thehesiod Apr 17, 2020
748a13d
fix for deprecated warnings
thehesiod Apr 17, 2020
3f89fe8
try to fix tests
thehesiod Apr 18, 2020
2b7629d
revert change
thehesiod Apr 18, 2020
2b7c919
fix tests
thehesiod Apr 18, 2020
fc98f0a
fix tests
thehesiod Apr 18, 2020
be861e5
clean up comments
Kyle-Verhoog Apr 21, 2020
28b53b3
remove fallback service
Kyle-Verhoog Apr 21, 2020
54eddb2
don't use defaults
Kyle-Verhoog Apr 21, 2020
08cb583
changes based on review
thehesiod Apr 21, 2020
ad8d45e
use config api
Kyle-Verhoog Apr 21, 2020
5023571
Merge branch 'thehesiod/aiohttp' of https://github.com/thehesiod/dd-t…
Kyle-Verhoog Apr 21, 2020
4dfe291
fix patch
thehesiod Apr 21, 2020
abb7853
fix tests
thehesiod May 11, 2020
5ba77f9
Merge remote-tracking branch 'DataDog/master' into thehesiod/aiohttp
thehesiod May 11, 2020
f422ad0
trace all read methods
thehesiod May 15, 2020
a732384
fix flake
thehesiod May 15, 2020
c7765fd
bug/flake fixes
thehesiod May 15, 2020
108e90a
add tracing of Request StreamReader
thehesiod May 19, 2020
5f4e19a
add missing aiter
thehesiod Jun 1, 2020
c24f472
add tracing of query string + fragment
thehesiod Jun 2, 2020
f7276cb
make query string default to off, and add support for redacting values
thehesiod Jun 2, 2020
54d7b2f
flake
thehesiod Jun 16, 2020
952e624
Merge remote-tracking branch 'DataDog/master' into thehesiod/aiohttp
thehesiod Jun 16, 2020
4a1d4b5
behave like requests
thehesiod Jun 17, 2020
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
215 changes: 128 additions & 87 deletions ddtrace/contrib/aiohttp/middlewares.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,124 @@
import asyncio
import functools

from ..asyncio import context_provider
from ...compat import stringify
from ...constants import ANALYTICS_SAMPLE_RATE_KEY, SPAN_MEASURED_KEY
from ...ext import SpanTypes, http
from ...propagation.http import HTTPPropagator
from ...pin import Pin
from ...settings import config
from ...context import Context
from ...utils.wrappers import iswrapped
from .patch import _WrappedStreamReader

try:
from aiohttp.web import middleware

CONFIG_KEY = 'datadog_trace'
REQUEST_CONTEXT_KEY = 'datadog_context'
REQUEST_CONFIG_KEY = '__datadog_trace_config'
REQUEST_SPAN_KEY = '__datadog_request_span'
AIOHTTP_HAS_MIDDLEWARE = True
except ImportError:
AIOHTTP_HAS_MIDDLEWARE = False

def middleware(f):
return f

@asyncio.coroutine
def trace_middleware(app, handler):
import aiohttp.streams


CONFIG_KEY = "datadog_trace"
REQUEST_CONTEXT_KEY = "datadog_context"
REQUEST_CONFIG_KEY = "__datadog_trace_config"
REQUEST_SPAN_KEY = "__datadog_request_span"

propagator = HTTPPropagator()


config._add("aiohttp_server", dict(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

should we instead make this two level?

ex: conf.add("aiohttp", dict(server=dict(...), client=(...)). otherwise is there any reason for using _ instead of . ?

service="aiohttp.server",
distributed_tracing_enabled=True,
))


@middleware
async def trace_middleware_2x(request, handler, app=None):
# application configs
if app is None:
app = request.app

tracer = app[CONFIG_KEY]["tracer"]
service = app[CONFIG_KEY]["service"]
distributed_tracing = app[CONFIG_KEY]["distributed_tracing_enabled"]

# Create a new context based on the propagated information.
if distributed_tracing:
context = propagator.extract(request.headers)

if context.trace_id:
tracer.context_provider.activate(context)
else:
# In case a non-distributed request comes after a distributed request we need to clear out
# the previous context
tracer.context_provider.activate(Context())
Copy link
Member

Choose a reason for hiding this comment

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

What's the reasoning here for clearing the context?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated description to state:

            # In case a non-distributed request comes after a distributed request we need to clear out
            # the previous context

Copy link
Contributor

@majorgreys majorgreys May 27, 2020

Choose a reason for hiding this comment

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

@thehesiod This should be handled by the ContextVars-enabled default context manager:

    def get(self):
        ctx = _DD_CONTEXTVAR.get()
        if not ctx:
            ctx = Context()
            self.set(ctx)


        return ctx

https://github.com/DataDog/dd-trace-py/blob/master/ddtrace/internal/context_manager.py#L92-L98


# trace the handler
request_span = tracer.trace("aiohttp.request", service=service, span_type=SpanTypes.WEB)
# Unset resource as we'll be setting this in all cases
request_span.resource = None

request_span.set_tag(SPAN_MEASURED_KEY)

# Configure trace search sample rate
analytics_enabled = app[CONFIG_KEY]["analytics_enabled"]
if (config.analytics_enabled and analytics_enabled is not False) or analytics_enabled is True:
request_span.set_tag(ANALYTICS_SAMPLE_RATE_KEY, app[CONFIG_KEY].get("analytics_sample_rate", True))

# attach the context and the root span to the request; the Context
# may be freely used by the application code
request[REQUEST_CONTEXT_KEY] = request_span.context
request[REQUEST_SPAN_KEY] = request_span
request[REQUEST_CONFIG_KEY] = app[CONFIG_KEY]

if request.match_info.route.resource:
# collect the resource name based on http resource type
res_info = request.match_info.route.resource.get_info()

resource = None
if res_info.get("path"):
resource = res_info.get("path")
elif res_info.get("formatter"):
resource = res_info.get("formatter")
elif res_info.get("prefix"):
resource = res_info.get("prefix")

if resource:
# prefix the resource name by the http method
resource = "{} {}".format(request.method, resource)
request_span.resource = resource

request_span.set_tag(http.METHOD, request.method)
request_span.set_tag(http.URL, request.url.with_query(None))
trace_query_string = request[REQUEST_CONFIG_KEY].get("trace_query_string")
if trace_query_string is None:
trace_query_string = config._http.trace_query_string
if trace_query_string:
request_span.set_tag(http.QUERY_STRING, request.query_string)

if not iswrapped(request._payload) and isinstance(request._payload, aiohttp.streams.StreamReader):
tags = {tag: request_span.get_tag(tag) for tag in {http.URL, http.METHOD, http.QUERY_STRING}
if request_span.get_tag(tag)}

pin = Pin(service, tracer=tracer, tags=tags, _config=config.aiohttp_server)
request._payload = _WrappedStreamReader(request._payload, pin, request_span.trace_id, request_span.span_id,
request_span.resource)

try:
response = await handler(request)
return response
except Exception:
request_span.set_traceback()
raise


async def trace_middleware_1x(app, handler):
"""
``aiohttp`` middleware that traces the handler execution.
Because handlers are run in different tasks for each request, we attach the Context
Expand All @@ -24,54 +127,13 @@ def trace_middleware(app, handler):
* the Task is used by the internal automatic instrumentation
* the ``Context`` attached to the request can be freely used in the application code
"""
@asyncio.coroutine
def attach_context(request):
# application configs
tracer = app[CONFIG_KEY]['tracer']
service = app[CONFIG_KEY]['service']
distributed_tracing = app[CONFIG_KEY]['distributed_tracing_enabled']

# Create a new context based on the propagated information.
if distributed_tracing:
propagator = HTTPPropagator()
context = propagator.extract(request.headers)
# Only need to active the new context if something was propagated
if context.trace_id:
tracer.context_provider.activate(context)

# trace the handler
request_span = tracer.trace(
'aiohttp.request',
service=service,
span_type=SpanTypes.WEB,
)
request_span.set_tag(SPAN_MEASURED_KEY)

# Configure trace search sample rate
# DEV: aiohttp is special case maintains separate configuration from config api
analytics_enabled = app[CONFIG_KEY]['analytics_enabled']
if (config.analytics_enabled and analytics_enabled is not False) or analytics_enabled is True:
request_span.set_tag(
ANALYTICS_SAMPLE_RATE_KEY,
app[CONFIG_KEY].get('analytics_sample_rate', True)
)

# attach the context and the root span to the request; the Context
# may be freely used by the application code
request[REQUEST_CONTEXT_KEY] = request_span.context
request[REQUEST_SPAN_KEY] = request_span
request[REQUEST_CONFIG_KEY] = app[CONFIG_KEY]
try:
response = yield from handler(request)
return response
except Exception:
request_span.set_traceback()
raise
return attach_context


@asyncio.coroutine
def on_prepare(request, response):
return functools.partial(trace_middleware_2x, handler=handler, app=app)


trace_middleware = trace_middleware_2x if AIOHTTP_HAS_MIDDLEWARE else trace_middleware_1x


async def on_prepare(request, response):
"""
The on_prepare signal is used to close the request span that is created during
the trace middleware execution.
Expand All @@ -82,39 +144,18 @@ def on_prepare(request, response):
return

# default resource name
resource = stringify(response.status)

if request.match_info.route.resource:
# collect the resource name based on http resource type
res_info = request.match_info.route.resource.get_info()

if res_info.get('path'):
resource = res_info.get('path')
elif res_info.get('formatter'):
resource = res_info.get('formatter')
elif res_info.get('prefix'):
resource = res_info.get('prefix')
if not request_span.resource:
request_span.resource = stringify(response.status)

# prefix the resource name by the http method
resource = '{} {}'.format(request.method, resource)
request_span.set_tag(http.STATUS_CODE, response.status)

if 500 <= response.status < 600:
request_span.error = 1

request_span.resource = resource
request_span.set_tag('http.method', request.method)
request_span.set_tag('http.status_code', response.status)
request_span.set_tag(http.URL, request.url.with_query(None))
# DEV: aiohttp is special case maintains separate configuration from config api
trace_query_string = request[REQUEST_CONFIG_KEY].get('trace_query_string')
if trace_query_string is None:
trace_query_string = config._http.trace_query_string
if trace_query_string:
request_span.set_tag(http.QUERY_STRING, request.query_string)
request_span.finish()


def trace_app(app, tracer, service='aiohttp-web'):
def trace_app(app, tracer, service="aiohttp-web"):
"""
Tracing function that patches the ``aiohttp`` application so that it will be
traced using the given ``tracer``.
Expand All @@ -125,17 +166,17 @@ def trace_app(app, tracer, service='aiohttp-web'):
"""

# safe-guard: don't trace an application twice
if getattr(app, '__datadog_trace', False):
if getattr(app, "__datadog_trace", False):
return
setattr(app, '__datadog_trace', True)
setattr(app, "__datadog_trace", True)

# configure datadog settings
app[CONFIG_KEY] = {
'tracer': tracer,
'service': config._get_service(default=service),
'distributed_tracing_enabled': True,
'analytics_enabled': None,
'analytics_sample_rate': 1.0,
"tracer": tracer,
"service": config._get_service(default=service),
"distributed_tracing_enabled": config.aiohttp_server.distributed_tracing_enabled,
"analytics_enabled": None,
"analytics_sample_rate": 1.0,
}

# the tracer must work with asynchronous Context propagation
Expand Down
Loading