예제 #1
0
    def test_patch_unpatch(self):
        tracer = get_dummy_tracer()
        writer = tracer.writer

        # Test patch idempotence
        patch()
        patch()

        client = pymongo.MongoClient(port=MONGO_CONFIG['port'])
        Pin.get_from(client).clone(tracer=tracer).onto(client)
        client['testdb'].drop_collection('whatever')

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

        # Test unpatch
        unpatch()

        client = pymongo.MongoClient(port=MONGO_CONFIG['port'])
        client['testdb'].drop_collection('whatever')

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

        # Test patch again
        patch()

        client = pymongo.MongoClient(port=MONGO_CONFIG['port'])
        Pin.get_from(client).clone(tracer=tracer).onto(client)
        client['testdb'].drop_collection('whatever')

        spans = writer.pop()
        assert spans, spans
        assert len(spans) == 1
    def test_patch_unpatch(self):
        # Test patch idempotence
        patch()
        patch()

        tracer = get_dummy_tracer()
        Pin.get_from(Cluster).clone(tracer=tracer).onto(Cluster)

        session = Cluster(port=CASSANDRA_CONFIG['port']).connect(self.TEST_KEYSPACE)
        session.execute(self.TEST_QUERY)

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

        # Test unpatch
        unpatch()

        session = Cluster(port=CASSANDRA_CONFIG['port']).connect(self.TEST_KEYSPACE)
        session.execute(self.TEST_QUERY)

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

        # Test patch again
        patch()
        Pin.get_from(Cluster).clone(tracer=tracer).onto(Cluster)

        session = Cluster(port=CASSANDRA_CONFIG['port']).connect(self.TEST_KEYSPACE)
        session.execute(self.TEST_QUERY)

        spans = tracer.writer.pop()
        assert spans, spans
예제 #3
0
    def get_tracer_and_connect(self):
        tracer = get_dummy_tracer()
        Pin.get_from(mongoengine.connect).clone(tracer=tracer).onto(
            mongoengine.connect)
        mongoengine.connect(port=MONGO_CONFIG['port'])

        return tracer
예제 #4
0
    def test_blueprint_add_url_rule(self):
        """
        When we call ``flask.Blueprint.add_url_rule``
            When the ``Blueprint`` has a ``Pin`` attached
                We clone the Blueprint's ``Pin`` to the view
            When the ``Blueprint`` does not have a ``Pin`` attached
                We do not attach a ``Pin`` to the func
        """
        # When the Blueprint has a Pin attached
        bp = flask.Blueprint('pinned', __name__)
        Pin(service='flask-bp', tracer=self.tracer).onto(bp)

        @bp.route('/')
        def test_view():
            pass

        # Assert the view func has a `Pin` attached with the Blueprint's service name
        pin = Pin.get_from(test_view)
        self.assertIsNotNone(pin)
        self.assertEqual(pin.service, 'flask-bp')

        # When the Blueprint does not have a Pin attached
        bp = flask.Blueprint('not-pinned', __name__)

        @bp.route('/')
        def test_view():
            pass

        # Assert the view does not have a `Pin` attached
        pin = Pin.get_from(test_view)
        self.assertIsNone(pin)
    def test_patch_unpatch(self):
        tracer = get_dummy_tracer()
        writer = tracer.writer

        # Test patch idempotence
        patch()
        patch()

        r = self._get_test_client()
        Pin.get_from(r).clone(tracer=tracer).onto(r)
        r.get('key')

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

        # Test unpatch
        unpatch()

        r = self._get_test_client()
        r.get('key')

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

        # Test patch again
        patch()

        r = self._get_test_client()
        Pin.get_from(r).clone(tracer=tracer).onto(r)
        r.get('key')

        spans = writer.pop()
        assert spans, spans
        assert len(spans) == 1
