You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
importloggingimportthreadingimporttimefrompsycopg2importpoolimportpsycopg2fromopentelemetryimporttracefromopentelemetry.instrumentation.psycopg2importPsycopg2Instrumentorfromopentelemetry.sdk.resourcesimportSERVICE_NAME, Resourcefromopentelemetry.exporter.otlp.proto.grpc.trace_exporterimportOTLPSpanExporterfromopentelemetry.sdk.traceimportTracerProviderfromopentelemetry.sdk.trace.exportimportBatchSpanProcessor# this database use the connection pollclassPostgresDatabasePool:
def__init__(self, minconn, maxconn, host, database, user, password, port):
self.db_pool=pool.ThreadedConnectionPool(
minconn=minconn,
maxconn=maxconn,
host=host,
database=database,
user=user,
password=password,
port=port
)
defexecute_query(self, query):
conn=Nonecursor=Nonetry:
conn=self.db_pool.getconn()
cursor=conn.cursor()
cursor.execute(query)
logging.info(f"execute command: {query}")
exceptExceptionase:
logging.error(f"SQL error: {e}")
finally:
ifcursor:
cursor.close()
ifconn:
self.db_pool.putconn(conn)
# this database use the default connectclassPostgresDatabase:
def__init__(self, host, database, user, password, port):
self.conn=psycopg2.connect(
host=host,
database=database,
user=user,
password=password,
port=port
)
self.conn.autocommit=Trueself.cursor=self.conn.cursor()
defexecute_query(self, query):
ifnotself.cursor:
logging.warning("Please connect first")
returntry:
self.cursor.execute(query)
logging.info(f"execute command: {query}")
exceptExceptionase:
logging.error(f"SQL error: {e}")
defdelete1_with_db_pool(thread_name):
whileTrue:
withtracer.start_as_current_span("delete1_with_db_pool", kind=trace.SpanKind.INTERNAL):
dbPool.execute_query("DELETE FROM public.test1;")
dbPool.execute_query("DELETE FROM public.test1;")
dbPool.execute_query("DELETE FROM public.test1;")
dbPool.execute_query("DELETE FROM public.test1;")
dbPool.execute_query("DELETE FROM public.test1;")
time.sleep(5)
defdelete2_with_db_pool(thread_name):
whileTrue:
withtracer.start_as_current_span("delete2_with_db_pool", kind=trace.SpanKind.INTERNAL):
dbPool.execute_query("DELETE FROM public.test2;")
dbPool.execute_query("DELETE FROM public.test2;")
dbPool.execute_query("DELETE FROM public.test2;")
dbPool.execute_query("DELETE FROM public.test2;")
dbPool.execute_query("DELETE FROM public.test2;")
time.sleep(5)
defdelete1(thread_name):
whileTrue:
withtracer.start_as_current_span("delete1", kind=trace.SpanKind.INTERNAL):
db.execute_query("DELETE FROM public.test1;")
db.execute_query("DELETE FROM public.test1;")
db.execute_query("DELETE FROM public.test1;")
db.execute_query("DELETE FROM public.test1;")
db.execute_query("DELETE FROM public.test1;")
time.sleep(5)
defdelete2(thread_name):
whileTrue:
withtracer.start_as_current_span("delete2", kind=trace.SpanKind.INTERNAL):
db.execute_query("DELETE FROM public.test2;")
db.execute_query("DELETE FROM public.test2;")
db.execute_query("DELETE FROM public.test2;")
db.execute_query("DELETE FROM public.test2;")
db.execute_query("DELETE FROM public.test2;")
time.sleep(5)
# tracingresource=Resource(attributes={SERVICE_NAME: 'Demo_Bug'})
provider=TracerProvider(resource=resource)
otlp_exporter=OTLPSpanExporter(endpoint='localhost:4317', insecure=True)
provider.add_span_processor(BatchSpanProcessor(otlp_exporter))
trace.set_tracer_provider(provider)
tracer=trace.get_tracer("test", "1.0.0")
# Psycopg2Psycopg2Instrumentor().instrument()
# init databasedbPool=PostgresDatabasePool(1, 5, "localhost", "example", "root", "12345678", 5432)
db=PostgresDatabase("localhost", "example", "root", "12345678", 5432)
# create tabledb.execute_query("CREATE TABLE IF NOT EXISTS public.test1 (id serial NOT NULL , text varchar(64) NOT NULL);")
db.execute_query("CREATE TABLE IF NOT EXISTS public.test2 (id serial NOT NULL , text varchar(64) NOT NULL);")
# init threadthreads= [threading.Thread(target=delete1_with_db_pool, args=("Thread-1",)), threading.Thread(target=delete2_with_db_pool, args=("Thread-2",)),
threading.Thread(target=delete1, args=("Thread-3",)), threading.Thread(target=delete2, args=("Thread-4",))]
# startforthreadinthreads:
thread.start()
# waitforthreadinthreads:
thread.join()
Run command
docker-compose up -d
pip install -r requirements.txt
python index.py
What is the expected behavior?
The result of tracing methods delete1_with_db_pool and delete2_with_db_pool should be the same as delete1 and delete2.
What is the actual behavior?
Additional context
I suspect the problem lies in our use of the pool.ThreadedConnectionPool() function in the psycopg2 library to reuse the database connection. It seems that opentelemetry-instrumentation-psycopg2 hasn't taken this case.
changemyminds
changed the title
Recursion issue in database operations when using opentelemetry-instrumentation-psycopg2 with psycopg2's ThreadedConnectionPool
Recursive tracing issue in database operations when using opentelemetry-instrumentation-psycopg2 with psycopg2's ThreadedConnectionPool
Aug 31, 2023
After I switched the Python version and ran the same code for testing, the final test result changed.
If you use Python version between 3.6 and 3.8 for testing, you will encounter a recursion issue. However, if you use versions between 3.9 and 3.11, the recursive issue does not appear. It's very strange.
Here are my test result after switching Python versions:
3.6.15 (has a recursion issue)
3.7.16 (has a recursion issue)
3.8.16 (has a recursion issue)
3.9.16 (works well)
3.10.9 (works well)
3.11.1 (works well)
I suspect that the root cause is the Python version, if you want to use psycopg2's ThreadedConnectionPool. make sure your Python version is above 3.9.x; otherwise, you will encounter a recursion issue.
Describe your environment
Language & Library
Infra (Docker Image)
Steps to reproduce
Prepare
Run command
What is the expected behavior?
The result of tracing methods
delete1_with_db_pool
anddelete2_with_db_pool
should be the same asdelete1
anddelete2
.What is the actual behavior?
Additional context
I suspect the problem lies in our use of the
pool.ThreadedConnectionPool()
function in thepsycopg2
library to reuse the database connection. It seems thatopentelemetry-instrumentation-psycopg2
hasn't taken this case.#355
#381
The text was updated successfully, but these errors were encountered: