Ejemplo n.º 1
0
 def test_commit_is_traced(self):
     connection = self.connection
     tracer = self.tracer
     connection.commit.return_value = None
     pin = Pin('pin_name', tracer=tracer)
     traced_connection = TracedConnection(connection, pin)
     traced_connection.commit()
     assert tracer.pop()[0].name == 'mock.connection.commit'
     connection.commit.assert_called_with()
Ejemplo n.º 2
0
 def test_rollback_is_traced(self):
     connection = self.connection
     tracer = self.tracer
     connection.rollback.return_value = None
     pin = Pin('pin_name', tracer=tracer)
     traced_connection = TracedConnection(connection, pin)
     traced_connection.rollback()
     assert tracer.writer.pop()[0].name == 'mock.connection.rollback'
     connection.rollback.assert_called_with()
Ejemplo n.º 3
0
 def test_connection_analytics_with_rate(self):
     with self.override_config("dbapi2", dict(analytics_enabled=True, analytics_sample_rate=0.5)):
         connection = self.connection
         tracer = self.tracer
         connection.commit.return_value = None
         pin = Pin("pin_name", tracer=tracer)
         traced_connection = TracedConnection(connection, pin)
         traced_connection.commit()
         span = tracer.pop()[0]
         self.assertIsNone(span.get_metric(ANALYTICS_SAMPLE_RATE_KEY))
Ejemplo n.º 4
0
    def test_cursor_class(self):
        pin = Pin('pin_name', tracer=self.tracer)

        # Default
        traced_connection = TracedConnection(self.connection, pin=pin)
        self.assertTrue(traced_connection._self_cursor_cls is TracedCursor)

        # Trace fetched methods
        with self.override_config('dbapi2', dict(trace_fetch_methods=True)):
            traced_connection = TracedConnection(self.connection, pin=pin)
            self.assertTrue(traced_connection._self_cursor_cls is FetchTracedCursor)

        # Manually provided cursor class
        with self.override_config('dbapi2', dict(trace_fetch_methods=True)):
            traced_connection = TracedConnection(self.connection, pin=pin, cursor_cls=TracedCursor)
            self.assertTrue(traced_connection._self_cursor_cls is TracedCursor)
Ejemplo n.º 5
0
def patch_conn(conn):
    tags = {t: getattr(conn, a, '') for t, a in CONN_ATTR_BY_TAG.items()}
    pin = Pin(app='pymysql', tags=tags)

    # grab the metadata from the conn
    wrapped = TracedConnection(conn, pin=pin, cfg=config.pymysql)
    pin.onto(wrapped)
    return wrapped
Ejemplo n.º 6
0
def patch_conn(conn):

    tags = {t: getattr(conn, a, '') for t, a in CONN_ATTR_BY_TAG.items()}
    pin = Pin(service="mysql", app="mysql", app_type="db", tags=tags)

    # grab the metadata from the conn
    wrapped = TracedConnection(conn)
    pin.onto(wrapped)
    return wrapped
Ejemplo n.º 7
0
def patch_conn(conn):

    tags = {t: getattr(conn, a) for t, a in CONN_ATTR_BY_TAG.items() if getattr(conn, a, '') != ''}
    pin = Pin(service='mysql', app='mysql', app_type=AppTypes.db, tags=tags)

    # grab the metadata from the conn
    wrapped = TracedConnection(conn, pin=pin)
    pin.onto(wrapped)
    return wrapped
Ejemplo n.º 8
0
def patch_conn(conn, *args, **kwargs):
    tags = {
        t: kwargs[k] if k in kwargs else args[p] for t, (k, p) in KWPOS_BY_TAG.items() if k in kwargs or len(args) > p
    }
    tags[net.TARGET_PORT] = conn.port
    pin = Pin(app="mysql", tags=tags)

    # grab the metadata from the conn
    wrapped = TracedConnection(conn, pin=pin, cfg=config.mysqldb)
    pin.onto(wrapped)
    return wrapped
Ejemplo n.º 9
0
def patch_conn(conn, *args, **kwargs):
    tags = {
        t: kwargs[k] if k in kwargs else args[p]
        for t, (k, p) in KWPOS_BY_TAG.items() if k in kwargs or len(args) > p
    }
    tags[net.TARGET_PORT] = conn.port
    pin = Pin(service='mysql', app='mysql', app_type=AppTypes.db, tags=tags)

    # grab the metadata from the conn
    wrapped = TracedConnection(conn, pin=pin)
    pin.onto(wrapped)
    return wrapped
Ejemplo n.º 10
0
def _connect(func, instance, args, kwargs):
    conn = func(*args, **kwargs)
    tags = {
        net.TARGET_HOST: kwargs["host"],
        net.TARGET_PORT: kwargs["port"],
        db.USER: kwargs["user"],
        db.NAME: kwargs["database"],
    }

    pin = Pin(app="mariadb", tags=tags)

    wrapped = TracedConnection(conn, pin=pin, cfg=config.mariadb)
    pin.onto(wrapped)
    return wrapped
