Пример #1
0
def tracer_and_collector():
    t = ddtrace.Tracer()
    r = recorder.Recorder()
    c = stack.StackCollector(r, tracer=t)
    c.start()
    try:
        yield t, c
    finally:
        c.stop()
Пример #2
0
def test_tracer_shutdown_timeout():
    t = ddtrace.Tracer()
    t.writer = mock.Mock(wraps=t.writer)

    with t.trace("something"):
        pass

    t.shutdown(timeout=2)
    t.writer.stop.assert_called_once_with(timeout=2)
Пример #3
0
 def test_tracer_info_level_log(self):
     logging.basicConfig(level=logging.INFO)
     tracer = ddtrace.Tracer()
     tracer.log = mock.MagicMock()
     tracer.configure()
     assert tracer.log.log.mock_calls == [
         mock.call(logging.INFO,
                   re_matcher("- DATADOG TRACER CONFIGURATION - "))
     ]
Пример #4
0
 def test_tags_from_DD_TAGS_override(self):
     t = ddtrace.Tracer()
     ddtrace.config.env = "env"
     ddtrace.config.service = "service"
     ddtrace.config.version = "0.123"
     with t.trace("test") as s:
         assert s.service == "service"
         assert s.get_tag("env") == "env"
         assert s.get_tag("version") == "0.123"
Пример #5
0
def test_ctx():
    tracer = ddtrace.Tracer()
    tracer.writer = DummyWriter()

    with tracer.trace("test") as s1:
        assert tracer.current_span() == s1
        assert tracer.current_root_span() == s1
        assert tracer.get_call_context().trace_id == s1.trace_id
        assert tracer.get_call_context().span_id == s1.span_id

        with tracer.trace("test2") as s2:
            assert tracer.current_span() == s2
            assert tracer.current_root_span() == s1
            assert tracer.get_call_context().trace_id == s1.trace_id
            assert tracer.get_call_context().span_id == s2.span_id

            with tracer.trace("test3") as s3:
                assert tracer.current_span() == s3
                assert tracer.current_root_span() == s1
                assert tracer.get_call_context().trace_id == s1.trace_id
                assert tracer.get_call_context().span_id == s3.span_id

            assert tracer.get_call_context().trace_id == s1.trace_id
            assert tracer.get_call_context().span_id == s2.span_id

        with tracer.trace("test4") as s4:
            assert tracer.current_span() == s4
            assert tracer.current_root_span() == s1
            assert tracer.get_call_context().trace_id == s1.trace_id
            assert tracer.get_call_context().span_id == s4.span_id

        assert tracer.current_span() == s1
        assert tracer.current_root_span() == s1

    assert tracer.current_span() is None
    assert tracer.current_root_span() is None
    assert s1.parent_id is None
    assert s2.parent_id == s1.span_id
    assert s3.parent_id == s2.span_id
    assert s4.parent_id == s1.span_id
    assert s1.trace_id == s2.trace_id == s3.trace_id == s4.trace_id
    assert s1.metrics[SAMPLING_PRIORITY_KEY] == 1
    assert SAMPLING_PRIORITY_KEY not in s2.metrics
    assert ORIGIN_KEY not in s1.meta

    t = tracer.writer.pop_traces()
    assert len(t) == 1
    assert len(t[0]) == 4
    _s1, _s2, _s3, _s4 = t[0]
    assert s1 == _s1
    assert s2 == _s2
    assert s3 == _s3
    assert s4 == _s4

    with tracer.trace("s") as s:
        assert s.parent_id is None
        assert s.trace_id != s1.trace_id
Пример #6
0
def tracer_and_collector(monkeypatch):
    monkeypatch.setenv("DD_TRACE_STARTUP_LOGS", "0")
    t = ddtrace.Tracer()
    r = recorder.Recorder()
    c = stack.StackCollector(r, tracer=t)
    c.start()
    try:
        yield t, c
    finally:
        c.stop()
Пример #7
0
 def test_tracer_loglevel_info_no_connection(self):
     tracer = ddtrace.Tracer()
     tracer.log = mock.MagicMock()
     tracer.configure()
     # Python 2 logs will go to stderr directly since there's no log handler
     if ddtrace.compat.PY3:
         assert tracer.log.log.mock_calls == [
             mock.call(logging.INFO, re_matcher("- DATADOG TRACER CONFIGURATION - ")),
             mock.call(logging.WARNING, re_matcher("- DATADOG TRACER DIAGNOSTIC - ")),
         ]
