Пример #1
0
def test_mark_instrumented_and_uninstrumented():
    class MockModule(object):
        pass

    module = MockModule()
    utils.mark_instrumented(module)
    assert getattr(module, constants.instrumented_attr) is True
    assert utils.is_instrumented(module) is True
    utils.mark_uninstrumented(module)
    assert not hasattr(module, constants.instrumented_attr)
    assert utils.is_instrumented(module) is False
Пример #2
0
def instrument(tracer=None):
    tornado = utils.get_module('tornado')
    if utils.is_instrumented(tornado):
        return

    tornado_opentracing = utils.get_module('tornado_opentracing')

    def _tracer_config(wrapped_tracer_config, _, wrapt_args, __):
        """
        A function wrapper for tornado_opentracing's monkey patcher of tornado.web.Application.__init__()
        used to inject tracer configuration as settings arguments.  As a wrapt function wrapper of a
        function_wrapper, _tracer_config's meaningful arguments are oddly nested.
        """
        __init__ = wrapt_args[0]
        app = wrapt_args[1]
        args = wrapt_args[2]
        kwargs = wrapt_args[3]

        _tracer = tracer or config.tracer or opentracing.tracer
        kwargs['opentracing_tracing'] = tornado_opentracing.TornadoTracing(_tracer)
        kwargs['opentracing_trace_all'] = config.trace_all
        kwargs['opentracing_trace_client'] = config.trace_client
        kwargs['opentracing_traced_attributes'] = config.traced_attributes
        kwargs['opentracing_start_span_cb'] = config.start_span_cb

        wrapped_tracer_config(__init__, app, args, kwargs)

    wrap_function_wrapper('tornado_opentracing.application', 'tracer_config', _tracer_config)
    tornado_opentracing.init_tracing()
    utils.mark_instrumented(tornado)
def uninstrument():
    elasticsearch = utils.get_module('elasticsearch')
    if not utils.is_instrumented(elasticsearch):
        return

    from elasticsearch_opentracing import disable_tracing, TracingTransport
    disable_tracing()

    # because of https://bugs.python.org/issue25731 we cannot simply restore
    # built-in __new__.  Use a generic implementation as a workaround
    def __new__(cls, *_, **__):
        return object.__new__(cls)

    if _tracing_transport_new[0] is not None:
        if hasattr(_tracing_transport_new[0], '__get__'):
            TracingTransport.__new__ = _tracing_transport_new[0].__get__(
                TracingTransport)
        else:  # builtin doesn't follow descriptor protocol
            TracingTransport.__new__ = __new__.__get__(TracingTransport)
        _tracing_transport_new[0] = None

    if _transport_new[0] is not None:
        if hasattr(_transport_new[0], '__get__'):
            elasticsearch.transport.Transport.__new__ = _transport_new[
                0].__get__(elasticsearch.transport.Transport)
        else:
            elasticsearch.transport.Transport.__new__ = __new__.__get__(
                elasticsearch.transport.Transport)
        _transport_new[0] = None
    utils.mark_uninstrumented(elasticsearch)
def uninstrument():
    falcon = utils.get_module("falcon")
    if not utils.is_instrumented(falcon):
        return

    utils.revert_wrapper(falcon.API, "__init__")
    utils.mark_uninstrumented(falcon)
Пример #5
0
def instrument(tracer=None):
    pymongo = utils.get_module('pymongo')
    if utils.is_instrumented(pymongo):
        return

    pymongo_opentracing = utils.get_module('pymongo_opentracing')

    def pymongo_tracer(__init__, app, args, kwargs):
        """
        A function wrapper of pymongo.MongoClient.__init__ to register a corresponding
        pymongo_opentracing.CommandTracing upon client instantiation.
        """
        _tracer = tracer or config.tracer or opentracing.tracer

        command_tracing = pymongo_opentracing.CommandTracing(
            tracer=_tracer,
            span_tags=config.span_tags or {},
        )

        event_listeners = list(kwargs.pop('event_listeners', []))
        event_listeners.insert(0, command_tracing)
        kwargs['event_listeners'] = event_listeners
        __init__(*args, **kwargs)

    wrap_function_wrapper('pymongo', 'MongoClient.__init__', pymongo_tracer)
    utils.mark_instrumented(pymongo)
