Пример #1
0
def test_payload_too_large(encoding, monkeypatch):
    SIZE = 1 << 12  # 4KB
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)
    monkeypatch.setenv("DD_TRACE_WRITER_BUFFER_SIZE_BYTES", str(SIZE))
    monkeypatch.setenv("DD_TRACE_WRITER_MAX_PAYLOAD_SIZE_BYTES", str(SIZE))

    t = Tracer()
    assert t.writer._max_payload_size == SIZE
    assert t.writer._buffer_size == SIZE
    # Make sure a flush doesn't happen partway through.
    t.configure(
        writer=AgentWriter(agent.get_trace_url(), processing_interval=1000))
    with mock.patch("ddtrace.internal.writer.log") as log:
        for i in range(100000 if encoding == "v0.5" else 1000):
            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()
Пример #2
0
def test_metrics():
    with override_global_config(dict(health_metrics_enabled=True)):
        t = Tracer()
        statsd_mock = mock.Mock()
        t.writer.dogstatsd = statsd_mock
        assert t.writer._report_metrics
        with mock.patch("ddtrace.internal.writer.log") as log:
            for _ in range(5):
                spans = []
                for i in range(3000):
                    spans.append(t.trace("op"))
                for s in spans:
                    s.finish()

            t.shutdown()
            log.warning.assert_not_called()
            log.error.assert_not_called()

        statsd_mock.distribution.assert_has_calls(
            [
                mock.call("datadog.tracer.buffer.accepted.traces", 5, tags=[]),
                mock.call(
                    "datadog.tracer.buffer.accepted.spans", 15000, tags=[]),
                mock.call("datadog.tracer.http.requests", 1, tags=[]),
                mock.call("datadog.tracer.http.sent.bytes", AnyInt()),
            ],
            any_order=True,
        )
Пример #3
0
def test_partial_flush_log(run_python_code_in_subprocess):
    partial_flush_min_spans = 2
    t = Tracer()

    t.configure(
        partial_flush_enabled=True,
        partial_flush_min_spans=partial_flush_min_spans,
    )

    s1 = t.trace("1")
    s2 = t.trace("2")
    s3 = t.trace("3")
    t_id = s3.trace_id

    with mock.patch("ddtrace.internal.processor.trace.log") as log:
        s3.finish()
        s2.finish()

    calls = [
        mock.call("trace %d has %d spans, %d finished", t_id, 3, 1),
        mock.call("Partially flushing %d spans for trace %d",
                  partial_flush_min_spans, t_id),
    ]

    log.debug.assert_has_calls(calls)
    s1.finish()
    t.shutdown()
Пример #4
0
def test_priority_sampling_response(encoding, monkeypatch):
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)

    # 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
Пример #5
0
def test_bad_payload_log_payload(monkeypatch):
    monkeypatch.setenv("_DD_TRACE_WRITER_LOG_ERROR_PAYLOADS", "true")
    t = Tracer()

    class BadEncoder:
        def __len__(self):
            return 0

        def put(self, trace):
            pass

        def encode(self):
            return b"bad_payload"

        def encode_traces(self, traces):
            return b"bad_payload"

    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, payload %s",
            "http://localhost:8126/v0.4/traces",
            400,
            "Bad Request",
            "6261645f7061796c6f6164",
        )
    ]
    log.error.assert_has_calls(calls)
Пример #6
0
def test_bad_payload():
    t = Tracer()

    class BadEncoder:
        def __len__(self):
            return 0

        def put(self, trace):
            pass

        def encode(self):
            return ""

        def encode_traces(self, traces):
            return ""

    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)
Пример #7
0
def test_bad_encoder():
    t = Tracer()

    class BadEncoder:
        def __len__(self):
            return 0

        def put(self, trace):
            pass

        def encode(self):
            raise Exception()

        def encode_traces(self, traces):
            raise Exception()

    t.writer._encoder = BadEncoder()
    with mock.patch("ddtrace.internal.writer.log") as log:
        t.trace("asdf").finish()
        t.shutdown()
    calls = [
        mock.call("failed to encode trace with encoder %r",
                  t.writer._encoder,
                  exc_info=True)
    ]
    log.error.assert_has_calls(calls)
Пример #8
0
    def test_wrong_span_name_type_refused_by_agent(self):
        """Span names should be a text type."""
        tracer = Tracer()
        with mock.patch("ddtrace.internal.writer.log") as log:
            with tracer.trace(123):
                pass
            tracer.shutdown()

        self._assert_bad_trace_refused_by_agent(log)
Пример #9
0
def test_single_trace_uds():
    t = Tracer()
    sockdir = "/tmp/ddagent/trace.sock"
    t.configure(uds_path=sockdir)

    with mock.patch("ddtrace.internal.writer.log") as log:
        t.trace("client.testing").finish()
        t.shutdown()
        log.warning.assert_not_called()
        log.error.assert_not_called()
Пример #10
0
def test_uds_wrong_socket_path():
    t = Tracer()
    t.configure(uds_path="/tmp/ddagent/nosockethere")
    with mock.patch("ddtrace.internal.writer.log") as log:
        t.trace("client.testing").finish()
        t.shutdown()
    calls = [
        mock.call("failed to send traces to Datadog Agent at %s", "unix:///tmp/ddagent/nosockethere", exc_info=True)
    ]
    log.error.assert_has_calls(calls)
Пример #11
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)
Пример #12
0
def test_downgrade():
    t = Tracer()
    t.writer._downgrade(None, None)
    assert t.writer._endpoint == "/v0.3/traces"
    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()
Пример #13
0
 def test_simple_trace_accepted_by_agent(self):
     tracer = Tracer()
     with mock.patch("ddtrace.internal.writer.log") as log:
         with tracer.trace("root"):
             for _ in range(999):
                 with tracer.trace("child"):
                     pass
         tracer.shutdown()
     log.warning.assert_not_called()
     log.error.assert_not_called()
Пример #14
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)
Пример #15
0
    def test_trace_with_wrong_metrics_types_refused_by_agent(self, metrics):
        tracer = Tracer()
        with mock.patch("ddtrace.internal.writer.log") as log:
            with tracer.trace("root") as root:
                root.metrics = metrics
                for _ in range(499):
                    with tracer.trace("child") as child:
                        child.metrics = metrics
            tracer.shutdown()

        self._assert_bad_trace_refused_by_agent(log)
Пример #16
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()
Пример #17
0
def test_single_trace_uds(encoding, monkeypatch):
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)

    t = Tracer()
    sockdir = "/tmp/ddagent/trace.sock"
    t.configure(uds_path=sockdir)

    with mock.patch("ddtrace.internal.writer.log") as log:
        t.trace("client.testing").finish()
        t.shutdown()
        log.warning.assert_not_called()
        log.error.assert_not_called()
Пример #18
0
 def test_trace_with_meta_accepted_by_agent(self, tags):
     """Meta tags should be text types."""
     tracer = Tracer()
     with mock.patch("ddtrace.internal.writer.log") as log:
         with tracer.trace("root", service="test_encoding", resource="test_resource") as root:
             root.set_tags(tags)
             for _ in range(999):
                 with tracer.trace("child") as child:
                     child.set_tags(tags)
         tracer.shutdown()
     log.warning.assert_not_called()
     log.error.assert_not_called()
Пример #19
0
 def test_trace_with_metrics_accepted_by_agent(self, metrics):
     """Metric tags should be numeric types - i.e. int, float, long (py3), and str numbers."""
     tracer = Tracer()
     with mock.patch("ddtrace.internal.writer.log") as log:
         with tracer.trace("root") as root:
             root.set_metrics(metrics)
             for _ in range(999):
                 with tracer.trace("child") as child:
                     child.set_metrics(metrics)
         tracer.shutdown()
     log.warning.assert_not_called()
     log.error.assert_not_called()
Пример #20
0
def test_span_tags():
    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()
Пример #21
0
def test_large_payload():
    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()
Пример #22
0
def test_child_spans():
    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()
Пример #23
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()
Пример #24
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()
Пример #25
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()
Пример #26
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()
Пример #27
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)
Пример #28
0
def test_uds_wrong_socket_path(encoding, monkeypatch):
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)

    t = Tracer()
    t.configure(uds_path="/tmp/ddagent/nosockethere")
    with mock.patch("ddtrace.internal.writer.log") as log:
        t.trace("client.testing").finish()
        t.shutdown()
    calls = [
        mock.call(
            "failed to send traces to Datadog Agent at %s",
            "unix:///tmp/ddagent/nosockethere/{}/traces".format(
                encoding if encoding else "v0.4"),
            exc_info=True,
        )
    ]
    log.error.assert_has_calls(calls)
Пример #29
0
def test_single_trace_too_large(encoding, monkeypatch):
    monkeypatch.setenv("DD_TRACE_API_VERSION", encoding)

    t = Tracer()
    with mock.patch("ddtrace.internal.writer.log") as log:
        with t.trace("huge"):
            for i in range(200000):
                with t.trace("operation") as s:
                    s.set_tag("a" * 10, "b" * 10)
        t.shutdown()

        calls = [
            mock.call(
                "trace (%db) larger than payload buffer limit (%db), dropping",
                AnyInt(), AnyInt())
        ]
        log.warning.assert_has_calls(calls)
        log.error.assert_not_called()
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()