diff --git a/.circleci/config.yml b/.circleci/config.yml index 7584cb2a625..dcdc9da263f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -469,10 +469,12 @@ jobs: aiohttp: <<: *machine_executor + parallelism: 6 steps: - run_test: pattern: 'aiohttp' snapshot: true + docker_services: 'httpbin_local' asgi: <<: *contrib_job_small diff --git a/ddtrace/contrib/aiohttp/__init__.py b/ddtrace/contrib/aiohttp/__init__.py index 04ac34c72a6..fa81b649913 100644 --- a/ddtrace/contrib/aiohttp/__init__.py +++ b/ddtrace/contrib/aiohttp/__init__.py @@ -1,7 +1,43 @@ """ -The ``aiohttp`` integration traces all requests defined in the application handlers. +The ``aiohttp`` integration traces requests made with the client or to the server. -Automatic instrumentation is not available for ``aiohttp.web.Application``, instead +The client is automatically instrumented while the server must be manually instrumented using middleware. + +Client +****** + +Enabling +~~~~~~~~ + +The client integration is enabled automatically when using +:ref:`ddtrace-run` or :func:`patch_all()`. + +Or use :func:`patch()` to manually enable the integration:: + + from ddtrace import patch + patch(aiohttp=True) + + +Global Configuration +~~~~~~~~~~~~~~~~~~~~ + +.. py:data:: ddtrace.config.aiohttp_client['distributed_tracing'] + + Include distributed tracing headers in requests sent from the aiohttp client. + + This option can also be set with the ``DD_AIOHTTP_CLIENT_DISTRIBUTED_TRACING`` + environment variable. + + Default: ``True`` + + +Server +****** + +Enabling +~~~~~~~~ + +Automatic instrumentation is not available for the server, instead the provided ``trace_app`` function must be used:: from aiohttp import web diff --git a/ddtrace/contrib/aiohttp/patch.py b/ddtrace/contrib/aiohttp/patch.py index 17034bb86f1..7e7b5bcef5f 100644 --- a/ddtrace/contrib/aiohttp/patch.py +++ b/ddtrace/contrib/aiohttp/patch.py @@ -1,25 +1,139 @@ +import os + +from yarl import URL + from ddtrace import config from ddtrace.internal.logger import get_logger +from ddtrace.internal.utils import get_argument_value +from ddtrace.internal.utils.formats import asbool +from ddtrace.vendor import wrapt + +from ...ext import SpanTypes +from ...internal.compat import parse +from ...pin import Pin +from ...propagation.http import HTTPPropagator +from ..trace_utils import ext_service +from ..trace_utils import set_http_meta +from ..trace_utils import unwrap +from ..trace_utils import with_traced_module as with_traced_module_sync +from ..trace_utils import wrap +from ..trace_utils_async import with_traced_module log = get_logger(__name__) +# Server config config._add( "aiohttp", + dict(distributed_tracing=True), +) + +config._add( + "aiohttp_client", dict( - distributed_tracing=True, + distributed_tracing=asbool(os.getenv("DD_AIOHTTP_CLIENT_DISTRIBUTED_TRACING", True)), ), ) +class _WrappedConnectorClass(wrapt.ObjectProxy): + def __init__(self, obj, pin): + super().__init__(obj) + pin.onto(self) + + async def connect(self, req, *args, **kwargs): + pin = Pin.get_from(self) + with pin.tracer.trace("%s.connect" % self.__class__.__name__): + result = await self.__wrapped__.connect(req, *args, **kwargs) + return result + + async def _create_connection(self, req, *args, **kwargs): + pin = Pin.get_from(self) + with pin.tracer.trace("%s._create_connection" % self.__class__.__name__): + result = await self.__wrapped__._create_connection(req, *args, **kwargs) + return result + + +@with_traced_module +async def _traced_clientsession_request(aiohttp, pin, func, instance, args, kwargs): + method = get_argument_value(args, kwargs, 0, "method") # type: str + url = URL(get_argument_value(args, kwargs, 1, "url")) # type: URL + params = kwargs.get("params") + headers = kwargs.get("headers") or {} + + with pin.tracer.trace( + "aiohttp.request", span_type=SpanTypes.HTTP, service=ext_service(pin, config.aiohttp_client) + ) as span: + if pin._config["distributed_tracing"]: + HTTPPropagator.inject(span.context, headers) + kwargs["headers"] = headers + + # Params can be included separate of the URL so the URL has to be constructed + # with the passed params. + url_str = str(url.update_query(params) if params else url) + parsed_url = parse.urlparse(url_str) + set_http_meta( + span, + config.aiohttp_client, + method=method, + url=url_str, + query=parsed_url.query, + request_headers=headers, + ) + resp = await func(*args, **kwargs) # type: aiohttp.ClientResponse + set_http_meta( + span, config.aiohttp_client, response_headers=resp.headers, status_code=resp.status, status_msg=resp.reason + ) + return resp + + +@with_traced_module_sync +def _traced_clientsession_init(aiohttp, pin, func, instance, args, kwargs): + func(*args, **kwargs) + instance._connector = _WrappedConnectorClass(instance._connector, pin) + + +def _patch_client(aiohttp): + Pin().onto(aiohttp) + pin = Pin(_config=config.aiohttp_client.copy()) + pin.onto(aiohttp.ClientSession) + + wrap("aiohttp", "ClientSession.__init__", _traced_clientsession_init(aiohttp)) + wrap("aiohttp", "ClientSession._request", _traced_clientsession_request(aiohttp)) + + def patch(): + # Legacy patch aiohttp_jinja2 from ddtrace.contrib.aiohttp_jinja2 import patch as aiohttp_jinja2_patch aiohttp_jinja2_patch() + import aiohttp + + if getattr(aiohttp, "_datadog_patch", False): + return + + _patch_client(aiohttp) + + setattr(aiohttp, "_datadog_patch", True) + + +def _unpatch_client(aiohttp): + unwrap(aiohttp.ClientSession, "__init__") + unwrap(aiohttp.ClientSession, "_request") + def unpatch(): from ddtrace.contrib.aiohttp_jinja2 import unpatch as aiohttp_jinja2_unpatch aiohttp_jinja2_unpatch() + + import aiohttp + + if not getattr(aiohttp, "_datadog_patch", False): + return + + _unpatch_client(aiohttp) + + setattr(aiohttp, "_datadog_patch", False) diff --git a/ddtrace/contrib/trace_utils_async.py b/ddtrace/contrib/trace_utils_async.py new file mode 100644 index 00000000000..63a3325db50 --- /dev/null +++ b/ddtrace/contrib/trace_utils_async.py @@ -0,0 +1,39 @@ +""" +async tracing utils + +Note that this module should only be imported in Python 3.5+. +""" +from ddtrace import Pin +from ddtrace.internal.logger import get_logger + + +log = get_logger(__name__) + + +def with_traced_module(func): + """Async version of trace_utils.with_traced_module. + Usage:: + + @with_traced_module + async def my_traced_wrapper(django, pin, func, instance, args, kwargs): + # Do tracing stuff + pass + + def patch(): + import django + wrap(django.somefunc, my_traced_wrapper(django)) + """ + + def with_mod(mod): + async def wrapper(wrapped, instance, args, kwargs): + pin = Pin._find(instance, mod) + if pin and not pin.enabled(): + return await wrapped(*args, **kwargs) + elif not pin: + log.debug("Pin not found for traced method %r", wrapped) + return await wrapped(*args, **kwargs) + return await func(mod, pin, wrapped, instance, args, kwargs) + + return wrapper + + return with_mod diff --git a/docs/index.rst b/docs/index.rst index 13ee20e0133..8cac37c97ad 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -42,7 +42,9 @@ contacting support. +==================================================+===============+================+ | :ref:`aiobotocore` | >= 0.2.3 | No | +--------------------------------------------------+---------------+----------------+ -| :ref:`aiohttp` | >= 2.0 | No | +| :ref:`aiohttp` (client) | >= 2.0 | Yes | ++--------------------------------------------------+---------------+----------------+ +| :ref:`aiohttp` (server) | >= 2.0 | No | +--------------------------------------------------+---------------+----------------+ | :ref:`aiopg` | >= 0.12.0, | Yes | | | <= 0.16 | | diff --git a/releasenotes/notes/aiohttp-98ae9ce70dda1dbc.yaml b/releasenotes/notes/aiohttp-98ae9ce70dda1dbc.yaml new file mode 100644 index 00000000000..dd3838c41d5 --- /dev/null +++ b/releasenotes/notes/aiohttp-98ae9ce70dda1dbc.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + aiohttp: add client integration. This integration traces requests made using the aiohttp client and includes support + for distributed tracing. See `the documentation `_ + for more information. diff --git a/riotfile.py b/riotfile.py index d9689b3adc8..419153a1db8 100644 --- a/riotfile.py +++ b/riotfile.py @@ -1400,11 +1400,34 @@ def select_pys(min_version=MIN_PYTHON_VERSION, max_version=MAX_PYTHON_VERSION): }, ), Venv( - # Python 3.5 is deprecated for aiohttp >= 3.0 - pys=select_pys(min_version="3.6", max_version="3.9"), + # pytest-asyncio is incompatible with aiohttp 3.0+ in Python 3.6 + pys="3.6", + pkgs={ + "aiohttp": [ + "~=3.0", + "~=3.2", + "~=3.4", + "~=3.6", + "~=3.8", + latest, + ], + "aiohttp_jinja2": latest, + "yarl": "~=1.0", + }, + ), + Venv( + pys=select_pys(min_version="3.7", max_version="3.10"), pkgs={ - "aiohttp": ["~=3.0", "~=3.1", "~=3.2", "~=3.3", "~=3.4", "~=3.5", "~=3.6"], - "aiohttp_jinja2": "~=0.15", + "pytest-asyncio": [latest], + "aiohttp": [ + "~=3.0", + "~=3.2", + "~=3.4", + "~=3.6", + "~=3.8", + latest, + ], + "aiohttp_jinja2": latest, "yarl": "~=1.0", }, ), diff --git a/tests/contrib/aiohttp/conftest.py b/tests/contrib/aiohttp/conftest.py index 06f0b3afd84..1446e34643a 100644 --- a/tests/contrib/aiohttp/conftest.py +++ b/tests/contrib/aiohttp/conftest.py @@ -3,7 +3,7 @@ import pytest from ddtrace.contrib.aiohttp.middlewares import trace_app -from ddtrace.contrib.aiohttp.patch import patch +from ddtrace.contrib.aiohttp_jinja2.patch import patch as patch_jinja2 from ddtrace.internal.utils import version from ddtrace.pin import Pin @@ -24,7 +24,7 @@ def app_tracer(tracer, loop): @pytest.fixture def patched_app_tracer(app_tracer): - patch() + patch_jinja2() app, tracer = app_tracer Pin.override(aiohttp_jinja2, tracer=tracer) return app, tracer @@ -34,7 +34,7 @@ def patched_app_tracer(app_tracer): @pytest.fixture def untraced_app_tracer(tracer, loop): - patch() + patch_jinja2() app = setup_app() Pin.override(aiohttp_jinja2, tracer=tracer) return app, tracer @@ -53,7 +53,7 @@ async def app_tracer(tracer, loop): @pytest.fixture async def patched_app_tracer(app_tracer): - patch() + patch_jinja2() app, tracer = app_tracer Pin.override(aiohttp_jinja2, tracer=tracer) return app, tracer @@ -63,7 +63,7 @@ async def patched_app_tracer(app_tracer): @pytest.fixture async def untraced_app_tracer(tracer, loop): - patch() + patch_jinja2() app = setup_app() Pin.override(aiohttp_jinja2, tracer=tracer) return app, tracer diff --git a/tests/contrib/aiohttp/test_aiohttp_client.py b/tests/contrib/aiohttp/test_aiohttp_client.py new file mode 100644 index 00000000000..10264dd0cfe --- /dev/null +++ b/tests/contrib/aiohttp/test_aiohttp_client.py @@ -0,0 +1,189 @@ +import os +import sys + +import aiohttp +import pytest + +from ddtrace import Pin +from ddtrace.contrib.aiohttp import patch +from ddtrace.contrib.aiohttp import unpatch +from tests.utils import override_http_config + +from ..config import HTTPBIN_CONFIG + + +HOST = HTTPBIN_CONFIG["host"] +PORT = HTTPBIN_CONFIG["port"] +SOCKET = "{}:{}".format(HOST, PORT) +URL = "http://{}".format(SOCKET) +URL_200 = "{}/status/200".format(URL) +URL_500 = "{}/status/500".format(URL) + + +@pytest.fixture(autouse=True) +def patch_aiohttp_client(): + patch() + yield + unpatch() + + +@pytest.mark.asyncio +async def test_200_request(snapshot_context): + with snapshot_context(): + async with aiohttp.ClientSession() as session: + async with session.get(URL_200) as resp: + assert resp.status == 200 + + +@pytest.mark.asyncio +async def test_200_request_post(snapshot_context): + with snapshot_context(): + async with aiohttp.ClientSession() as session: + async with session.post(URL_200) as resp: + assert resp.status == 200 + + +@pytest.mark.asyncio +async def test_500_request(snapshot_context): + with snapshot_context(): + async with aiohttp.ClientSession() as session: + async with session.get(URL_500) as resp: + assert resp.status == 500 + + +@pytest.mark.asyncio +async def test_200_request_distributed_tracing(tracer): + async with aiohttp.ClientSession() as session: + async with session.get("%s/headers" % URL) as resp: + assert resp.status == 200 + headers = await resp.json() + for h in ("x-datadog-trace-id", "x-datadog-parent-id", "x-datadog-sampling-priority"): + assert h not in headers + + +@pytest.mark.asyncio +@pytest.mark.parametrize("variant", ["pin", "global"]) +async def test_distributed_tracing_disabled(ddtrace_run_python_code_in_subprocess, variant): + code = """ +import asyncio +import sys +import aiohttp +from ddtrace import Pin +from tests.contrib.aiohttp.test_aiohttp_client import URL + +async def test(): + async with aiohttp.ClientSession() as session: + async with session.get("%s/headers" % URL) as resp: + assert resp.status == 200 + headers = await resp.json() + + for h in ("x-datadog-trace-id", "x-datadog-parent-id", "x-datadog-sampling-priority"): + assert h not in headers + +if sys.version_info >= (3, 7, 0): + asyncio.run(test()) +else: + asyncio.get_event_loop().run_until_complete(test()) + """ + env = os.environ.copy() + if variant == "global": + env["DD_AIOHTTP_CLIENT_DISTRIBUTED_TRACING"] = "false" + out, err, status, pid = ddtrace_run_python_code_in_subprocess(code, env=env) + assert status == 0, err + assert err == b"" + + +@pytest.mark.snapshot(async_mode=False) +def test_configure_global_service_name_env(ddtrace_run_python_code_in_subprocess): + """ + When only setting DD_SERVICE + The value from DD_SERVICE is used + """ + code = """ +import asyncio +import sys +import aiohttp +from tests.contrib.aiohttp.test_aiohttp_client import URL_200 +async def test(): + async with aiohttp.ClientSession() as session: + async with session.get(URL_200) as resp: + pass + +if sys.version_info >= (3, 7, 0): + asyncio.run(test()) +else: + asyncio.get_event_loop().run_until_complete(test()) + """ + env = os.environ.copy() + env["DD_SERVICE"] = "global-service-name" + out, err, status, pid = ddtrace_run_python_code_in_subprocess(code, env=env) + assert status == 0, err + assert err == b"" + + +@pytest.mark.snapshot(async_mode=False) +def test_configure_service_name_pin(ddtrace_run_python_code_in_subprocess): + code = """ +import asyncio +import sys +import aiohttp +from ddtrace import Pin +from tests.contrib.aiohttp.test_aiohttp_client import URL_200 + +async def test(): + async with aiohttp.ClientSession() as session: + Pin.override(session, service="pin-custom-svc") + async with session.get(URL_200) as resp: + pass + +if sys.version_info >= (3, 7, 0): + asyncio.run(test()) +else: + asyncio.get_event_loop().run_until_complete(test()) + """ + out, err, status, pid = ddtrace_run_python_code_in_subprocess(code, env=os.environ.copy()) + assert status == 0, err + assert err == b"" + + +@pytest.mark.asyncio +@pytest.mark.skipif(sys.version_info < (3, 6, 0), reason="Python versions below 3.6 sort dictionaries differently") +async def test_trace_query_string(snapshot_context): + """ + When trace_query_string is enabled + The query string is included as a tag on the span + """ + with override_http_config("aiohttp_client", {"trace_query_string": True}): + with snapshot_context(): + async with aiohttp.ClientSession() as session: + async with session.get( + "%s/?k1=v1&k2=v2" % URL_200, + params={ + "k3": "v3", + "k4": "v4", + }, + ) as resp: + assert resp.status == 404 + + +@pytest.mark.asyncio +async def test_trace_parenting(snapshot_context): + pin = Pin.get_from(aiohttp) + tracer = pin.tracer + with snapshot_context(): + with tracer.trace("parent"): + async with aiohttp.ClientSession() as session: + async with session.get(URL_200) as resp: + assert resp.status == 200 + + +@pytest.mark.asyncio +async def test_trace_multiple(snapshot_context): + with snapshot_context(): + async with aiohttp.ClientSession() as session: + async with session.get(URL_200) as resp: + assert resp.status == 200 + async with session.get(URL_200) as resp: + assert resp.status == 200 + async with session.get(URL_200) as resp: + assert resp.status == 200 diff --git a/tests/contrib/config.py b/tests/contrib/config.py index 0abc5ea41bf..5d660c095bb 100644 --- a/tests/contrib/config.py +++ b/tests/contrib/config.py @@ -80,3 +80,8 @@ "password": os.getenv("TEST_RABBITMQ_PASSWORD", "guest"), "port": int(os.getenv("TEST_RABBITMQ_PORT", 5672)), } + +HTTPBIN_CONFIG = { + "host": "localhost", + "port": 8001, +} diff --git a/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_200_request.json b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_200_request.json new file mode 100644 index 00000000000..ad756672de0 --- /dev/null +++ b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_200_request.json @@ -0,0 +1,36 @@ +[[ + { + "name": "aiohttp.request", + "service": null, + "resource": "aiohttp.request", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "http", + "meta": { + "http.method": "GET", + "http.status_code": "200", + "http.status_msg": "OK", + "http.url": "http://localhost:8001/status/200", + "runtime-id": "b984b1b0f414444b914808157cba1e4d" + }, + "metrics": { + "_dd.agent_psr": 1.0, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "system.pid": 32687 + }, + "duration": 12671000, + "start": 1646414759574649000 + }, + { + "name": "TCPConnector.connect", + "service": null, + "resource": "TCPConnector.connect", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "duration": 7026000, + "start": 1646414759575827000 + }]] diff --git a/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_200_request_post.json b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_200_request_post.json new file mode 100644 index 00000000000..56a1a796372 --- /dev/null +++ b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_200_request_post.json @@ -0,0 +1,36 @@ +[[ + { + "name": "aiohttp.request", + "service": null, + "resource": "aiohttp.request", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "http", + "meta": { + "http.method": "POST", + "http.status_code": "200", + "http.status_msg": "OK", + "http.url": "http://localhost:8001/status/200", + "runtime-id": "d52ced09ce864933baf63a295ce898d8" + }, + "metrics": { + "_dd.agent_psr": 1.0, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "system.pid": 28240 + }, + "duration": 6568000, + "start": 1646794689782412000 + }, + { + "name": "TCPConnector.connect", + "service": null, + "resource": "TCPConnector.connect", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "duration": 2740000, + "start": 1646794689782860000 + }]] diff --git a/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_500_request.json b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_500_request.json new file mode 100644 index 00000000000..fd77511f48d --- /dev/null +++ b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_500_request.json @@ -0,0 +1,37 @@ +[[ + { + "name": "aiohttp.request", + "service": null, + "resource": "aiohttp.request", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "http", + "error": 1, + "meta": { + "http.method": "GET", + "http.status_code": "500", + "http.status_msg": "INTERNAL SERVER ERROR", + "http.url": "http://localhost:8001/status/500", + "runtime-id": "b984b1b0f414444b914808157cba1e4d" + }, + "metrics": { + "_dd.agent_psr": 1.0, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "system.pid": 32687 + }, + "duration": 6225000, + "start": 1646414759679627000 + }, + { + "name": "TCPConnector.connect", + "service": null, + "resource": "TCPConnector.connect", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "duration": 2061000, + "start": 1646414759680240000 + }]] diff --git a/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_configure_global_service_name_env.json b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_configure_global_service_name_env.json new file mode 100644 index 00000000000..001550ae0ee --- /dev/null +++ b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_configure_global_service_name_env.json @@ -0,0 +1,36 @@ +[[ + { + "name": "aiohttp.request", + "service": "global-service-name", + "resource": "aiohttp.request", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "http", + "meta": { + "http.method": "GET", + "http.status_code": "200", + "http.status_msg": "OK", + "http.url": "http://localhost:8001/status/200", + "runtime-id": "992426ee48034b75b0dc066b040d8810" + }, + "metrics": { + "_dd.agent_psr": 1.0, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "system.pid": 48841 + }, + "duration": 8008000, + "start": 1646721315459365000 + }, + { + "name": "TCPConnector.connect", + "service": "global-service-name", + "resource": "TCPConnector.connect", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "duration": 4452000, + "start": 1646721315459826000 + }]] diff --git a/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_configure_service_name_pin.json b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_configure_service_name_pin.json new file mode 100644 index 00000000000..177e6aceadc --- /dev/null +++ b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_configure_service_name_pin.json @@ -0,0 +1,36 @@ +[[ + { + "name": "aiohttp.request", + "service": "pin-custom-svc", + "resource": "aiohttp.request", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "http", + "meta": { + "http.method": "GET", + "http.status_code": "200", + "http.status_msg": "OK", + "http.url": "http://localhost:8001/status/200", + "runtime-id": "b13cb8dce9b247bcb2b3dfb5c2bdddbf" + }, + "metrics": { + "_dd.agent_psr": 1.0, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "system.pid": 49985 + }, + "duration": 22335000, + "start": 1646721987368402000 + }, + { + "name": "TCPConnector.connect", + "service": "pin-custom-svc", + "resource": "TCPConnector.connect", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "duration": 18051000, + "start": 1646721987369091000 + }]] diff --git a/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_trace_multiple.json b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_trace_multiple.json new file mode 100644 index 00000000000..b165e1571a5 --- /dev/null +++ b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_trace_multiple.json @@ -0,0 +1,108 @@ +[[ + { + "name": "aiohttp.request", + "service": null, + "resource": "aiohttp.request", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "http", + "meta": { + "http.method": "GET", + "http.status_code": "200", + "http.status_msg": "OK", + "http.url": "http://localhost:8001/status/200", + "runtime-id": "2d042941bd8e4cd18a0bcb6ea7c9b80f" + }, + "metrics": { + "_dd.agent_psr": 1.0, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "system.pid": 27506 + }, + "duration": 29211000, + "start": 1646794505597988000 + }, + { + "name": "TCPConnector.connect", + "service": null, + "resource": "TCPConnector.connect", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "duration": 26278000, + "start": 1646794505598411000 + }], +[ + { + "name": "aiohttp.request", + "service": null, + "resource": "aiohttp.request", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "http", + "meta": { + "http.method": "GET", + "http.status_code": "200", + "http.status_msg": "OK", + "http.url": "http://localhost:8001/status/200", + "runtime-id": "2d042941bd8e4cd18a0bcb6ea7c9b80f" + }, + "metrics": { + "_dd.agent_psr": 1.0, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "system.pid": 27506 + }, + "duration": 3596000, + "start": 1646794505627424000 + }, + { + "name": "TCPConnector.connect", + "service": null, + "resource": "TCPConnector.connect", + "trace_id": 1, + "span_id": 2, + "parent_id": 1, + "duration": 70000, + "start": 1646794505627940000 + }], +[ + { + "name": "aiohttp.request", + "service": null, + "resource": "aiohttp.request", + "trace_id": 2, + "span_id": 1, + "parent_id": 0, + "type": "http", + "meta": { + "http.method": "GET", + "http.status_code": "200", + "http.status_msg": "OK", + "http.url": "http://localhost:8001/status/200", + "runtime-id": "2d042941bd8e4cd18a0bcb6ea7c9b80f" + }, + "metrics": { + "_dd.agent_psr": 1.0, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "system.pid": 27506 + }, + "duration": 3312000, + "start": 1646794505631290000 + }, + { + "name": "TCPConnector.connect", + "service": null, + "resource": "TCPConnector.connect", + "trace_id": 2, + "span_id": 2, + "parent_id": 1, + "duration": 136000, + "start": 1646794505631851000 + }]] diff --git a/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_trace_parenting.json b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_trace_parenting.json new file mode 100644 index 00000000000..66cd2dea8f3 --- /dev/null +++ b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_trace_parenting.json @@ -0,0 +1,48 @@ +[[ + { + "name": "parent", + "service": null, + "resource": "parent", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "meta": { + "runtime-id": "93de13222bfa491d896a7fd6f40622e1" + }, + "metrics": { + "_dd.agent_psr": 1.0, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "system.pid": 27123 + }, + "duration": 6315000, + "start": 1646794413225857000 + }, + { + "name": "aiohttp.request", + "service": null, + "resource": "aiohttp.request", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "type": "http", + "meta": { + "http.method": "GET", + "http.status_code": "200", + "http.status_msg": "OK", + "http.url": "http://localhost:8001/status/200" + }, + "duration": 5716000, + "start": 1646794413226273000 + }, + { + "name": "TCPConnector.connect", + "service": null, + "resource": "TCPConnector.connect", + "trace_id": 0, + "span_id": 3, + "parent_id": 2, + "duration": 2464000, + "start": 1646794413226798000 + }]] diff --git a/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_trace_query_string.json b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_trace_query_string.json new file mode 100644 index 00000000000..63f2961cebe --- /dev/null +++ b/tests/snapshots/tests.contrib.aiohttp.test_aiohttp_client.test_trace_query_string.json @@ -0,0 +1,37 @@ +[[ + { + "name": "aiohttp.request", + "service": null, + "resource": "aiohttp.request", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "http", + "meta": { + "http.method": "GET", + "http.query.string": "k1=v1&k2=v2&k3=v3&k4=v4", + "http.status_code": "404", + "http.status_msg": "NOT FOUND", + "http.url": "http://localhost:8001/status/200/?k1=v1&k2=v2&k3=v3&k4=v4", + "runtime-id": "61df78e7f89c4a8f90049e780be97e8f" + }, + "metrics": { + "_dd.agent_psr": 1.0, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "system.pid": 83844 + }, + "duration": 5072000, + "start": 1646853117219334000 + }, + { + "name": "TCPConnector.connect", + "service": null, + "resource": "TCPConnector.connect", + "trace_id": 0, + "span_id": 2, + "parent_id": 1, + "duration": 1803000, + "start": 1646853117220225000 + }]]