예제 #1
0
    def test_patch_unpatch(self):
        tracer = DummyTracer()

        # Test patch idempotence
        patch()
        patch()

        r = redis.Redis(port=REDIS_CONFIG["port"])
        Pin.get_from(r).clone(tracer=tracer).onto(r)
        r.get("key")

        spans = tracer.pop()
        assert spans, spans
        assert len(spans) == 1

        # Test unpatch
        unpatch()

        r = redis.Redis(port=REDIS_CONFIG["port"])
        r.get("key")

        spans = tracer.pop()
        assert not spans, spans

        # Test patch again
        patch()

        r = redis.Redis(port=REDIS_CONFIG["port"])
        Pin.get_from(r).clone(tracer=tracer).onto(r)
        r.get("key")

        spans = tracer.pop()
        assert spans, spans
        assert len(spans) == 1
예제 #2
0
 def setUp(self):
     self.tracer = DummyTracer()
     self.traced_app = TraceMiddleware(
         cherrypy,
         self.tracer,
         service="test.cherrypy.service",
         distributed_tracing=True,
     )
예제 #3
0
def tracer():
    tracer = DummyTracer()
    if sys.version_info < (3, 7):
        # enable legacy asyncio support
        from ddtrace.contrib.asyncio.provider import AsyncioContextProvider

        tracer.configure(context_provider=AsyncioContextProvider())
    yield tracer
예제 #4
0
def test_redis_legacy():
    # ensure the old interface isn't broken, but doesn't trace
    tracer = DummyTracer()
    TracedRedisCache = get_traced_redis(tracer, "foo")
    r = TracedRedisCache(port=REDIS_CONFIG["port"])
    r.set("a", "b")
    got = r.get("a")
    assert compat.to_unicode(got) == "b"
    assert not tracer.pop()
예제 #5
0
    def make_ot_tracer(service_name="my_svc", config=None, scope_manager=None, context_provider=None):
        config = config or {}
        tracer = Tracer(service_name=service_name, config=config, scope_manager=scope_manager)

        # similar to how we test the ddtracer, use a dummy tracer
        dd_tracer = DummyTracer()
        if context_provider:
            dd_tracer.configure(context_provider=context_provider)

        # attach the dummy tracer to the opentracer
        tracer._dd_tracer = dd_tracer
        return tracer
예제 #6
0
def tracer():
    original_tracer = ddtrace.tracer
    tracer = DummyTracer()
    if sys.version_info < (3, 7):
        # enable legacy asyncio support
        from ddtrace.contrib.asyncio.provider import AsyncioContextProvider

        tracer.configure(context_provider=AsyncioContextProvider())
    setattr(ddtrace, "tracer", tracer)
    patch()
    yield tracer
    setattr(ddtrace, "tracer", original_tracer)
    unpatch()
예제 #7
0
def nop_tracer():
    from ddtrace.opentracer import Tracer

    tracer = Tracer(service_name="mysvc", config={})
    # use the same test tracer used by the primary tests
    tracer._tracer = DummyTracer()
    return tracer
예제 #8
0
 def test_log_unfinished_spans_disabled(self, log):
     # the trace finished status logging is disabled
     tracer = DummyTracer()
     ctx = Context()
     # manually create a root-child trace
     root = Span(tracer=tracer, name="root")
     child_1 = Span(tracer=tracer,
                    name="child_1",
                    trace_id=root.trace_id,
                    parent_id=root.span_id)
     child_2 = Span(tracer=tracer,
                    name="child_2",
                    trace_id=root.trace_id,
                    parent_id=root.span_id)
     child_1._parent = root
     child_2._parent = root
     ctx.add_span(root)
     ctx.add_span(child_1)
     ctx.add_span(child_2)
     # close only the parent
     root.finish()
     # the logger has never been invoked to print unfinished spans
     for call, _ in log.call_args_list:
         msg = call[0]
         assert "the trace has %d unfinished spans" not in msg
예제 #9
0
    def test_inject(self):
        tracer = DummyTracer()

        ctx = Context(trace_id=1234,
                      sampling_priority=2,
                      dd_origin="synthetics")
        tracer.context_provider.activate(ctx)
        with tracer.trace("global_root_span") as span:
            headers = {}
            HTTPPropagator.inject(span.context, headers)

            assert int(headers[HTTP_HEADER_TRACE_ID]) == span.trace_id
            assert int(headers[HTTP_HEADER_PARENT_ID]) == span.span_id
            assert int(headers[HTTP_HEADER_SAMPLING_PRIORITY]
                       ) == span.context.sampling_priority
            assert headers[HTTP_HEADER_ORIGIN] == span.context.dd_origin
예제 #10
0
def test_pre_v4():
    tracer = DummyTracer()
    MySQL = get_traced_pymysql_connection(tracer, service="my-mysql-server")
    conn = MySQL(**config.MYSQL_CONFIG)
    cursor = conn.cursor()
    cursor.execute("SELECT 1")
    assert cursor.fetchone()[0] == 1
예제 #11
0
    def test_extract(self):
        tracer = DummyTracer()

        headers = {
            "x-datadog-trace-id": "1234",
            "x-datadog-parent-id": "5678",
            "x-datadog-sampling-priority": "1",
            "x-datadog-origin": "synthetics",
        }

        context = HTTPPropagator.extract(headers)
        tracer.context_provider.activate(context)

        with tracer.trace("local_root_span") as span:
            assert span.trace_id == 1234
            assert span.parent_id == 5678
            assert span.context.sampling_priority == 1
            assert span.context.dd_origin == "synthetics"
예제 #12
0
def tracer_with_debug_logging():
    # All the tracers, dummy or not, shares the same logging object.
    tracer = DummyTracer()
    level = tracer.log.level
    tracer.log.setLevel(logging.DEBUG)
    try:
        yield tracer
    finally:
        tracer.log.setLevel(level)
예제 #13
0
    def test_WSGI_extract(self):
        """Ensure we support the WSGI formatted headers as well."""
        tracer = DummyTracer()

        headers = {
            "HTTP_X_DATADOG_TRACE_ID": "1234",
            "HTTP_X_DATADOG_PARENT_ID": "5678",
            "HTTP_X_DATADOG_SAMPLING_PRIORITY": "1",
            "HTTP_X_DATADOG_ORIGIN": "synthetics",
        }

        context = HTTPPropagator.extract(headers)
        tracer.context_provider.activate(context)

        with tracer.trace("local_root_span") as span:
            assert span.trace_id == 1234
            assert span.parent_id == 5678
            assert span.context.sampling_priority == 1
            assert span.context.dd_origin == "synthetics"
예제 #14
0
 def test_log_unfinished_spans_when_ok(self, log):
     # if the unfinished spans logging is enabled but the trace is finished, don't log anything
     tracer = DummyTracer()
     ctx = Context()
     # manually create a root-child trace
     root = Span(tracer=tracer, name="root")
     child = Span(tracer=tracer,
                  name="child_1",
                  trace_id=root.trace_id,
                  parent_id=root.span_id)
     child._parent = root
     ctx.add_span(root)
     ctx.add_span(child)
     # close the trace
     child.finish()
     root.finish()
     # the logger has never been invoked to print unfinished spans
     for call, _ in log.call_args_list:
         msg = call[0]
         assert "the trace has %d unfinished spans" not in msg
예제 #15
0
def get_dummy_tracer():
    return DummyTracer()
예제 #16
0
def tracer():
    return DummyTracer()
예제 #17
0
def tracer():
    tracer = DummyTracer()
    return tracer