Пример #8
0
def test_tracer_configure_writer_stop_started():
    t = ddtrace.Tracer()
    t.writer = mock.Mock(wraps=t.writer)
    orig_writer = t.writer

    # Do a write to start the writer
    with t.trace("something"):
        pass

    t.configure(hostname="localhost", port=8126)
    orig_writer.stop.assert_called_once_with()
Пример #9
0
def test_start_span_hooks():
    t = ddtrace.Tracer()

    result = {}

    @t.on_start_span
    def store_span(span):
        result["span"] = span

    span = t.start_span("hello")

    assert span == result["span"]
Пример #10
0
 def test_tracer_loglevel_info_no_connection_py2_handler(self):
     tracer = ddtrace.Tracer()
     tracer.log = mock.MagicMock()
     logging.basicConfig()
     tracer.configure()
     if ddtrace.compat.PY2:
         assert tracer.log.log.mock_calls == [
             mock.call(logging.INFO,
                       re_matcher("- DATADOG TRACER CONFIGURATION - ")),
             mock.call(logging.WARNING,
                       re_matcher("- DATADOG TRACER DIAGNOSTIC - ")),
         ]
Пример #11
0
def test_tracer_url():
    t = ddtrace.Tracer()
    assert t.writer.api.hostname == 'localhost'
    assert t.writer.api.port == 8126

    t = ddtrace.Tracer(url='http://foobar:12')
    assert t.writer.api.hostname == 'foobar'
    assert t.writer.api.port == 12

    t = ddtrace.Tracer(url='unix:///foobar')
    assert t.writer.api.uds_path == '/foobar'

    t = ddtrace.Tracer(url='http://localhost')
    assert t.writer.api.hostname == 'localhost'
    assert t.writer.api.port == 80
    assert not t.writer.api.https

    t = ddtrace.Tracer(url='https://localhost')
    assert t.writer.api.hostname == 'localhost'
    assert t.writer.api.port == 443
    assert t.writer.api.https

    with pytest.raises(ValueError) as e:
        t = ddtrace.Tracer(url='foo://foobar:12')
        assert str(e) == 'Unknown scheme `https` for agent URL'
Пример #12
0
def test_tracer_url():
    t = ddtrace.Tracer()
    assert t.writer._hostname == "localhost"
    assert t.writer._port == 8126

    t = ddtrace.Tracer(url="http://foobar:12")
    assert t.writer._hostname == "foobar"
    assert t.writer._port == 12

    t = ddtrace.Tracer(url="unix:///foobar")
    assert t.writer._uds_path == "/foobar"

    t = ddtrace.Tracer(url="http://localhost")
    assert t.writer._hostname == "localhost"
    assert t.writer._port == 80
    assert not t.writer._https

    t = ddtrace.Tracer(url="https://localhost")
    assert t.writer._hostname == "localhost"
    assert t.writer._port == 443
    assert t.writer._https

    with pytest.raises(ValueError) as e:
        t = ddtrace.Tracer(url="foo://foobar:12")
        assert str(e) == "Unknown scheme `https` for agent URL"
Пример #13
0
 def test_tracer_loglevel_info_no_connection(self):
     tracer = ddtrace.Tracer()
     logging.basicConfig(level=logging.INFO)
     with mock.patch.object(logging.Logger, "log") as mock_logger:
         tracer.configure()
     # Python 2 logs will go to stderr directly since there's no log handler
     if PY3:
         assert mock.call(logging.INFO,
                          re_matcher("- DATADOG TRACER CONFIGURATION - ")
                          ) in mock_logger.mock_calls
         assert mock.call(logging.WARNING,
                          re_matcher("- DATADOG TRACER DIAGNOSTIC - ")
                          ) in mock_logger.mock_calls