def trace_before_publish(*args, **kwargs):
    # `before_task_publish` signal doesn't propagate the task instance so
    # we need to retrieve it from the Celery Registry to access the `Pin`. The
    # `Task` instance **does not** include any information about the current
    # execution, so it **must not** be used to retrieve `request` data.
    task_name = kwargs.get('sender')
    task = registry.tasks.get(task_name)
    task_id = retrieve_task_id(kwargs)
    # safe-guard to avoid crashes in case the signals API
    # changes in Celery
    if task is None or task_id is None:
        log.debug(
            'unable to extract the Task and the task_id. This version of Celery may not be supported.'
        )
        return

    # propagate the `Span` in the current task Context
    pin = Pin.get_from(task) or Pin.get_from(task.app)
    if pin is None:
        return

    # apply some tags here because most of the data is not available
    # in the task_after_publish signal
    service = config.celery['producer_service_name']
    span = pin.tracer.trace(c.PRODUCER_ROOT_SPAN,
                            service=service,
                            resource=task_name)
    span.set_tag(c.TASK_TAG_KEY, c.TASK_APPLY_ASYNC)
    span.set_tag('celery.id', task_id)
    span.set_tags(tags_from_context(kwargs))
    # Note: adding tags from `traceback` or `state` calls will make an
    # API call to the backend for the properties so we should rely
    # only on the given `Context`
    attach_span(task, task_id, span, is_publish=True)
    def test_patch_unpatch(self):
        tracer = get_dummy_tracer()
        writer = tracer.writer

        # 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 = writer.pop()
        assert spans, spans
        assert len(spans) == 1

        # Test unpatch
        unpatch()

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

        spans = writer.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 = writer.pop()
        assert spans, spans
        assert len(spans) == 1
 def test_same_tracer(self):
     """Ensure same tracer reference is used by the pin on pymemache and
     Clients.
     """
     client = pymemcache.client.base.Client((TEST_HOST, TEST_PORT))
     self.assertEqual(
         Pin.get_from(client).tracer,
         Pin.get_from(pymemcache).tracer)
예제 #9
0
    def get_client(self):
        url = '%s:%s' % (cfg['host'], cfg['port'])
        client = pylibmc.Client([url])
        client.flush_all()

        Pin.get_from(client).clone(tracer=self.tracer).onto(client)

        return client, self.tracer
    def trace_spans(self):
        conn, _ = yield from self._get_conn_and_tracer()

        Pin.get_from(conn).clone(service='db', tracer=self.tracer).onto(conn)

        cursor = yield from conn.cursor()
        yield from cursor.execute('select \'foobar\'')
        rows = yield from cursor.fetchall()
        assert rows

        return self.get_spans()
    def test_override_missing(self):
        # ensure overriding an instance doesn't override the Class
        class A(object):
            pass

        a = A()
        assert Pin.get_from(a) is None
        Pin.override(a, service='metrics')
        assert Pin.get_from(a).service == 'metrics'

        b = A()
        assert Pin.get_from(b) is None
    def test_patch_unpatch(self):
        """ Tests repatch-unpatch cycle """
        # Already call patch in setUp
        self.assertTrue(Pin.get_from(molten) is not None)
        molten_client()
        spans = self.tracer.writer.pop()
        self.assertTrue(len(spans) > 0)

        # Test unpatch
        unpatch()
        self.assertTrue(Pin.get_from(molten) is None)
        molten_client()
        spans = self.tracer.writer.pop()
        self.assertEqual(len(spans), 0)
    def test_connect_factory(self):
        tracer = get_dummy_tracer()

        services = ['db', 'another']
        for service in services:
            conn, _ = yield from self._get_conn_and_tracer()
            Pin.get_from(conn).clone(service=service, tracer=tracer).onto(conn)
            yield from self.assert_conn_is_traced(tracer, conn, service)
            conn.close()

        # ensure we have the service types
        service_meta = tracer.writer.pop_services()
        expected = {}
        assert service_meta == expected
    def test_override(self):
        # ensure Override works for an instance object
        class A(object):
            pass

        Pin(service='metrics', app='flask').onto(A)
        a = A()
        Pin.override(a, app='django')
        assert Pin.get_from(a).app == 'django'
        assert Pin.get_from(a).service == 'metrics'

        b = A()
        assert Pin.get_from(b).app == 'flask'
        assert Pin.get_from(b).service == 'metrics'