Пример #6
0
def instrument(tracer=None):
    """
    Requests auto-instrumentation works by hooking a __new__ proxy for a CeleryTracing
    instance upon celery.Celery initialization to trigger proper inheritance.
    CeleryTracing.__init__ is also wrapped for correct argument injection.
    """

    celery = utils.get_module('celery')
    if utils.is_instrumented(celery):
        return

    import celery.app

    def celery_tracing_init(__init__, instance, args, kwargs):
        _tracer = tracer or config.tracer or opentracing.tracer
        __init__(*args,
                 tracer=_tracer,
                 propagate=config.propagate,
                 span_tags=config.span_tags or {},
                 **kwargs)

    from celery_opentracing import CeleryTracing

    _celery_new[0] = celery.Celery.__new__
    _celery_tracing_new[0] = CeleryTracing.__new__

    CeleryTracing.__new__ = celery_tracing_new.__get__(CeleryTracing)
    celery.app.base.Celery.__new__ = celery_new.__get__(celery.Celery)
    wrap_function_wrapper('celery_opentracing.tracing',
                          'CeleryTracing.__init__', celery_tracing_init)

    utils.mark_instrumented(celery)
def instrument(tracer=None):
    django = utils.get_module('django')
    if utils.is_instrumented(django):
        return

    settings = utils.get_module('django.conf').settings
    # Tracer settings (need to be before initialization)
    settings.OPENTRACING_TRACE_ALL = config.trace_all
    settings.OPENTRACING_TRACED_ATTRIBUTES = config.traced_attributes

    settings.OPENTRACING_SET_GLOBAL_TRACER = config.set_global_tracer

    # DjangoTracing will obtain global tracer for us
    _tracer = tracer or config.tracer
    if _tracer is not None:
        django_opentracing = utils.get_module('django_opentracing')
        settings.OPENTRACING_TRACING = django_opentracing.DjangoTracer(tracer)

    if config.tracer_callable:
        settings.OPENTRACING_TRACER_CALLABLE = config.tracer_callable
        settings.OPENTRACING_TRACER_PARAMETERS = config.tracer_parameters or {}

    middleware_classes, setting = get_middleware_and_setting_name()
    setattr(settings, setting,
            [config.middleware_class] + list(middleware_classes))
    utils.mark_instrumented(django)
def uninstrument():
    logging = utils.get_module('logging')
    if not utils.is_instrumented(logging):
        return

    utils.revert_wrapper(logging, 'Logger.makeRecord')
    utils.mark_uninstrumented(logging)
def instrument(tracer=None):
    flask = utils.get_module('flask')
    if utils.is_instrumented(flask):
        return

    flask_opentracing = utils.get_module('flask_opentracing')

    def flask_tracer(__init__, app, args, kwargs):
        """
        A function wrapper of flask.Flask.__init__ to create a corresponding
        flask_opentracing.FlaskTracer upon app instantiation.
        """

        __init__(*args, **kwargs)

        _tracer = tracer or config.tracer or opentracing.tracer

        app.config['FLASK_TRACER'] = flask_opentracing.FlaskTracer(
            tracer=_tracer,
            trace_all_requests=config.trace_all,
            app=app,
            traced_attributes=config.traced_attributes)

    wrap_function_wrapper('flask', 'Flask.__init__', flask_tracer)
    utils.mark_instrumented(flask)
def instrument(tracer=None):
    """
    Requests auto-instrumentation works by hooking a __new__ proxy for a SessionTracing
    instance upon requests.sessions.Session initialization to trigger proper inheritance.
    SessionTracing.__init__ is also wrapped for correct argument injection.
    """

    requests = utils.get_module('requests')
    if utils.is_instrumented(requests):
        return

    def session_tracing_init(__init__, instance, _, __):
        _tracer = tracer or config.tracer or opentracing.tracer
        __init__(_tracer,
                 propagate=config.propagate,
                 span_tags=config.span_tags or {})

    from requests_opentracing import SessionTracing

    _session_new[0] = requests.Session.__new__
    _session_tracing_new[0] = SessionTracing.__new__

    SessionTracing.__new__ = session_tracing_new.__get__(SessionTracing)
    requests.Session.__new__ = session_new.__get__(requests.Session)
    wrap_function_wrapper('requests_opentracing.tracing',
                          'SessionTracing.__init__', session_tracing_init)

    utils.mark_instrumented(requests)