Пример #14
0
def test_tracer_trace_across_multiple_forks():
    """
    When a trace is started and crosses multiple process boundaries
        The trace should be continued in the child processes
    """
    tracer = ddtrace.Tracer()
    tracer.writer = DummyWriter()

    # Start a span in this process then start a child process which itself
    # starts a span and spawns another child process which starts a span.
    def task(tracer, q):
        tracer.writer = DummyWriter()

        def task2(tracer, q):
            tracer.writer = DummyWriter()

            with tracer.trace("child2"):
                pass

            spans = tracer.writer.pop()
            q.put([
                dict(trace_id=s.trace_id, parent_id=s.parent_id) for s in spans
            ])

        with tracer.trace("child1"):
            q2 = multiprocessing.Queue()
            p = multiprocessing.Process(target=task2, args=(tracer, q2))
            p.start()
            p.join()

        task2_spans = q2.get()
        spans = tracer.writer.pop()
        q.put([
            dict(trace_id=s.trace_id, parent_id=s.parent_id, span_id=s.span_id)
            for s in spans
        ] + task2_spans)

    # Assert tracer in a new process correctly recreates the writer
    q = multiprocessing.Queue()
    with tracer.trace("parent") as parent:
        p = multiprocessing.Process(target=task, args=(tracer, q))
        p.start()
        p.join()

    children = q.get()
    assert len(children) == 2
    child1, child2 = children
    assert parent.trace_id == child1["trace_id"] == child2["trace_id"]
    assert child1["parent_id"] == parent.span_id
    assert child2["parent_id"] == child1["span_id"]
Пример #15
0
def test_deregister_start_span_hooks():
    t = ddtrace.Tracer()

    result = {}

    @t.on_start_span
    def store_span(span):
        result["span"] = span

    t.deregister_on_start_span(store_span)

    t.start_span("hello")

    assert result == {}
Пример #16
0
def test_tracer_shutdown_no_timeout():
    t = ddtrace.Tracer()
    t.writer = mock.Mock(wraps=t.writer)

    # The writer thread does not start until the first write.
    t.shutdown()
    assert not t.writer.stop.called
    assert not t.writer.join.called

    # Do a write to start the writer.
    with t.trace("something"):
        pass
    t.shutdown()
    t.writer.stop.assert_called_once_with()
    t.writer.join.assert_called_once_with(timeout=None)
Пример #17
0
def test_startup_logs_sampling_rules():
    tracer = ddtrace.Tracer()
    sampler = ddtrace.sampler.DatadogSampler(rules=[ddtrace.sampler.SamplingRule(sample_rate=1.0)])
    tracer.configure(sampler=sampler)
    f = debug.collect(tracer)

    assert f.get("sampler_rules") == ["SamplingRule(sample_rate=1.0, service='NO_RULE', name='NO_RULE')"]

    sampler = ddtrace.sampler.DatadogSampler(
        rules=[ddtrace.sampler.SamplingRule(sample_rate=1.0, service="xyz", name="abc")]
    )
    tracer.configure(sampler=sampler)
    f = debug.collect(tracer)

    assert f.get("sampler_rules") == ["SamplingRule(sample_rate=1.0, service='xyz', name='abc')"]
Пример #18
0
def test_partial_flush_log():
    tracer = ddtrace.Tracer()

    tracer.configure(
        partial_flush_enabled=True,
        partial_flush_min_spans=300,
    )

    f = debug.collect(tracer)

    partial_flush_enabled = f.get("partial_flush_enabled")
    partial_flush_min_spans = f.get("partial_flush_min_spans")

    assert partial_flush_enabled is True
    assert partial_flush_min_spans == 300
Пример #19
0
def test_tracer_fork():
    t = ddtrace.Tracer()
    original_pid = t._pid
    original_writer = t.writer

    @contextlib.contextmanager
    def capture_failures(errors):
        try:
            yield
        except AssertionError as e:
            errors.put(e)

    def task(t, errors):
        # Start a new span to trigger process checking
        with t.trace('test', service='test') as span:

            # Assert we recreated the writer and have a new queue
            with capture_failures(errors):
                assert t._pid != original_pid
                assert t.writer != original_writer
                assert t.writer._trace_queue != original_writer._trace_queue

        # Assert the trace got written into the correct queue
        assert original_writer._trace_queue.qsize() == 0
        assert t.writer._trace_queue.qsize() == 1
        assert [[span]] == list(t.writer._trace_queue.get())

    # Assert tracer in a new process correctly recreates the writer
    errors = multiprocessing.Queue()
    p = multiprocessing.Process(target=task, args=(t, errors))
    try:
        p.start()
    finally:
        p.join(timeout=2)

    while errors.qsize() > 0:
        raise errors.get()

    # Ensure writing into the tracer in this process still works as expected
    with t.trace('test', service='test') as span:
        assert t._pid == original_pid
        assert t.writer == original_writer
        assert t.writer._trace_queue == original_writer._trace_queue

    # Assert the trace got written into the correct queue
    assert original_writer._trace_queue.qsize() == 1
    assert t.writer._trace_queue.qsize() == 1
    assert [[span]] == list(t.writer._trace_queue.get())
