Ejemplo n.º 1
0
def test_trace_top_level_span_processor_orphan_span():
    """Trace chuck does not contain parent span"""

    tracer = Tracer()
    tracer.configure(writer=DummyWriter())

    with tracer.trace("parent") as parent:
        pass

    with tracer.start_span("orphan span", child_of=parent) as orphan_span:
        pass

    # top_level in orphan_span should be explicitly set to zero/false
    assert orphan_span.get_metric("_dd.top_level") == 0
Ejemplo n.º 2
0
def test_priority_sampling_response():
    # Send the data once because the agent doesn't respond with them on the
    # first payload.
    t = Tracer()
    s = t.trace("operation", service="my-svc")
    s.set_tag("env", "my-env")
    s.finish()
    assert "service:my-svc,env:my-env" not in t.writer._priority_sampler._by_service_samplers
    t.shutdown()

    # For some reason the agent doesn't start returning the service information
    # immediately
    import time

    time.sleep(5)

    t = Tracer()
    s = t.trace("operation", service="my-svc")
    s.set_tag("env", "my-env")
    s.finish()
    assert "service:my-svc,env:my-env" not in t.writer._priority_sampler._by_service_samplers
    t.shutdown()
    assert "service:my-svc,env:my-env" in t.writer._priority_sampler._by_service_samplers
Ejemplo n.º 3
0
def test_span_tags(encoding, monkeypatch):
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)

    t = Tracer()
    with mock.patch("ddtrace.internal.writer.log") as log:
        s = t.trace("operation", service="my-svc")
        s.set_tag("env", "my-env")
        s.set_metric("number", 123)
        s.set_metric("number", 12.0)
        s.set_metric("number", "1")
        s.finish()
        t.shutdown()
    log.warning.assert_not_called()
    log.error.assert_not_called()
Ejemplo n.º 4
0
def test_large_payload(encoding, monkeypatch):
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)

    t = Tracer()
    # Traces are approx. 275 bytes.
    # 10,000*275 ~ 3MB
    with mock.patch("ddtrace.internal.writer.log") as log:
        for i in range(10000):
            with t.trace("operation"):
                pass

        t.shutdown()
        log.warning.assert_not_called()
        log.error.assert_not_called()
Ejemplo n.º 5
0
def test_child_spans(encoding, monkeypatch):
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)

    t = Tracer()
    with mock.patch("ddtrace.internal.writer.log") as log:
        spans = []
        for i in range(10000):
            spans.append(t.trace("op"))
        for s in spans:
            s.finish()

        t.shutdown()
        log.warning.assert_not_called()
        log.error.assert_not_called()
Ejemplo n.º 6
0
def test_bad_endpoint():
    t = Tracer()
    t.writer._endpoint = "/bad"
    with mock.patch("ddtrace.internal.writer.log") as log:
        s = t.trace("operation", service="my-svc")
        s.set_tag("env", "my-env")
        s.finish()
        t.shutdown()
    calls = [
        mock.call(
            "unsupported endpoint '%s': received response %s from Datadog Agent",
            "/bad", 404)
    ]
    log.error.assert_has_calls(calls)
Ejemplo n.º 7
0
def test_bad_payload():
    t = Tracer()

    class BadEncoder:
        def encode_trace(self, spans):
            return []

        def join_encoded(self, traces):
            return "not msgpack"

    t.writer._encoder = BadEncoder()
    with mock.patch("ddtrace.internal.writer.log") as log:
        t.trace("asdf").finish()
        t.shutdown()
    calls = [
        mock.call(
            "failed to send traces to Datadog Agent at %s: HTTP error status %s, reason %s",
            "http://localhost:8126",
            400,
            "Bad Request",
        )
    ]
    log.error.assert_has_calls(calls)
Ejemplo n.º 8
0
def test_writer_headers(encoding, monkeypatch):
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)

    t = Tracer()
    t.writer._put = mock.Mock(wraps=t.writer._put)
    with t.trace("op"):
        pass
    t.shutdown()
    assert t.writer._put.call_count == 1
    _, headers = t.writer._put.call_args[0]
    assert headers.get("Datadog-Meta-Tracer-Version") == ddtrace.__version__
    assert headers.get("Datadog-Meta-Lang") == "python"
    assert headers.get("Content-Type") == "application/msgpack"
    assert headers.get("X-Datadog-Trace-Count") == "1"
    if container.get_container_info():
        assert "Datadog-Container-Id" in headers

    t = Tracer()
    t.writer._put = mock.Mock(wraps=t.writer._put)
    for _ in range(100):
        with t.trace("op"):
            pass
    t.shutdown()
    assert t.writer._put.call_count == 1
    _, headers = t.writer._put.call_args[0]
    assert headers.get("X-Datadog-Trace-Count") == "100"

    t = Tracer()
    t.writer._put = mock.Mock(wraps=t.writer._put)
    for _ in range(10):
        with t.trace("op"):
            for _ in range(5):
                t.trace("child").finish()
    t.shutdown()
    assert t.writer._put.call_count == 1
    _, headers = t.writer._put.call_args[0]
    assert headers.get("X-Datadog-Trace-Count") == "10"