def uninstrument():
    """Will only prevent new clients from registering tracers."""
    redis = utils.get_module('redis')
    if not utils.is_instrumented(redis):
        return

    from redis.client import StrictRedis
    utils.revert_wrapper(StrictRedis, '__init__')
    utils.mark_uninstrumented(redis)
Пример #12
0
def uninstrument():
    tornado = utils.get_module('tornado')
    if not utils.is_instrumented(tornado):
        return

    tornado_initialization = utils.get_module('tornado_opentracing.initialization')
    tornado_initialization._unpatch_tornado()
    tornado_initialization._unpatch_tornado_client()

    utils.mark_uninstrumented(tornado)
Пример #13
0
def uninstrument():
    """
    Will only prevent new Connections from registering tracers.
    It's not reasonably feasible to unwrap existing ConnectionTracing instances
    """
    psycopg2 = utils.get_module('psycopg2')
    if not utils.is_instrumented(psycopg2):
        return

    utils.revert_wrapper(psycopg2, 'connect')
    utils.mark_uninstrumented(psycopg2)
Пример #14
0
def uninstrument():
    """
    Will only prevent new applications from registering tracers.
    It's not reasonably feasible to remove existing before/after_request
    trace methods of existing apps.
    """
    bottle = utils.get_module('bottle')
    if not utils.is_instrumented(bottle):
        return

    utils.revert_wrapper(bottle, 'run')
    utils.mark_uninstrumented(bottle)
def uninstrument():
    """
    Will only prevent new applications from registering tracers.
    It's not reasonably feasible to remove existing before/after_request
    trace methods of existing apps.
    """
    flask = utils.get_module('flask')
    if not utils.is_instrumented(flask):
        return

    utils.revert_wrapper(flask.Flask, '__init__')
    utils.mark_uninstrumented(flask)
Пример #16
0
def uninstrument():
    """
    Will only prevent new clients from registering tracers.
    It's not reasonably feasible to remove existing before/after_request
    trace methods of existing clients.
    """
    pymongo = utils.get_module('pymongo')
    if not utils.is_instrumented(pymongo):
        return

    utils.revert_wrapper(pymongo.MongoClient, '__init__')
    utils.mark_uninstrumented(pymongo)
Пример #17
0
def instrument(tracer=None):
    aioredis = utils.get_module('aioredis')
    if utils.is_instrumented(aioredis):
        return

    tracing.init_tracing(tracer=tracer or config.tracer or opentracing.tracer)

    def traced_client(__init__, client, args, kwargs):
        __init__(*args, **kwargs)
        tracing.trace_client(client)

    wrap_function_wrapper('aioredis', 'Redis.__init__', traced_client)
    utils.mark_instrumented(aioredis)
def instrument(tracer=None):
    redis = utils.get_module('redis')
    if utils.is_instrumented(redis):
        return

    redis_opentracing = utils.get_module('redis_opentracing')
    redis_opentracing.init_tracing(tracer=tracer or config.tracer or opentracing.tracer,
                                   trace_all_classes=False)

    def traced_client(__init__, client, args, kwargs):
        __init__(*args, **kwargs)
        redis_opentracing.trace_client(client)

    wrap_function_wrapper('redis.client', 'StrictRedis.__init__', traced_client)
    utils.mark_instrumented(redis)
Пример #19
0
def instrument(tracer=None):
    falcon = utils.get_module("falcon")
    if utils.is_instrumented(falcon):
        return

    _tracer = tracer or config.tracer or opentracing.tracer

    def traced_init(wrapped, instance, args, kwargs):
        mw = kwargs.pop("middleware", [])

        mw.insert(0, TraceMiddleware(_tracer, config.traced_attributes))
        kwargs["middleware"] = mw

        wrapped(*args, **kwargs)

    wrap_function_wrapper("falcon", "API.__init__", traced_init)
    utils.mark_instrumented(falcon)