Пример #20
0
def test_early_exit():
    t = ddtrace.Tracer()
    s1 = t.trace("1")
    s2 = t.trace("2")
    s1.finish()
    s2.finish()
    assert s1.parent_id is None
    assert s2.parent_id is s1.span_id

    s1 = t.trace("1-1")
    s1.finish()
    assert s1.parent_id is None

    s1 = t.trace("1-2")
    s1.finish()
    assert s1.parent_id is None
Пример #21
0
def test_tracer_runtime_tags_fork():
    tracer = ddtrace.Tracer()

    def task(tracer, q):
        span = tracer.start_span("foobaz")
        q.put(span.get_tag("runtime-id"))

    span = tracer.start_span("foobar")

    q = multiprocessing.Queue()
    p = multiprocessing.Process(target=task, args=(tracer, q))
    p.start()
    p.join()

    children_tag = q.get()
    assert children_tag != span.get_tag("runtime-id")
Пример #22
0
def test_tracer_fork():
    t = ddtrace.Tracer()
    original_pid = t._pid
    original_writer = t.writer

    @contextlib.contextmanager
    def capture_failures(errors):
        try:
            yield
        except AssertionError as e:
            errors.put(e)

    def task(t, errors):
        # Start a new span to trigger process checking
        with t.trace("test", service="test"):

            # Assert we recreated the writer and have a new queue
            with capture_failures(errors):
                assert t._pid != original_pid
                assert t.writer != original_writer
                assert t.writer._buffer != original_writer._buffer

        # Assert the trace got written into the correct queue
        assert len(original_writer._buffer) == 0
        assert len(t.writer._buffer) == 1

    # Assert tracer in a new process correctly recreates the writer
    errors = multiprocessing.Queue()
    p = multiprocessing.Process(target=task, args=(t, errors))
    try:
        p.start()
    finally:
        p.join(timeout=2)

    assert errors.empty(), errors.get()

    # Ensure writing into the tracer in this process still works as expected
    with t.trace("test", service="test"):
        assert t._pid == original_pid
        assert t.writer == original_writer
        assert t.writer._buffer == original_writer._buffer

    # Assert the trace got written into the correct queue
    assert len(original_writer._buffer) == 1
    assert len(t.writer._buffer) == 1
Пример #23
0
def test_runtime_id_parent_only():
    tracer = ddtrace.Tracer()

    # Parent spans should have runtime-id
    s = tracer.trace("test")
    rtid = s.get_tag("runtime-id")
    assert isinstance(rtid, six.string_types)

    # Child spans should not
    s2 = tracer.trace("test2")
    assert s2.get_tag("runtime-id") is None
    s2.finish()
    s.finish()

    # Parent spans should have runtime-id
    s = tracer.trace("test")
    rtid = s.get_tag("runtime-id")
    assert isinstance(rtid, six.string_types)
Пример #24
0
def test_custom_writer():
    tracer = ddtrace.Tracer()

    class CustomWriter(TraceWriter):
        def recreate(self):
            # type: () -> TraceWriter
            return self

        def stop(self, timeout=None):
            # type: (Optional[float]) -> None
            pass

        def write(self, spans=None):
            # type: (Optional[List[Span]]) -> None
            pass

    tracer.writer = CustomWriter()
    info = debug.collect(tracer)

    assert info.get("agent_url") == "CUSTOM"
Пример #25
0
def test_early_exit():
    t = ddtrace.Tracer()
    t.writer = DummyWriter()
    s1 = t.trace("1")
    s2 = t.trace("2")
    s1.finish()
    s2.finish()
    assert s1.parent_id is None
    assert s2.parent_id is s1.span_id

    traces = t.writer.pop_traces()
    assert len(traces) == 1
    assert len(traces[0]) == 2

    s1 = t.trace("1-1")
    s1.finish()
    assert s1.parent_id is None

    s1 = t.trace("1-2")
    s1.finish()
    assert s1.parent_id is None