Ejemplo n.º 9
0
def test_single_trace_too_large():
    t = Tracer()
    with mock.patch("ddtrace.internal.writer.log") as log:
        with t.trace("huge"):
            for i in range(100000):
                with tracer.trace("operation") as s:
                    s.set_tag("a" * 10, "b" * 10)
        t.shutdown()

        calls = [
            mock.call("trace (%db) larger than payload limit (%db), dropping",
                      AnyInt(), AnyInt())
        ]
        log.warning.assert_has_calls(calls)
        log.error.assert_not_called()
Ejemplo n.º 10
0
def test_trace_bad_url():
    t = Tracer()
    t.configure(hostname="bad", port=1111)

    with mock.patch("ddtrace.internal.writer.log") as log:
        with t.trace("op"):
            pass
        t.shutdown()

    calls = [
        mock.call("failed to send traces to Datadog Agent at %s",
                  "http://bad:1111",
                  exc_info=True)
    ]
    log.error.assert_has_calls(calls)
Ejemplo n.º 11
0
def test_trace_top_level_span_processor_partial_flushing():
    """Parent span and child span have the same service name"""
    tracer = Tracer()
    tracer.configure(
        partial_flush_enabled=True,
        partial_flush_min_spans=2,
        writer=DummyWriter(),
    )

    with tracer.trace("parent") as parent:
        with tracer.trace("1") as child1:
            pass
        with tracer.trace("2") as child2:
            pass
        with tracer.trace("3") as child3:
            pass

    # child spans 1 and 2 were partial flushed WITHOUT the parent span in the trace chunk
    assert child1.get_metric("_dd.top_level") == 0
    assert child2.get_metric("_dd.top_level") == 0

    # child span 3 was partial flushed WITH the parent span in the trace chunk
    assert "_dd.top_level" not in child3.metrics
    assert parent.get_metric("_dd.top_level") == 1
Ejemplo n.º 12
0
def test_downgrade(encoding, monkeypatch):
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)

    t = Tracer()
    t.writer._downgrade(None, None)
    assert t.writer._endpoint == {
        "v0.5": "v0.4/traces",
        "v0.4": "v0.3/traces"
    }[encoding or "v0.4"]
    with mock.patch("ddtrace.internal.writer.log") as log:
        s = t.trace("operation", service="my-svc")
        s.finish()
        t.shutdown()
    log.warning.assert_not_called()
    log.error.assert_not_called()
Ejemplo n.º 13
0
def test_trace_bad_url(encoding, monkeypatch):
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)

    t = Tracer()
    t.configure(hostname="bad", port=1111)

    with mock.patch("ddtrace.internal.writer.log") as log:
        with t.trace("op"):
            pass
        t.shutdown()

    calls = [
        mock.call("failed to send traces to Datadog Agent at %s",
                  "http://bad:1111",
                  exc_info=True)
    ]
    log.error.assert_has_calls(calls)
def test_tracer_trace_across_fork():
    """
    When a trace is started in a parent process and a child process is spawned
        The trace should be continued in the child process
    """
    tracer = Tracer()

    def task(tracer):
        with tracer.trace("child"):
            pass
        tracer.shutdown()

    with tracer.trace("parent"):
        p = multiprocessing.Process(target=task, args=(tracer, ))
        p.start()
        p.join()

    tracer.shutdown()
Ejemplo n.º 15
0
 def test_get_log_correlation_context(self, global_config):
     """Ensure expected DDLogRecord is generated via get_correlation_log_record."""
     with tracer.trace("test-span-1") as span1:
         dd_log_record = tracer.get_log_correlation_context()
     assert dd_log_record == {
         "span_id": str(span1.span_id),
         "trace_id": str(span1.trace_id),
         "service": "test-service",
         "env": "test-env",
         "version": "test-version",
     }
     test_tracer = Tracer()
     with test_tracer.trace("test-span-2") as span2:
         dd_log_record = test_tracer.get_log_correlation_context()
     assert dd_log_record == {
         "span_id": str(span2.span_id),
         "trace_id": str(span2.trace_id),
         "service": "test-service",
         "env": "test-env",
         "version": "test-version",
     }
Ejemplo n.º 16
0
def test_payload_too_large():
    t = Tracer()
    # Make sure a flush doesn't happen partway through.
    t.configure(writer=AgentWriter(processing_interval=1000))
    with mock.patch("ddtrace.internal.writer.log") as log:
        for i in range(100000):
            with t.trace("operation") as s:
                s.set_tag(str(i), "b" * 190)
                s.set_tag(str(i), "a" * 190)

        t.shutdown()
        calls = [
            mock.call(
                "trace buffer (%s traces %db/%db) cannot fit trace of size %db, dropping",
                AnyInt(),
                AnyInt(),
                AnyInt(),
                AnyInt(),
            )
        ]
        log.warning.assert_has_calls(calls)
        log.error.assert_not_called()
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 = Tracer()

    def task(tracer):
        def task2(tracer):
            with tracer.trace("child2"):
                pass
            tracer.shutdown()

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

    with tracer.trace("parent"):
        p = multiprocessing.Process(target=task, args=(tracer, ))
        p.start()
        p.join()
    tracer.shutdown()