def test_custom_tracer_provider(self): provider = TracerProvider( resource=Resource.create( { "service.name": "test", "deployment.environment": "env", "service.version": "1234", }, ), ) provider.add_span_processor( export.SimpleSpanProcessor(self.memory_exporter) ) SQLAlchemyInstrumentor().instrument(tracer_provider=provider) from sqlalchemy import create_engine # pylint: disable-all engine = create_engine("sqlite:///:memory:") cnx = engine.connect() cnx.execute("SELECT 1 + 1;").fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) self.assertEqual(spans[0].resource.attributes["service.name"], "test") self.assertEqual( spans[0].resource.attributes["deployment.environment"], "env" ) self.assertEqual( spans[0].resource.attributes["service.version"], "1234" )
def tearDown(self): # pylint: disable=invalid-name # clear the database and dispose the engine self.session.close() Base.metadata.drop_all(bind=self.engine) self.engine.dispose() SQLAlchemyInstrumentor().uninstrument() super().tearDown()
def test_sqlcommenter_disabled(self): logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO) engine = create_engine("sqlite:///:memory:", echo=True) SQLAlchemyInstrumentor().instrument( engine=engine, tracer_provider=self.tracer_provider) cnx = engine.connect() cnx.execute("SELECT 1;").fetchall() self.assertEqual(self.caplog.records[-2].getMessage(), "SELECT 1;")
def instrument_app(self) -> None: logger.info("Activating Opentelemetry tracing to app", app=self.title) trace.set_tracer_provider(tracer_provider) FastAPIInstrumentor.instrument_app(self) RequestsInstrumentor().instrument() HTTPXClientInstrumentor().instrument() RedisInstrumentor().instrument() Psycopg2Instrumentor().instrument() SQLAlchemyInstrumentor().instrument(engine=db.engine, tracer_provider=tracer_provider)
def setUp(self): # create a traced engine with the given arguments SQLAlchemyInstrumentor().instrument() dsn = ( "postgresql://%(user)s:%(password)s@%(host)s:%(port)s/%(dbname)s" % POSTGRES_CONFIG) self.engine = sqlalchemy.create_engine(dsn) # prepare a connection self.conn = self.engine.connect() super().setUp()
def test_instrument_engine_connect(self): engine = create_engine("sqlite:///:memory:") SQLAlchemyInstrumentor().instrument( engine=engine, tracer_provider=self.tracer_provider, ) engine.connect() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1)
def test_create_engine_wrapper(self): SQLAlchemyInstrumentor().instrument() from sqlalchemy import create_engine # pylint: disable-all engine = create_engine("sqlite:///:memory:") cnx = engine.connect() cnx.execute("SELECT 1 + 1;").fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) self.assertEqual(spans[0].name, "SELECT 1 + 1;")
def test_trace_integration(self): engine = create_engine("sqlite:///:memory:") SQLAlchemyInstrumentor().instrument( engine=engine, tracer_provider=self.tracer_provider, ) cnx = engine.connect() cnx.execute("SELECT 1 + 1;").fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) self.assertEqual(spans[0].name, "SELECT 1 + 1;")
async def run(): SQLAlchemyInstrumentor().instrument() from sqlalchemy.ext.asyncio import ( # pylint: disable-all create_async_engine, ) engine = create_async_engine("sqlite+aiosqlite:///:memory:") async with engine.connect() as cnx: await cnx.execute(sqlalchemy.text("SELECT 1 + 1;")) spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) self.assertEqual(spans[0].name, "SELECT :memory:") self.assertEqual(spans[0].kind, trace.SpanKind.CLIENT)
def setUp(self): super().setUp() # create an engine with the given arguments self.engine = _create_engine(self.ENGINE_ARGS) # create the database / entities and prepare a session for the test Base.metadata.drop_all(bind=self.engine) Base.metadata.create_all(self.engine, checkfirst=False) self.session = sessionmaker(bind=self.engine)() # trace the engine SQLAlchemyInstrumentor().instrument( engine=self.engine, tracer_provider=self.tracer_provider) self.memory_exporter.clear()
def test_sqlcommenter_enabled(self): engine = create_engine("sqlite:///:memory:") SQLAlchemyInstrumentor().instrument( engine=engine, tracer_provider=self.tracer_provider, enable_commenter=True, commenter_options={"db_framework": False}, ) cnx = engine.connect() cnx.execute("SELECT 1;").fetchall() self.assertRegex( self.caplog.records[-2].getMessage(), r"SELECT 1 /\*db_driver='(.*)',traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;", )
def test_instrument_two_engines(self): engine_1 = create_engine("sqlite:///:memory:") engine_2 = create_engine("sqlite:///:memory:") SQLAlchemyInstrumentor().instrument( engines=[engine_1, engine_2], tracer_provider=self.tracer_provider, ) cnx_1 = engine_1.connect() cnx_1.execute("SELECT 1 + 1;").fetchall() cnx_2 = engine_2.connect() cnx_2.execute("SELECT 1 + 1;").fetchall() spans = self.memory_exporter.get_finished_spans() # 2 queries + 2 engine connect self.assertEqual(len(spans), 4)
def test_trace_integration(self): engine = create_engine("sqlite:///:memory:") SQLAlchemyInstrumentor().instrument( engine=engine, tracer_provider=self.tracer_provider, ) cnx = engine.connect() cnx.execute("SELECT 1 + 1;").fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) # first span - the connection to the db self.assertEqual(spans[0].name, "connect") self.assertEqual(spans[0].kind, trace.SpanKind.CLIENT) # second span - the query itself self.assertEqual(spans[1].name, "SELECT :memory:") self.assertEqual(spans[1].kind, trace.SpanKind.CLIENT)
def test_not_recording(self): mock_tracer = mock.Mock() mock_span = mock.Mock() mock_span.is_recording.return_value = False mock_tracer.start_span.return_value = mock_span with mock.patch("opentelemetry.trace.get_tracer") as tracer: tracer.return_value = mock_tracer engine = create_engine("sqlite:///:memory:") SQLAlchemyInstrumentor().instrument( engine=engine, tracer_provider=self.tracer_provider, ) cnx = engine.connect() cnx.execute("SELECT 1 + 1;").fetchall() self.assertFalse(mock_span.is_recording()) self.assertTrue(mock_span.is_recording.called) self.assertFalse(mock_span.set_attribute.called) self.assertFalse(mock_span.set_status.called)
def __init__(self, uri, logger=logging): self.engine = create_engine(uri) self.logger = logger self.contacts_table = Table( "contacts", MetaData(self.engine), Column("username", String, nullable=False), Column("label", String, nullable=False), Column("account_num", String, nullable=False), Column("routing_num", String, nullable=False), Column("is_external", Boolean, nullable=False), ) # Set up tracing autoinstrumentation for sqlalchemy SQLAlchemyInstrumentor().instrument( engine=self.engine, service="contacts", )
def test_create_engine_wrapper(self): SQLAlchemyInstrumentor().instrument() from sqlalchemy import create_engine # pylint: disable-all engine = create_engine("sqlite:///:memory:") cnx = engine.connect() cnx.execute("SELECT 1 + 1;").fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) # first span - the connection to the db self.assertEqual(spans[0].name, "connect") self.assertEqual(spans[0].kind, trace.SpanKind.CLIENT) # second span - the query self.assertEqual(spans[1].name, "SELECT :memory:") self.assertEqual(spans[1].kind, trace.SpanKind.CLIENT) self.assertEqual( spans[1].instrumentation_scope.name, "opentelemetry.instrumentation.sqlalchemy", )
async def run(): SQLAlchemyInstrumentor().instrument() from sqlalchemy.ext.asyncio import ( # pylint: disable-all create_async_engine, ) engine = create_async_engine("sqlite+aiosqlite:///:memory:") async with engine.connect() as cnx: await cnx.execute(sqlalchemy.text("SELECT 1 + 1;")) spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) # first span - the connection to the db self.assertEqual(spans[0].name, "connect") self.assertEqual(spans[0].kind, trace.SpanKind.CLIENT) # second span - the query self.assertEqual(spans[1].name, "SELECT :memory:") self.assertEqual(spans[1].kind, trace.SpanKind.CLIENT) self.assertEqual( spans[1].instrumentation_scope.name, "opentelemetry.instrumentation.sqlalchemy", )
def __init__(self, uri, logger=logging): self.engine = create_engine(uri) self.logger = logger self.users_table = Table( 'users', MetaData(self.engine), Column('accountid', String, primary_key=True), Column('username', String, unique=True, nullable=False), Column('passhash', LargeBinary, nullable=False), Column('firstname', String, nullable=False), Column('lastname', String, nullable=False), Column('birthday', Date, nullable=False), Column('timezone', String, nullable=False), Column('address', String, nullable=False), Column('state', String, nullable=False), Column('zip', String, nullable=False), Column('ssn', String, nullable=False), ) # Set up tracing autoinstrumentation for sqlalchemy SQLAlchemyInstrumentor().instrument( engine=self.engine, service='users', )
def __init__(self, app, service='atlas-api', sqlalchemy_engine=None, datadog_agent=None, span_callback=None, ignored_paths: List[str] = None, sql_service=None): self.app = app trace.set_tracer_provider(TracerProvider()) self.tracer = trace.get_tracer(__name__) if datadog_agent: from ddtrace.internal.writer import AgentWriter from opentelemetry.exporter.datadog import DatadogExportSpanProcessor, \ DatadogSpanExporter exporter = DatadogSpanExporter(agent_url=datadog_agent, service=service) exporter._agent_writer = AgentWriter(datadog_agent) span_processor = DatadogExportSpanProcessor(exporter) trace.get_tracer_provider().add_span_processor(span_processor) AtlasFastAPIInstrumentor.instrument_app(app, span_callback=span_callback, ignored_paths=ignored_paths) RequestsInstrumentor().instrument() BotocoreInstrumentor().instrument(tracer_provider=trace.get_tracer_provider()) BotoInstrumentor().instrument(tracer_provider=trace.get_tracer_provider()) RedisInstrumentor().instrument(tracer_provider=trace.get_tracer_provider()) if sqlalchemy_engine: sqlalch_service_name = service if not sql_service else sql_service SQLAlchemyInstrumentor().instrument(engine=sqlalchemy_engine, service=sqlalch_service_name)
def tearDown(self): # clear the database and dispose the engine self.conn.close() self.engine.dispose() SQLAlchemyInstrumentor().uninstrument()
from opentelemetry.instrumentation.flask import FlaskInstrumentor from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor from opentelemetry.instrumentation.requests import RequestsInstrumentor from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchExportSpanProcessor app = Flask(__name__) app.config.from_object(Config) db = SQLAlchemy(app) # Set global TracerProvider before instrumenting trace.set_tracer_provider(TracerProvider()) # Enable tracing for sqlalchemy library SQLAlchemyInstrumentor().instrument() # Enable tracing for Flask library FlaskInstrumentor().instrument_app(app) # Enable tracing for requests library RequestsInstrumentor().instrument() trace_exporter = AzureMonitorSpanExporter( connection_string=Config.CONNECTION_STRING ) trace.get_tracer_provider().add_span_processor( BatchExportSpanProcessor(trace_exporter) ) # Import here to avoid circular imports
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor from sqlalchemy import Column, Integer, String, create_engine from sqlalchemy.ext.declarative import declarative_base url = "mssql+pyodbc://sa:yourStrong(!)Password@localhost:1433/repro?driver=ODBC+Driver+17+for+SQL+Server" engine = create_engine(url) SQLAlchemyInstrumentor().instrument(engine=engine, ) Base = declarative_base() class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True) name = Column(String(20)) def main(): Base.metadata.drop_all(bind=engine) if __name__ == "__main__": main()
def tearDown(self): super().tearDown() SQLAlchemyInstrumentor().uninstrument()