예제 #18
0
class TestCherrypy(helper.CPWebCase):
    """
    FIXME: the tests using getPage() are not synchronous and so require a
           delay afterwards.
    """
    @staticmethod
    def setup_server():
        cherrypy.tree.mount(
            TestApp(),
            "/",
            {
                "/": {
                    "tools.tracer.on": True
                },
            },
        )

    def setUp(self):
        self.tracer = DummyTracer()
        self.traced_app = TraceMiddleware(
            cherrypy,
            self.tracer,
            service="test.cherrypy.service",
            distributed_tracing=True,
        )

    def test_double_instrumentation(self):
        # ensure CherryPy is never instrumented twice when `ddtrace-run`
        # and `TraceMiddleware` are used together. `traced_app` MUST
        # be assigned otherwise it's not possible to reproduce the
        # problem (the test scope must keep a strong reference)
        traced_app = TraceMiddleware(cherrypy, self.tracer)  # noqa: F841
        self.getPage("/")
        time.sleep(0.1)
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertStatus("200 OK")

        spans = self.tracer.writer.pop()
        assert len(spans) == 1

    def test_double_instrumentation_config(self):
        # ensure CherryPy uses the last set configuration to be sure
        # there are no breaking changes for who uses `ddtrace-run`
        # with the `TraceMiddleware`
        assert cherrypy.tools.tracer.service == "test.cherrypy.service"
        TraceMiddleware(
            cherrypy,
            self.tracer,
            service="new-intake",
        )
        self.getPage("/")
        time.sleep(0.1)
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertStatus("200 OK")

        spans = self.tracer.writer.pop()
        assert len(spans) == 1

        assert cherrypy.tools.tracer.service == "new-intake"

    def test_child(self):
        self.getPage("/child")
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody("child")

        # ensure trace worked
        spans = self.tracer.writer.pop()
        assert len(spans) == 2

        spans_by_name = {s.name: s for s in spans}

        s = spans_by_name["cherrypy.request"]
        assert s.span_id
        assert s.trace_id
        assert not s.parent_id
        assert s.service == "test.cherrypy.service"
        assert s.resource == "GET /child"
        assert s.error == 0

        c = spans_by_name["child"]
        assert c.span_id
        assert c.trace_id == s.trace_id
        assert c.parent_id == s.span_id
        assert c.service == "test.cherrypy.service"
        assert c.resource == "child"
        assert c.error == 0

    def test_success(self):
        self.getPage("/")
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody("Hello world!")

        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "test.cherrypy.service"
        assert s.resource == "GET /"
        assert s.error == 0
        assert_span_http_status_code(s, 200)
        assert s.meta.get(http.METHOD) == "GET"

    def test_alias(self):
        self.getPage("/aliases")
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody("alias")

        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "test.cherrypy.service"
        assert s.resource == "GET /aliases"
        assert s.error == 0
        assert_span_http_status_code(s, 200)
        assert s.meta.get(http.METHOD) == "GET"

    def test_handleme(self):
        self.getPage("/handleme")
        time.sleep(0.1)
        self.assertErrorPage(418, message="handled")

        # ensure trace worked
        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "test.cherrypy.service"
        assert s.resource == "GET /handleme"
        assert s.error == 0
        assert_span_http_status_code(s, 418)
        assert s.meta.get(http.METHOD) == "GET"

    def test_error(self):
        self.getPage("/error")
        time.sleep(0.1)
        self.assertErrorPage(500)

        # ensure the request was traced.
        assert not self.tracer.current_span()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "test.cherrypy.service"
        assert s.resource == "GET /error"
        assert_span_http_status_code(s, 500)
        assert s.error == 1
        assert s.meta.get(http.METHOD) == "GET"

    def test_fatal(self):
        self.getPage("/fatal")
        time.sleep(0.1)

        self.assertErrorPage(500)

        assert not self.tracer.current_span()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "test.cherrypy.service"
        assert s.resource == "GET /fatal"
        assert_span_http_status_code(s, 500)
        assert s.error == 1
        assert s.meta.get(http.METHOD) == "GET"
        assert "ZeroDivisionError" in s.meta.get(errors.ERROR_TYPE), s.meta
        assert "by zero" in s.meta.get(errors.ERROR_MSG)
        assert re.search(
            'File ".*/contrib/cherrypy/web.py", line [0-9]+, in fatal',
            s.meta.get(errors.ERROR_STACK))

    def test_unicode(self):
        # Encoded utf8 query strings MUST be parsed correctly.
        # Here, the URL is encoded in utf8 and then %HEX
        # See https://docs.cherrypy.org/en/latest/_modules/cherrypy/test/test_encoding.html for more
        self.getPage(url_quote(u"/üŋïĉóđē".encode("utf-8")))
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody(
            b"\xc3\xbc\xc5\x8b\xc3\xaf\xc4\x89\xc3\xb3\xc4\x91\xc4\x93")

        # ensure trace worked
        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "test.cherrypy.service"
        assert s.resource == u"GET /üŋïĉóđē"
        assert s.error == 0
        assert_span_http_status_code(s, 200)
        assert s.meta.get(http.METHOD) == "GET"
        assert s.meta.get(http.URL) == u"http://127.0.0.1:54583/üŋïĉóđē"

    def test_404(self):
        self.getPage(u"/404/test")
        time.sleep(0.1)
        self.assertStatus("404 Not Found")

        # ensure trace worked
        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "test.cherrypy.service"
        assert s.resource == u"GET /404/test"
        assert s.error == 0
        assert_span_http_status_code(s, 404)
        assert s.meta.get(http.METHOD) == "GET"
        assert s.meta.get(http.URL) == u"http://127.0.0.1:54583/404/test"

    def test_propagation(self):
        self.getPage(
            "/",
            headers=[
                ("x-datadog-trace-id", "1234"),
                ("x-datadog-parent-id", "4567"),
                ("x-datadog-sampling-priority", "2"),
            ],
        )
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody("Hello world!")

        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]

        # ensure the propagation worked well
        assert s.trace_id == 1234
        assert s.parent_id == 4567
        assert s.get_metric(SAMPLING_PRIORITY_KEY) == 2

    def test_disabled_distributed_tracing_config(self):
        previous_distributed_tracing = config.cherrypy["distributed_tracing"]
        config.cherrypy["distributed_tracing"] = False
        self.getPage(
            "/",
            headers=[
                ("x-datadog-trace-id", "1234"),
                ("x-datadog-parent-id", "4567"),
                ("x-datadog-sampling-priority", "2"),
            ],
        )
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody("Hello world!")

        # ensure trace worked
        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]

        # ensure the propagation worked well
        assert s.trace_id != 1234
        assert s.parent_id != 4567
        assert s.get_metric(SAMPLING_PRIORITY_KEY) != 2

        config.cherrypy["distributed_tracing"] = previous_distributed_tracing

    def test_disabled_distributed_tracing_middleware(self):
        previous_distributed_tracing = cherrypy.tools.tracer.use_distributed_tracing
        cherrypy.tools.tracer.use_distributed_tracing = False
        self.getPage(
            "/",
            headers=[
                ("x-datadog-trace-id", "1234"),
                ("x-datadog-parent-id", "4567"),
                ("x-datadog-sampling-priority", "2"),
            ],
        )
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody("Hello world!")

        # ensure trace worked
        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]

        # ensure the propagation worked well
        assert s.trace_id != 1234
        assert s.parent_id != 4567
        assert s.get_metric(SAMPLING_PRIORITY_KEY) != 2

        cherrypy.tools.tracer.use_distributed_tracing = previous_distributed_tracing

    def test_custom_span(self):
        self.getPage(u"/custom_span")
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertBody("hiya")

        # ensure trace worked
        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "test.cherrypy.service"
        assert s.resource == "overridden"
        assert s.error == 0
        assert_span_http_status_code(s, 200)
        assert s.meta.get(http.METHOD) == "GET"

    def test_http_request_header_tracing(self):
        config.cherrypy.http.trace_headers(["Host", "my-header"])
        self.getPage(
            "/",
            headers=[
                ("my-header", "my_value"),
                ("x-datadog-parent-id", "4567"),
                ("x-datadog-sampling-priority", "2"),
            ],
        )
        time.sleep(0.1)

        traces = self.tracer.writer.pop_traces()
        assert len(traces) == 1
        assert len(traces[0]) == 1
        span = traces[0][0]
        assert span.get_tag("http.request.headers.my-header") == "my_value"
        assert span.get_tag("http.request.headers.host") == "127.0.0.1:54583"

    def test_http_response_header_tracing(self):
        config.cherrypy.http.trace_headers(["my-response-header"])
        self.getPage("/response_headers")
        time.sleep(0.1)

        traces = self.tracer.writer.pop_traces()
        assert len(traces) == 1
        assert len(traces[0]) == 1
        span = traces[0][0]

        assert span.get_tag(
            "http.response.headers.my-response-header") == "my_response_value"

    def test_variable_resource(self):
        self.getPage("/dispatch/abc123/")
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody("dispatch with abc123")

        # ensure trace worked
        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "test.cherrypy.service"

        # Once CherryPy returns sensible results for virtual path components, this
        # can be: "GET /dispatch/{{test_value}}/"
        assert s.resource == "GET /dispatch/abc123/"
        assert s.error == 0
        assert_span_http_status_code(s, 200)
        assert s.meta.get(http.METHOD) == "GET"

    def test_post(self):
        self.getPage("/", method="POST")
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody("Hello world!")

        # ensure trace worked
        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "test.cherrypy.service"
        assert s.resource == "POST /"
        assert s.error == 0
        assert_span_http_status_code(s, 200)
        assert s.meta.get(http.METHOD) == "POST"

    def test_service_configuration_config(self):
        previous_service = config.cherrypy.get("service",
                                               "test.cherrypy.service")
        config.cherrypy["service"] = "my_cherrypy_service"
        self.getPage("/")
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody("Hello world!")

        # ensure trace worked
        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "my_cherrypy_service"
        assert s.resource == "GET /"
        assert s.error == 0
        assert_span_http_status_code(s, 200)
        assert s.meta.get(http.METHOD) == "GET"

        config.cherrypy["service"] = previous_service

    def test_service_configuration_middleware(self):
        previous_service = cherrypy.tools.tracer.service
        cherrypy.tools.tracer.service = "my_cherrypy_service2"
        self.getPage("/")
        time.sleep(0.1)
        self.assertStatus("200 OK")
        self.assertHeader("Content-Type", "text/html;charset=utf-8")
        self.assertBody("Hello world!")

        # ensure trace worked
        assert not self.tracer.current_span(), self.tracer.current_span(
        ).pprint()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1
        s = spans[0]
        assert s.service == "my_cherrypy_service2"
        assert s.resource == "GET /"
        assert s.error == 0
        assert_span_http_status_code(s, 200)
        assert s.meta.get(http.METHOD) == "GET"

        cherrypy.tools.tracer.service = previous_service