Ejemplo n.º 11
0
    def test_cursor_class(self):
        pin = Pin("pin_name", tracer=self.tracer)

        # Default
        traced_connection = TracedConnection(self.connection, pin=pin)
        self.assertTrue(traced_connection._self_cursor_cls is TracedCursor)

        # Trace fetched methods
        with self.override_config("dbapi2", dict(trace_fetch_methods=True)):
            with warnings.catch_warnings(record=True) as ws:
                warnings.simplefilter("always")

                traced_connection = TracedConnection(self.connection, pin=pin)
                self.assertTrue(traced_connection._self_cursor_cls is FetchTracedCursor)

                (w,) = ws
                self.assertTrue(issubclass(w.category, DeprecationWarning))
                self.assertTrue("ddtrace.config.dbapi2.trace_fetch_methods is now deprecated" in str(w.message))

        # Manually provided cursor class
        with self.override_config("dbapi2", dict(trace_fetch_methods=True)):
            traced_connection = TracedConnection(self.connection, pin=pin, cursor_cls=TracedCursor)
            self.assertTrue(traced_connection._self_cursor_cls is TracedCursor)
Ejemplo n.º 12
0
    def test_connection_context_manager(self):
        class Cursor(object):
            rowcount = 0

            def execute(self, *args, **kwargs):
                pass

            def fetchall(self, *args, **kwargs):
                pass

            def __enter__(self):
                return self

            def __exit__(self, *exc):
                return False

            def commit(self, *args, **kwargs):
                pass

        # When a connection is returned from a context manager the object proxy
        # should be returned so that tracing works.

        class ConnectionConnection(object):
            def __enter__(self):
                return self

            def __exit__(self, *exc):
                return False

            def cursor(self):
                return Cursor()

            def commit(self):
                pass

        pin = Pin("pin", tracer=self.tracer)
        conn = TracedConnection(ConnectionConnection(), pin)
        with conn as conn2:
            conn2.commit()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1

        with conn as conn2:
            with conn2.cursor() as cursor:
                cursor.execute("query")
                cursor.fetchall()

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

        # If a cursor is returned from the context manager
        # then it should be instrumented.

        class ConnectionCursor(object):
            def __enter__(self):
                return Cursor()

            def __exit__(self, *exc):
                return False

            def commit(self):
                pass

        with TracedConnection(ConnectionCursor(), pin) as cursor:
            cursor.execute("query")
            cursor.fetchall()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1

        # If a traced cursor is returned then it should not
        # be double instrumented.

        class ConnectionTracedCursor(object):
            def __enter__(self):
                return self.cursor()

            def __exit__(self, *exc):
                return False

            def cursor(self):
                return TracedCursor(Cursor(), pin, {})

            def commit(self):
                pass

        with TracedConnection(ConnectionTracedCursor(), pin) as cursor:
            cursor.execute("query")
            cursor.fetchall()
        spans = self.tracer.writer.pop()
        assert len(spans) == 1

        # Check when a different connection object is returned
        # from a connection context manager.
        # No traces should be produced.

        other_conn = ConnectionConnection()

        class ConnectionDifferentConnection(object):
            def __enter__(self):
                return other_conn

            def __exit__(self, *exc):
                return False

            def cursor(self):
                return Cursor()

            def commit(self):
                pass

        conn = TracedConnection(ConnectionDifferentConnection(), pin)
        with conn as conn2:
            conn2.commit()
        spans = self.tracer.writer.pop()
        assert len(spans) == 0

        with conn as conn2:
            with conn2.cursor() as cursor:
                cursor.execute("query")
                cursor.fetchall()

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

        # When some unexpected value is returned from the context manager
        # it should be handled gracefully.

        class ConnectionUnknown(object):
            def __enter__(self):
                return 123456

            def __exit__(self, *exc):
                return False

            def cursor(self):
                return Cursor()

            def commit(self):
                pass

        conn = TracedConnection(ConnectionDifferentConnection(), pin)
        with conn as conn2:
            conn2.commit()
        spans = self.tracer.writer.pop()
        assert len(spans) == 0

        with conn as conn2:
            with conn2.cursor() as cursor:
                cursor.execute("query")
                cursor.fetchall()

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

        # Errors should be the same when no context management is defined.

        class ConnectionNoCtx(object):
            def cursor(self):
                return Cursor()

            def commit(self):
                pass

        conn = TracedConnection(ConnectionNoCtx(), pin)
        with pytest.raises(AttributeError):
            with conn:
                pass

        with pytest.raises(AttributeError):
            with conn as conn2:
                pass

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