Пример #26
0
def test_ctx_distributed():
    tracer = ddtrace.Tracer()
    tracer.writer = DummyWriter()

    # Test activating an invalid context.
    ctx = Context(span_id=None, trace_id=None)
    tracer.context_provider.activate(ctx)
    assert tracer.current_span() is None

    with tracer.trace("test") as s1:
        assert tracer.current_span() == s1
        assert tracer.current_root_span() == s1
        assert tracer.get_call_context().trace_id == s1.trace_id
        assert tracer.get_call_context().span_id == s1.span_id
        assert s1.parent_id is None

    trace = tracer.writer.pop_traces()
    assert len(trace) == 1

    # Test activating a valid context.
    ctx = Context(span_id=1234,
                  trace_id=4321,
                  sampling_priority=2,
                  _dd_origin="somewhere")
    tracer.context_provider.activate(ctx)
    assert tracer.current_span() is None

    with tracer.trace("test2") as s2:
        assert tracer.current_span() == s2
        assert tracer.current_root_span() == s2
        assert tracer.get_call_context().trace_id == s2.trace_id == 4321
        assert tracer.get_call_context().span_id == s2.span_id
        assert s2.parent_id == 1234

    trace = tracer.writer.pop_traces()
    assert len(trace) == 1
    assert s2.metrics[SAMPLING_PRIORITY_KEY] == 2
    assert s2.meta[ORIGIN_KEY] == "somewhere"
Пример #27
0
def test_excepthook():
    class Foobar(Exception):
        pass

    called = {}

    def original(type, value, traceback):
        called['yes'] = True

    sys.excepthook = original
    ddtrace.install_excepthook()

    e = Foobar()

    tracer = ddtrace.Tracer()
    tracer._dogstatsd_client = mock.Mock()
    with override_global_tracer(tracer):
        sys.excepthook(e.__class__, e, None)

    tracer._dogstatsd_client.increment.assert_has_calls((
        mock.call('datadog.tracer.uncaught_exceptions', 1, tags=['class:Foobar']),
    ))
    assert called
Пример #28
0
def test_runtime_id_fork():
    tracer = ddtrace.Tracer()

    s = tracer.trace("test")
    s.finish()

    rtid = s.get_tag("runtime-id")
    assert isinstance(rtid, six.string_types)

    pid = os.fork()

    if pid == 0:
        # child
        s = tracer.trace("test")
        s.finish()

        rtid_child = s.get_tag("runtime-id")
        assert isinstance(rtid_child, six.string_types)
        assert rtid != rtid_child
        os._exit(12)

    _, status = os.waitpid(pid, 0)
    exit_code = os.WEXITSTATUS(status)
    assert exit_code == 12
Пример #29
0
def test_multithreaded():
    tracer = ddtrace.Tracer()
    tracer.writer = DummyWriter()

    def target():
        with tracer.trace("s1"):
            with tracer.trace("s2"):
                pass
            with tracer.trace("s3"):
                pass

    for i in range(1000):
        ts = [threading.Thread(target=target) for _ in range(10)]
        for t in ts:
            t.start()

        for t in ts:
            t.join()

        traces = tracer.writer.pop_traces()
        assert len(traces) == 10

        for trace in traces:
            assert len(trace) == 3
Пример #30
0
def test_tracer_url():
    t = ddtrace.Tracer()
    assert t.writer.agent_url == "http://localhost:8126"

    t = ddtrace.Tracer(url="http://foobar:12")
    assert t.writer.agent_url == "http://foobar:12"

    t = ddtrace.Tracer(url="unix:///foobar")
    assert t.writer.agent_url == "unix:///foobar"

    t = ddtrace.Tracer(url="http://localhost")
    assert t.writer.agent_url == "http://localhost:80"

    t = ddtrace.Tracer(url="https://localhost")
    assert t.writer.agent_url == "https://localhost:443"

    with pytest.raises(ValueError) as e:
        ddtrace.Tracer(url="foo://foobar:12")
        assert str(e) == "Unknown scheme `https` for agent URL"