mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-30 05:32:30 +08:00
193 lines
6.5 KiB
Python
193 lines
6.5 KiB
Python
import asyncio
|
|
import pytest
|
|
from opentracing.scope_managers.asyncio import AsyncioScopeManager
|
|
|
|
import ddtrace
|
|
from ddtrace.opentracer.utils import get_context_provider_for_scope_manager
|
|
|
|
from tests.contrib.asyncio.utils import AsyncioTestCase, mark_asyncio
|
|
from .conftest import ot_tracer_factory # noqa: F401
|
|
|
|
|
|
@pytest.fixture()
|
|
def ot_tracer(request, ot_tracer_factory): # noqa: F811
|
|
# use the dummy asyncio ot tracer
|
|
request.instance.ot_tracer = ot_tracer_factory(
|
|
'asyncio_svc',
|
|
config={},
|
|
scope_manager=AsyncioScopeManager(),
|
|
context_provider=ddtrace.contrib.asyncio.context_provider,
|
|
)
|
|
request.instance.ot_writer = request.instance.ot_tracer._dd_tracer.writer
|
|
request.instance.dd_tracer = request.instance.ot_tracer._dd_tracer
|
|
|
|
|
|
@pytest.mark.usefixtures('ot_tracer')
|
|
class TestTracerAsyncio(AsyncioTestCase):
|
|
|
|
def reset(self):
|
|
self.ot_writer.pop_traces()
|
|
|
|
@mark_asyncio
|
|
def test_trace_coroutine(self):
|
|
# it should use the task context when invoked in a coroutine
|
|
with self.ot_tracer.start_span('coroutine'):
|
|
pass
|
|
|
|
traces = self.ot_writer.pop_traces()
|
|
|
|
assert len(traces) == 1
|
|
assert len(traces[0]) == 1
|
|
assert traces[0][0].name == 'coroutine'
|
|
|
|
@mark_asyncio
|
|
def test_trace_multiple_coroutines(self):
|
|
# if multiple coroutines have nested tracing, they must belong
|
|
# to the same trace
|
|
@asyncio.coroutine
|
|
def coro():
|
|
# another traced coroutine
|
|
with self.ot_tracer.start_active_span('coroutine_2'):
|
|
return 42
|
|
|
|
with self.ot_tracer.start_active_span('coroutine_1'):
|
|
value = yield from coro()
|
|
|
|
# the coroutine has been called correctly
|
|
assert value == 42
|
|
# a single trace has been properly reported
|
|
traces = self.ot_writer.pop_traces()
|
|
assert len(traces) == 1
|
|
assert len(traces[0]) == 2
|
|
assert traces[0][0].name == 'coroutine_1'
|
|
assert traces[0][1].name == 'coroutine_2'
|
|
# the parenting is correct
|
|
assert traces[0][0] == traces[0][1]._parent
|
|
assert traces[0][0].trace_id == traces[0][1].trace_id
|
|
|
|
@mark_asyncio
|
|
def test_exception(self):
|
|
@asyncio.coroutine
|
|
def f1():
|
|
with self.ot_tracer.start_span('f1'):
|
|
raise Exception('f1 error')
|
|
|
|
with pytest.raises(Exception):
|
|
yield from f1()
|
|
|
|
traces = self.ot_writer.pop_traces()
|
|
assert len(traces) == 1
|
|
spans = traces[0]
|
|
assert len(spans) == 1
|
|
span = spans[0]
|
|
assert span.error == 1
|
|
assert span.get_tag('error.msg') == 'f1 error'
|
|
assert 'Exception: f1 error' in span.get_tag('error.stack')
|
|
|
|
@mark_asyncio
|
|
def test_trace_multiple_calls(self):
|
|
# create multiple futures so that we expect multiple
|
|
# traces instead of a single one (helper not used)
|
|
@asyncio.coroutine
|
|
def coro():
|
|
# another traced coroutine
|
|
with self.ot_tracer.start_span('coroutine'):
|
|
yield from asyncio.sleep(0.01)
|
|
|
|
futures = [asyncio.ensure_future(coro()) for x in range(10)]
|
|
for future in futures:
|
|
yield from future
|
|
|
|
traces = self.ot_writer.pop_traces()
|
|
|
|
assert len(traces) == 10
|
|
assert len(traces[0]) == 1
|
|
assert traces[0][0].name == 'coroutine'
|
|
|
|
|
|
@pytest.mark.usefixtures('ot_tracer')
|
|
class TestTracerAsyncioCompatibility(AsyncioTestCase):
|
|
"""Ensure the opentracer works in tandem with the ddtracer and asyncio."""
|
|
|
|
@mark_asyncio
|
|
def test_trace_multiple_coroutines_ot_dd(self):
|
|
"""
|
|
Ensure we can trace from opentracer to ddtracer across asyncio
|
|
context switches.
|
|
"""
|
|
# if multiple coroutines have nested tracing, they must belong
|
|
# to the same trace
|
|
@asyncio.coroutine
|
|
def coro():
|
|
# another traced coroutine
|
|
with self.dd_tracer.trace('coroutine_2'):
|
|
return 42
|
|
|
|
with self.ot_tracer.start_active_span('coroutine_1'):
|
|
value = yield from coro()
|
|
|
|
# the coroutine has been called correctly
|
|
assert value == 42
|
|
# a single trace has been properly reported
|
|
traces = self.ot_tracer._dd_tracer.writer.pop_traces()
|
|
assert len(traces) == 1
|
|
assert len(traces[0]) == 2
|
|
assert traces[0][0].name == 'coroutine_1'
|
|
assert traces[0][1].name == 'coroutine_2'
|
|
# the parenting is correct
|
|
assert traces[0][0] == traces[0][1]._parent
|
|
assert traces[0][0].trace_id == traces[0][1].trace_id
|
|
|
|
@mark_asyncio
|
|
def test_trace_multiple_coroutines_dd_ot(self):
|
|
"""
|
|
Ensure we can trace from ddtracer to opentracer across asyncio
|
|
context switches.
|
|
"""
|
|
# if multiple coroutines have nested tracing, they must belong
|
|
# to the same trace
|
|
@asyncio.coroutine
|
|
def coro():
|
|
# another traced coroutine
|
|
with self.ot_tracer.start_span('coroutine_2'):
|
|
return 42
|
|
|
|
with self.dd_tracer.trace('coroutine_1'):
|
|
value = yield from coro()
|
|
|
|
# the coroutine has been called correctly
|
|
assert value == 42
|
|
# a single trace has been properly reported
|
|
traces = self.ot_tracer._dd_tracer.writer.pop_traces()
|
|
assert len(traces) == 1
|
|
assert len(traces[0]) == 2
|
|
assert traces[0][0].name == 'coroutine_1'
|
|
assert traces[0][1].name == 'coroutine_2'
|
|
# the parenting is correct
|
|
assert traces[0][0] == traces[0][1]._parent
|
|
assert traces[0][0].trace_id == traces[0][1].trace_id
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
ddtrace.internal.context_manager.CONTEXTVARS_IS_AVAILABLE,
|
|
reason='only applicable to legacy asyncio provider'
|
|
)
|
|
class TestUtilsAsyncio(object):
|
|
"""Test the util routines of the opentracer with asyncio specific
|
|
configuration.
|
|
"""
|
|
|
|
def test_get_context_provider_for_scope_manager_asyncio(self):
|
|
scope_manager = AsyncioScopeManager()
|
|
ctx_prov = get_context_provider_for_scope_manager(scope_manager)
|
|
assert isinstance(
|
|
ctx_prov, ddtrace.contrib.asyncio.provider.AsyncioContextProvider
|
|
)
|
|
|
|
def test_tracer_context_provider_config(self):
|
|
tracer = ddtrace.opentracer.Tracer('mysvc', scope_manager=AsyncioScopeManager())
|
|
assert isinstance(
|
|
tracer._dd_tracer.context_provider,
|
|
ddtrace.contrib.asyncio.provider.AsyncioContextProvider,
|
|
)
|