Пример #1
0
    def before_cursor_execute(conn, cursor, sql, parameters, context,
                              executemany):
        data = dict(
            # TODO: Figure out how to retrieve the exact driver version.
            db_driver=conn.engine.driver,
            # Driver/framework centric information.
            db_framework='sqlalchemy:%s' % sqlalchemy.__version__,
        )

        # Because sqlalchemy is a plain database connectivity module,
        # folks using it in a web framework such as flask will
        # use it in unison with flask but initialize the parts disjointly,
        # unlike Django which uses ORMs directly as part of the framework.
        data.update(get_flask_info())

        # Filter down to just the requested attributes.
        data = {k: v for k, v in data.items() if attributes.get(k)}

        if with_opencensus:
            data.update(get_opencensus_values())

        sql_comment = generate_sql_comment(**data)

        # TODO: Check if the database type is MySQL and figure out
        # if we should prepend comments because MySQL server truncates
        # logs greater than 1kB.
        # See:
        #  * https://github.com/basecamp/marginalia/issues/61
        #  * https://github.com/basecamp/marginalia/pull/80
        sql += sql_comment

        return sql, parameters
Пример #2
0
 def test_opencensus_enabled(self):
     with mock_opencensus_tracer():
         self.assertEqual(
             generate_sql_comment(with_opencensus=True),
             " /*traceparent='00-trace%%20id-span%%20id-00',"
             "tracestate='congo%%3Dt61rcWkgMzE%%2Crojo%%3D00f067aa0ba902b7'*/"
         )
Пример #3
0
        def execute(self, sql, args=None):
            data = dict(
                # Psycopg2/framework information
                db_driver='psycopg2:%s' % psycopg2.__version__,
                dbapi_threadsafety=psycopg2.threadsafety,
                dbapi_level=psycopg2.apilevel,
                libpq_version=psycopg2.__libpq_version__,
                driver_paramstyle=psycopg2.paramstyle,
            )

            # Because psycopg2 is a plain database connectivity module,
            # folks using it in a web framework such as flask will
            # use it in unison with flask but initialize the parts disjointly,
            # unlike Django which uses ORMs directly as part of the framework.
            data.update(get_flask_info())

            # Filter down to just the requested attributes.
            data = {k: v for k, v in data.items() if attributes.get(k)}

            if with_opencensus:
                data.update(get_opencensus_values())

            sql += generate_sql_comment(**data)

            return psycopg2.extensions.cursor.execute(self, sql, args)
Пример #4
0
    def __call__(self, execute, sql, params, many, context):
        with_framework = getattr(django.conf.settings,
                                 'SQLCOMMENTER_WITH_FRAMEWORK', True)
        with_controller = getattr(django.conf.settings,
                                  'SQLCOMMENTER_WITH_CONTROLLER', True)
        with_route = getattr(django.conf.settings, 'SQLCOMMENTER_WITH_ROUTE',
                             True)
        with_app_name = getattr(django.conf.settings,
                                'SQLCOMMENTER_WITH_APP_NAME', False)
        with_opencensus = getattr(django.conf.settings,
                                  'SQLCOMMENTER_WITH_OPENCENSUS', False)
        with_opentelemetry = getattr(django.conf.settings,
                                     'SQLCOMMENTER_WITH_OPENTELEMETRY', False)
        with_db_driver = getattr(django.conf.settings,
                                 'SQLCOMMENTER_WITH_DB_DRIVER', False)

        if with_opencensus and with_opentelemetry:
            logger.warning(
                "SQLCOMMENTER_WITH_OPENCENSUS and SQLCOMMENTER_WITH_OPENTELEMETRY were enabled. "
                "Only use one to avoid unexpected behavior")

        db_driver = context['connection'].settings_dict.get('ENGINE', '')
        resolver_match = self.request.resolver_match

        sql_comment = generate_sql_comment(
            # Information about the controller.
            controller=resolver_match.view_name
            if resolver_match and with_controller else None,
            # route is the pattern that matched a request with a controller i.e. the regex
            # See https://docs.djangoproject.com/en/stable/ref/urlresolvers/#django.urls.ResolverMatch.route
            # getattr() because the attribute doesn't exist in Django < 2.2.
            route=getattr(resolver_match, 'route', None)
            if resolver_match and with_route else None,
            # app_name is the application namespace for the URL pattern that matches the URL.
            # See https://docs.djangoproject.com/en/stable/ref/urlresolvers/#django.urls.ResolverMatch.app_name
            app_name=(resolver_match.app_name or None)
            if resolver_match and with_app_name else None,
            # Framework centric information.
            framework=('django:%s' %
                       django_version) if with_framework else None,
            # Information about the database and driver.
            db_driver=db_driver if with_db_driver else None,
            **get_opencensus_values() if with_opencensus else {},
            **get_opentelemetry_values() if with_opentelemetry else {})

        # TODO: MySQL truncates logs > 1024B so prepend comments
        # instead of statements, if the engine is MySQL.
        # See:
        #  * https://github.com/basecamp/marginalia/issues/61
        #  * https://github.com/basecamp/marginalia/pull/80
        sql += sql_comment

        # Add the query to the query log if debugging.
        if execute.__self__.__class__ is CursorDebugWrapper:
            execute.__self__.db.queries_log.append(sql)

        return execute(sql, params, many, context)
Пример #5
0
 def test_opencensus_disabled(self):
     with mock_opencensus_tracer():
         self.assertEqual(generate_sql_comment(with_opencensus=False), '')
Пример #6
0
 def test_opencensus_not_available(self):
     self.assertEqual(generate_sql_comment(with_opencensus=True), '')
     self.assertEqual(generate_sql_comment(with_opencensus=False), '')
Пример #7
0
 def test_url_quoting(self):
     self.assertIn("foo='bar%%2Cbaz'", generate_sql_comment(foo='bar,baz'))
Пример #8
0
 def test_end_comment_escaping(self):
     self.assertIn(r'%%2A/abc', generate_sql_comment(a='*/abc'))
Пример #9
0
 def test_no_args(self):
     # As per internal issue #28, we've commented out
     # the old defaults such as os.uname() information.
     self.assertEqual(generate_sql_comment(), '')
 def test_bytes(self):
     self.assertIn("a='%%2A/abc'", generate_sql_comment(a=b'*/abc'))
 def test_no_args(self):
     self.assertEqual(generate_sql_comment(), '')