예제 #15
0
def traced_blueprint_register(wrapped, instance, args, kwargs):
    """
    Wrapper for flask.blueprints.Blueprint.register

    This wrapper just ensures the blueprint has a pin, either set manually on
    itself from the user or inherited from the application
    """
    app = kwargs.get('app', args[0])
    # Check if this Blueprint has a pin, otherwise clone the one from the app onto it
    pin = Pin.get_from(instance)
    if not pin:
        pin = Pin.get_from(app)
        if pin:
            pin.clone().onto(instance)
    return wrapped(*args, **kwargs)
    def test_unpatch_patch(self):
        """ Tests unpatch-patch cycle """
        unpatch()
        self.assertIsNone(Pin.get_from(molten))
        molten_client()
        spans = self.tracer.writer.pop()
        self.assertEqual(len(spans), 0)

        patch()
        # Need to override Pin here as we do in setUp
        Pin.override(molten, tracer=self.tracer)
        self.assertTrue(Pin.get_from(molten) is not None)
        molten_client()
        spans = self.tracer.writer.pop()
        self.assertTrue(len(spans) > 0)
    def test_pin_config_is_a_copy(self):
        # ensure that when a `Pin` is cloned, the config is a copy
        obj = self.Obj()
        Pin.override(obj, service='metrics')
        p1 = Pin.get_from(obj)
        assert p1._config is not None
        p1._config['distributed_tracing'] = True

        Pin.override(obj, service='intake')
        p2 = Pin.get_from(obj)
        assert p2._config is not None
        p2._config['distributed_tracing'] = False

        assert p1._config['distributed_tracing'] is True
        assert p2._config['distributed_tracing'] is False
    def test_patch_before_import(self):
        from oteltrace import patch
        patch(celery=True)
        import celery

        app = celery.Celery()
        assert Pin.get_from(app) is not None
    def test_patch_after_import(self):
        import celery
        from oteltrace import patch
        patch(celery=True)

        app = celery.Celery()
        assert Pin.get_from(app) is not None
    def _get_conn(self, service=None):
        conn = psycopg2.connect(**POSTGRES_CONFIG)
        pin = Pin.get_from(conn)
        if pin:
            pin.clone(service=service, tracer=self.tracer).onto(conn)

        return conn
 def get_spans(self):
     spans = []
     for _, client in self.client.clients.items():
         pin = Pin.get_from(client)
         tracer = pin.tracer
         spans.extend(tracer.writer.pop())
     return spans