Пример #20
0
def instrument(tracer=None):
    pymysql = utils.get_module('pymysql')
    if utils.is_instrumented(pymysql):
        return

    dbapi_opentracing = utils.get_module('dbapi_opentracing')

    def pymysql_tracer(connect, _, args, kwargs):
        """
        A function wrapper of pymysql.connect() to create a corresponding
        dbapi_opentracing.ConnectionTracing upon database connection.
        """

        connection = connect(*args, **kwargs)
        _tracer = tracer or config.tracer or opentracing.tracer

        traced_commands = set(config.traced_commands)
        traced_commands_kwargs = dict(trace_execute=False,
                                      trace_executemany=False,
                                      trace_callproc=False,
                                      trace_commit=False,
                                      trace_rollback=False)
        for command in traced_commands:
            flag = 'trace_{}'.format(command.lower())
            if flag not in traced_commands_kwargs:
                log.warn(
                    'Unable to trace PyMySQL command "{}".  Ignoring.'.format(
                        command))
                continue
            traced_commands_kwargs[flag] = True

        span_tags = {tags.DATABASE_TYPE: 'MySQL'}
        if connection.db is not None:
            span_tags[tags.DATABASE_INSTANCE] = ensure_str(connection.db)

        if config.span_tags is not None:
            span_tags.update(config.span_tags)

        return dbapi_opentracing.ConnectionTracing(connection,
                                                   _tracer,
                                                   span_tags=span_tags,
                                                   **traced_commands_kwargs)

    wrap_function_wrapper('pymysql', 'connect', pymysql_tracer)
    utils.mark_instrumented(pymysql)
Пример #21
0
def uninstrument():
    django = utils.get_module('django')
    if not utils.is_instrumented(django):
        return

    settings = utils.get_module('django.conf').settings
    for setting in ('OPENTRACING_TRACE_ALL', 'OPENTRACING_TRACED_ATTRIBUTES',
                    'OPENTRACING_TRACER_CALLABLE', 'OPENTRACING_TRACER_PARAMETERS',
                    'OPENTRACING_SET_GLOBAL_TRACER', 'OPENTRACING_TRACING', 'OPENTRACING_TRACER'):
        try:
            delattr(settings, setting)
        except AttributeError:
            pass

    middleware, setting = get_middleware_and_setting_name()
    middleware_classes = [i for i in middleware if i != config.middleware_class]
    setattr(settings, setting, middleware_classes)
    utils.mark_uninstrumented(django)
Пример #22
0
def instrument(tracer=None):
    """
    Unlike all other instrumentations, this instrumentation does not patch the logging
    lib to automatically generate spans. Instead it patches the lib to automatically
    inject trace context into logs.
    """
    logging = utils.get_module('logging')
    if utils.is_instrumented(logging):
        return

    wrap_function_wrapper(logging, 'Logger.makeRecord', makeRecordPatched)

    if config.injection_enabled:
        level = logging.INFO
        if utils.is_truthy(os.environ.get('SIGNALFX_TRACING_DEBUG', False)):
            level = logging.DEBUG
        logging.basicConfig(level=level, format=config.logging_format)

    utils.mark_instrumented(logging)
Пример #23
0
def instrument(tracer=None):
    bottle = utils.get_module('bottle')
    if utils.is_instrumented(bottle):
        return

    def bottle_tracer(run, _, args, kwargs):
        """
        A function wrapper of bottle.run to create a corresponding
        BottleTracer upon app instantiation.
        """
        app = kwargs.get('app', default_app())
        _tracer = tracer or config.tracer or opentracing.tracer
        BottleTracing(tracer=_tracer, trace_all_requests=config.trace_all,
                      app=app, traced_attributes=config.traced_attributes)

        run(**kwargs)

    wrap_function_wrapper('bottle', 'run', bottle_tracer)
    utils.mark_instrumented(bottle)
def uninstrument():
    requests = utils.get_module('requests')
    if not utils.is_instrumented(requests):
        return

    from requests_opentracing import SessionTracing

    if _session_tracing_new[0] is not None:
        if hasattr(_session_tracing_new[0], '__get__'):
            SessionTracing.__new__ = _session_tracing_new[0].__get__(SessionTracing)
        else:  # builtin doesn't follow descriptor protocol
            SessionTracing.__new__ = _session_tracing_new[0]
    if _session_new[0] is not None:
        if hasattr(_session_new[0], '__get__'):
            requests.Session.__new__ = _session_new[0].__get__(requests.Session)
        else:
            requests.Session.__new__ = _session_new[0]

    utils.revert_wrapper(SessionTracing, '__init__')
    utils.mark_uninstrumented(requests)