예제 #22
0
    def test_patch_unpatch(self):
        unpatch()
        # assert we start unpatched
        conn = mysql.connector.connect(**MYSQL_CONFIG)
        assert not Pin.get_from(conn)
        conn.close()

        patch()
        try:
            writer = self.tracer.writer
            conn = mysql.connector.connect(**MYSQL_CONFIG)
            pin = Pin.get_from(conn)
            assert pin
            pin.clone(service=self.TEST_SERVICE, tracer=self.tracer).onto(conn)
            assert conn.is_connected()

            cursor = conn.cursor()
            cursor.execute('SELECT 1')
            rows = cursor.fetchall()
            assert len(rows) == 1
            spans = writer.pop()
            assert len(spans) == 1

            span = spans[0]
            assert span.service == self.TEST_SERVICE
            assert span.name == 'mysql.query'
            assert span.span_type == 'sql'
            assert span.error == 0
            assert_dict_issuperset(
                span.meta, {
                    'out.host': u'127.0.0.1',
                    'out.port': u'3306',
                    'db.name': u'test',
                    'db.user': u'test',
                })
            assert span.get_tag('sql.query') is None

        finally:
            unpatch()

            # assert we finish unpatched
            conn = mysql.connector.connect(**MYSQL_CONFIG)
            assert not Pin.get_from(conn)
            conn.close()

        patch()
 def test_pin_config(self):
     # ensure `Pin` has a configuration object that can be modified
     obj = self.Obj()
     Pin.override(obj, service='metrics')
     pin = Pin.get_from(obj)
     assert pin._config is not None
     pin._config['distributed_tracing'] = True
     assert pin._config['distributed_tracing'] is True
    def test_pin(self):
        # ensure a Pin can be attached to an instance
        obj = self.Obj()
        pin = Pin(service='metrics')
        pin.onto(obj)

        got = Pin.get_from(obj)
        assert got.service == pin.service
        assert got is pin
    def test_pin_does_not_override_global(self):
        # ensure that when a `Pin` is created from a class, the specific
        # instance doesn't override the global one
        class A(object):
            pass

        Pin.override(A, service='metrics')
        global_pin = Pin.get_from(A)
        global_pin._config['distributed_tracing'] = True

        a = A()
        pin = Pin.get_from(a)
        assert pin is not None
        assert pin._config['distributed_tracing'] is True
        pin._config['distributed_tracing'] = False

        assert global_pin._config['distributed_tracing'] is True
        assert pin._config['distributed_tracing'] is False
    def test_cant_pin_with_slots(self):
        # ensure a Pin can't be attached if the __slots__ is defined
        class Obj(object):
            __slots__ = ['value']

        obj = Obj()
        obj.value = 1

        Pin(service='metrics').onto(obj)
        got = Pin.get_from(obj)
        assert got is None
    def test_pin_does_not_override_global_with_new_instance(self):
        # ensure that when a `Pin` is created from a class, the specific
        # instance doesn't override the global one, even if only the
        # `onto()` API has been used
        class A(object):
            pass

        pin = Pin(service='metrics')
        pin.onto(A)
        global_pin = Pin.get_from(A)
        global_pin._config['distributed_tracing'] = True

        a = A()
        pin = Pin.get_from(a)
        assert pin is not None
        assert pin._config['distributed_tracing'] is True
        pin._config['distributed_tracing'] = False

        assert global_pin._config['distributed_tracing'] is True
        assert pin._config['distributed_tracing'] is False
예제 #28
0
    def test_blueprint_register(self):
        """
        When we register a ``flask.Blueprint`` to a ``flask.Flask``
            When no ``Pin`` is attached to the ``Blueprint``
                We attach the pin from the ``flask.Flask`` app
            When a ``Pin`` is manually added to the ``Blueprint``
                We do not use the ``flask.Flask`` app ``Pin``
        """
        bp = flask.Blueprint('pinned', __name__)
        Pin(service='flask-bp', tracer=self.tracer).onto(bp)

        # DEV: This is more common than calling ``flask.Blueprint.register`` directly
        self.app.register_blueprint(bp)
        pin = Pin.get_from(bp)
        self.assertEqual(pin.service, 'flask-bp')

        bp = flask.Blueprint('not-pinned', __name__)
        self.app.register_blueprint(bp)
        pin = Pin.get_from(bp)
        self.assertEqual(pin.service, 'flask')
def _client_channel_interceptor(wrapped, instance, args, kwargs):
    channel = wrapped(*args, **kwargs)

    pin = Pin.get_from(constants.GRPC_PIN_MODULE_CLIENT)
    if not pin or not pin.enabled():
        return channel

    (host, port) = _parse_target_from_arguments(args, kwargs)

    interceptor_function = create_client_interceptor(pin, host, port)
    return grpc.intercept_channel(channel, interceptor_function)
def _unpatch_server():
    if not getattr(constants.GRPC_PIN_MODULE_SERVER, '__opentelemetry_patch',
                   False):
        return
    setattr(constants.GRPC_PIN_MODULE_SERVER, '__opentelemetry_patch', False)

    pin = Pin.get_from(constants.GRPC_PIN_MODULE_SERVER)
    if pin:
        pin.remove_from(constants.GRPC_PIN_MODULE_SERVER)

    _u(grpc, 'server')