def instrument(tracer=None):
    """
    Elasticsearch auto-instrumentation works by hooking a __new__ proxy for a TracingTransport
    instance upon elasticsearch.transports.Transport initialization to trigger proper inheritance.
    """
    elasticsearch = utils.get_module('elasticsearch')
    if utils.is_instrumented(elasticsearch):
        return

    from elasticsearch_opentracing import init_tracing, TracingTransport

    _tracer = tracer or config.tracer or opentracing.tracer
    init_tracing(_tracer, trace_all_requests=True, prefix=config.prefix)

    _transport_new[0] = elasticsearch.transport.Transport.__new__
    _tracing_transport_new[0] = TracingTransport.__new__

    TracingTransport.__new__ = tracing_transport_new.__get__(TracingTransport)
    elasticsearch.transport.Transport.__new__ = transport_new.__get__(
        elasticsearch.transport.Transport)

    utils.mark_instrumented(elasticsearch)
Пример #26
0
def uninstrument():
    celery = utils.get_module('celery')
    if not utils.is_instrumented(celery):
        return

    import celery.app

    from celery_opentracing import CeleryTracing

    if _celery_tracing_new[0] is not None:
        if hasattr(_celery_tracing_new[0], '__get__'):
            CeleryTracing.__new__ = _celery_tracing_new[0].__get__(
                CeleryTracing)
        else:  # builtin doesn't follow descriptor protocol
            CeleryTracing.__new__ = _celery_tracing_new[0]
    if _celery_new[0] is not None:
        if hasattr(_celery_new[0], '__get__'):
            celery.app.base.Celery.__new__ = _celery_new[0].__get__(
                celery.Celery)
        else:
            celery.app.base.Celery.__new__ = _celery_new[0]

    utils.revert_wrapper(CeleryTracing, '__init__')
    utils.mark_uninstrumented(celery)
Пример #27
0
def instrument(tracer=None):
    psycopg2 = utils.get_module('psycopg2')
    if psycopg2 is None or utils.is_instrumented(psycopg2):
        return

    dbapi_opentracing = utils.get_module('dbapi_opentracing')
    if dbapi_opentracing is None:
        return

    def psycopg2_tracer(connect, _, args, kwargs):
        """
        A function wrapper of psycopg2.connect() to create a corresponding
        dbapi_opentracing.ConnectionTracing upon database connection.
        """

        _tracer = tracer or config.tracer or opentracing.tracer

        traced_commands = set(config.traced_commands)
        traced_commands_kwargs = dict(trace_execute=False,
                                      trace_executemany=False,
                                      trace_callproc=False,
                                      trace_commit=False,
                                      trace_rollback=False)
        for command in traced_commands:
            flag = 'trace_{}'.format(command.lower())
            if flag not in traced_commands_kwargs:
                log.warn(
                    'Unable to trace Psycopg command "{}".  Ignoring.'.format(
                        command))
                continue
            traced_commands_kwargs[flag] = True

        span_tags = {tags.DATABASE_TYPE: 'PostgreSQL'}
        if config.span_tags is not None:
            span_tags.update(config.span_tags)

        if 'connection_factory' in kwargs:
            connection_factory = kwargs['connection_factory']
            if not inspect.isclass(connection_factory):
                log.error(
                    'connection_factory value %s is not a class, so it cannot be subclassed along with '
                    'PsycopgConnectionTracing.  No auto-instrumentation possible.',
                    connection_factory)
                return connect(*args, **kwargs)

            traced_commands_kwargs['connection_factory'] = kwargs.pop(
                'connection_factory')

        traced_commands_kwargs['tracer'] = _tracer
        traced_commands_kwargs['span_tags'] = span_tags

        def init_psycopg_connection_tracing(*a):
            return dbapi_opentracing.PsycopgConnectionTracing(
                *a, **traced_commands_kwargs)

        connection = connect(
            *args,
            connection_factory=init_psycopg_connection_tracing,
            **kwargs)
        if tags.DATABASE_INSTANCE not in span_tags:
            db_name = connection.get_dsn_parameters().get('dbname')
            if db_name:
                span_tags[tags.DATABASE_INSTANCE] = db_name

        return connection

    wrap_function_wrapper('psycopg2', 'connect', psycopg2_tracer)
    utils.mark_instrumented(psycopg2)