25.Tracing python-oracledb
25.1.Application Tracing
There are multiple approaches for application tracing and monitoring:
End-to-end database tracing attributes such as
Connection.action
andConnection.module
are supported in thepython-oracledb Thin and Thick modes. Using these attributes is recommendedsince they aid application monitoring and troubleshooting.You cansubclass python-oracledb classes and implementyour own driver API call tracing and logging. Also, the standardPythontracing capabilities can beused.
The Java Debug Wire Protocol (JDWP) for debugging PL/SQL can be used. SeeDebugging PL/SQL with the Java Debug Wire Protocol.
Instrumentation libraries such as OpenTelemetry allow sophisticatedmonitoring, seeUsing python-oracledb with OpenTelemetry.
Python-oracledb in Thick mode can dump a trace of SQL statementsexecuted. SeeLow Level SQL Tracing.
The unique connection identifiers that appear in connection error messages,and in Oracle Database traces and logs, can be used to resolve connectivityerrors. SeeUsing Connection Identifiers.
25.1.1.Oracle Database End-to-End Tracing
Oracle Database end-to-end application tracing simplifies diagnosingapplication code flow and performance problems in multi-tier or multi-userenvironments.
The connection attributesConnection.client_identifier
,Connection.clientinfo
,Connection.dbop
,Connection.module
, andConnection.action
set metadata forend-to-end tracing. The values can be queried from data dictionary and dynamicperformance views to monitor applications, or you can use tracingutilities. Values may appear in logs and audit trails.
Also seeConnection Metadata and Application Contexts for information about setting Application Contexts.
TheConnection.client_identifier
attribute is typically set to the name(or identifier) of the actual end user initiating a query. This allows thedatabase to distinguish, and trace, end users for applications that connectusing a common database username. It can also be used byOracle VirtualPrivate Database (VPD) policies to automatically limitdata access. Oracle Database’sDBMS_MONITOR package can take advantage of theclient identifer to enable statistics and tracing at an individual level.
TheConnection.module
andConnection.action
attributes can beset to user-chosen, descriptive values identifying your code architecture.
After attributes are set, the values are sent to the database when the nextround-trip to the database occurs, for example when thenext SQL statement is executed.
The attribute values will remain set in connections released back to aconnection pool. When the application re-acquires a connection from the pool,it should initialize the values to a desired state before using thatconnection.
The example below shows setting the action, module, and client identifierattributes on a connection object, and then querying a view to see the recordedvalues. The example both sets and queries the values, but typically monitoringis done externally to the application.
# Set the tracing metadataconnection.client_identifier="pythonuser"connection.action="Query Session tracing parameters"connection.module="End-to-end Demo"forrowincursor.execute(""" SELECT username, client_identifier, module, action FROM V$SESSION WHERE sid = SYS_CONTEXT('USERENV', 'SID')"""):print(row)
The output will be like:
('SYSTEM','pythonuser','End-to-end Demo','Query Session tracing parameters')
The values can also be manually set by callingDBMS_APPLICATION_INFO procedures orDBMS_SESSION.SET_IDENTIFIER. These incurround-trips to the database which reduces application scalability:
BEGINDBMS_SESSION.SET_IDENTIFIER('pythonuser');DBMS_APPLICATION_INFO.set_module('End-to-End Demo');DBMS_APPLICATION_INFO.set_action(action_name=>'Query Session tracing parameters');END;
TheConnection.dbop
attribute can be used for Real-Time SQL Monitoring,seeMonitoring Database Operations. The value willbe shown in the DBOP_NAME column of theV$SQL_MONITORview:
connection.dbop="my op"forrowincursor.execute(""" SELECT dbop_name FROM V$SQL_MONITOR WHERE sid = SYS_CONTEXT('USERENV', 'SID')"""):print(row)
25.1.2.Debugging PL/SQL with the Java Debug Wire Protocol
The Java Debug Wire Protocol (JDWP) for debugging PL/SQL can be used withpython-oracledb.
Python-oracledb applications that call PL/SQL can step through that PL/SQL codeusing JDWP in a debugger. This allows Python and PL/SQL code to be debugged inthe same debugger environment. You can enable PL/SQL debugging inpython-oracledb as follows:
In python-oracledb Thin or Thick modes, set the
ORA_DEBUG_JDWP
environment variable tohost=hostname;port=portnum indicating where thePL/SQL debugger is running. Then run the application.In python-oracledb Thin mode, you can alternatively set the connectionparameter
debug_jdwp
during connection. This variable defaults to thevalue of theORA_DEBUG_JDWP
environment variable.
See the documentation onDBMS_DEBUG_JDWP, the videoPL/SQL debugging with Visual Studio andVisual Studio Code, and theblog postDebugging PL/SQL with Visual Studio Code (and more).
25.1.3.Low Level SQL Tracing
The Thick mode of python-oracledb is implemented using theODPI-C wrapper on top of the Oracle Clientlibraries. The ODPI-C tracing capability can be used to log executedpython-oracledb statements to the standard error stream. Before executingPython, set the environment variableDPI_DEBUG_LEVEL
to 16 in your terminalwindow.
On Linux, you might use:
exportDPI_DEBUG_LEVEL=16
On Windows, this could be done with:
setDPI_DEBUG_LEVEL=16
After setting the variable, run the Python Script, for example on Linux:
pythonend-to-endtracing.py2>log.txt
For an application that does a single query, the log file might contain atracing line consisting of the prefix ‘ODPI’, a thread identifier, a timestamp,and the SQL statement executed:
ODPI[23389068]2025-06-2512:07:55.405:ODPI-C5.5.1ODPI[23389068]2025-06-2512:07:55.405:debuggingmessagesinitializedatlevel16ODPI[23389068]2025-06-2512:08:01.363:SQLselectnamefromjobs
SeeODPI-C Debugging fordocumentation onDPI_DEBUG_LEVEL
.
25.1.4.Using Connection Identifiers
A unique connection identifier (CONNECTION_ID
) is generated for eachconnection to the Oracle Database. The connection identifier is shown in someOracle Network error messages and logs, which helps in better tracing anddiagnosing of connection failures. For example:
DPY-6005:cannotconnecttodatabase(CONNECTION_ID=m0PfUY6hYSmWPcgrHZCQIQ==)
Depending on the Oracle Database version in use, the information that is shownin logs varies.
You can define a prefix value which is added to the beginning of theCONNECTION_ID
value. This prefix aids in identifying the connections from aspecific application.
SeeTroubleshooting Oracle Net Services for moreinformation on connection identifiers.
Python-oracledb Thin mode
In python-oracledb Thin mode, you can specify a prefix using theconnection_id_prefix
parameter when creatingstandaloneconnections
orpooledconnections
,or alternatively set a prefix when callingoracledb.ConnectParams()
ororacledb.PoolParams()
. For example:
connection=oracledb.connect(user="hr",password=userpwd,dsn="localhost/orclpdb",connection_id_prefix="MYAPP")
If this connection to the database fails,MYAPP
is added as a prefix to theCONNECTION_ID
value shown in the error message, for example:
DPY-6005:cannotconnecttodatabase(CONNECTION_ID=MYAPPm0PfUY6hYSmWPcgrHZCQIQ==).
Python-oracledb Thick mode
In python-oracledb Thick mode, you can specify the connection identifier prefixin the connection string or connect descriptor. For example:
mydb=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=...)(ADDRESS=...))(CONNECT_DATA=(SERVICE_NAME=sales.us.example.com)(CONNECTION_ID_PREFIX=MYAPP)))
25.1.5.Tracing Bind Values
Several methods for tracing bind variable values can be used. When tracing bindvariable values, be careful not to leak information and create a securityproblem.
In Oracle Database, the viewV$SQL_BIND_CAPTUREcan capture bind information. Tracing with Oracle Database’sDBMS_MONITORpackage may also be useful.
You can additionallysubclass python-oracledb classes andlog any bind values.
OpenTelemetry can also be used, seeUsing python-oracledb with OpenTelemetry.
25.1.6.Database Views for Tracing python-oracledb
This section shows some of the Oracle Database views useful for tracing andmonitoring python-oracledb. Other views and columns not described here alsocontain useful information, such as theDatabase Resident Connection Pooling (DRCP) views discussed inMonitoring DRCP, and the views discussed inOracle Database End-to-End Tracing andTracing Bind Values.
25.1.6.1.V$SESSION
The following table shows sample values for someV$SESSION columns. You may see other valuesif you have changed the defaults using theDefaults objectbefore connecting, set the equivalent connection or pool creation parameters,or set the attributeConnection.module
as shown inOracle Database End-to-End Tracing.
Column | Sample Thin mode value | Sample Thick mode value |
---|---|---|
MACHINE | “myusername-mac” | “myusername-mac” |
MODULE | The value of Python’s | Similar topython@myusername-mac (TNS V1-V3) |
OSUSER | “myusername” | “myusername” |
PROGRAM | The value of Python’s | Similar topython@myusername-mac (TNS V1-V3) |
TERMINAL | “unknown” | Similar tottys001 |
25.1.6.2.V$SESSION_CONNECT_INFO
The following table shows sample values for someV$SESSION_CONNECT_INFO columns. You may see othervalues if you have changed the defaults using theDefaults object before connecting, set the equivalent connection or pool creationparameters, or set thedriver_name
parameter inoracledb.init_oracle_client()
.
Column | Sample Thin mode value | Sample Thick mode value |
---|---|---|
CLIENT_DRIVER | “python-oracledb thn : 3.2.0” | “python-oracledb thk : 3.2.0” |
CLIENT_OCI_LIBRARY | “Unknown” | The Oracle Client or Instant Client type, such as “Full Instant Client” |
CLIENT_VERSION | “3.2.0.0.0” (the python-oracledb version number with an extra .0.0) | The Oracle Client library version number |
OSUSER | “myusername” | “myusername” |
25.2.Using python-oracledb with OpenTelemetry
The OpenTelemetry observability framework is useful for monitoring applicationsand identifying bottlenecks. Python-oracledb conforms to thePython DB APIspecification allowing standard Pythonmodules for OpenTelemetry to be used to instrument your applications.
OpenTelemetry’sbackend trace exporters can providegraphic and intuitive representation of OpenTelemetry trace information. Visualexporters include Zipkin, Jaeger, and Prometheus. Simple tracing can also bedirected to the console by making use of the exporter ConsoleSpanExporter fromthe opentelemetry-sdk package.
For details on using OpenTelemetry in Python, seePython OpenTelemetrydocumentation.
25.2.1.Example of Using python-oracledb with OpenTelemetry
This example shows a python-oracledb application using OpenTelemetry’sConsoleSpanExporter exporter to display trace information to the console.
Installing OpenTelemetry Modules
For this example, install:
python-mpipinstallopentelemetry-sdkopentelemetry-apiopentelemetry-instrumentation-dbapi
Sample Application
This simple application performs two queries in a custom span. It also sets theservice name and system attributes to user-chosen values. It uses thecapture_parameters
option to enable bind variable tracing.
Warning
The trace integration settingcapture_parameters=True
capturesbind variable values and is a security risk.
The sample code is:
importoracledbfromopentelemetryimporttracefromopentelemetry.sdk.traceimportTracerProviderfromopentelemetry.sdk.trace.exportimport(BatchSpanProcessor,ConsoleSpanExporter,)fromopentelemetry.sdk.resourcesimportResourceuser="hr"password=userpwdhost="dbhost.example.com"service_name="orclpdb"resource=Resource(attributes={"service.name":service_name,# displayed as a resource attribute "service.name"})provider=TracerProvider(resource=resource)processor=BatchSpanProcessor(ConsoleSpanExporter())provider.add_span_processor(processor)trace.set_tracer_provider(provider)fromopentelemetry.instrumentation.dbapiimporttrace_integrationtrace_integration(oracledb,connect_method_name="connect",database_system="oracle",# displayed as attribute "db.system"capture_parameters=True,# displayed as attribute "db.statement.parameters"# WARNING: this shows bind variable values)connection=oracledb.connect(user=user,password=password,host=host,service_name=service_name)withconnection.cursor()ascursor:tracer=trace.get_tracer("HR-tracer-name")withtracer.start_as_current_span("HR-span-1")asspan:sql="select city from locations where location_id = :1"forr,incursor.execute(sql,[2200]):print(r)sql="select 'Hello World!' from dual"forr,incursor.execute(sql):print(r)
Sample Output
The sample output will be like:
SydneyHello World!{ "name": "select", "context": { "trace_id": "0xb24817cd2ea38ffa523c2ee2778508f7", "span_id": "0xacfd82ed60e8976d", "trace_state": "[]" }, "kind": "SpanKind.CLIENT", "parent_id": "0x19027598c301cfac", "start_time": "2025-05-29T08:40:10.194645Z", "end_time": "2025-05-29T08:40:10.209815Z", "status": { "status_code": "UNSET" }, "attributes": { "db.system": "oracle", "db.name": "", "db.statement": "select city from locations where location_id = :1", "db.statement.parameters": "[2200]" }, "events": [], "links": [], "resource": { "attributes": { "service.name": "orclpdb1" }, "schema_url": "" }}{ "name": "select", "context": { "trace_id": "0xb24817cd2ea38ffa523c2ee2778508f7", "span_id": "0x376dff430f66b14f", "trace_state": "[]" }, "kind": "SpanKind.CLIENT", "parent_id": "0x19027598c301cfac", "start_time": "2025-05-29T08:40:10.210799Z", "end_time": "2025-05-29T08:40:10.214694Z", "status": { "status_code": "UNSET" }, "attributes": { "db.system": "oracle", "db.name": "", "db.statement": "select 'Hello World!' from dual" }, "events": [], "links": [], "resource": { "attributes": { "service.name": "orclpdb1" }, "schema_url": "" }}{ "name": "HR-span-1", "context": { "trace_id": "0xb24817cd2ea38ffa523c2ee2778508f7", "span_id": "0x19027598c301cfac", "trace_state": "[]" }, "kind": "SpanKind.INTERNAL", "parent_id": null, "start_time": "2025-05-29T08:40:10.194536Z", "end_time": "2025-05-29T08:40:10.214732Z", "status": { "status_code": "UNSET" }, "attributes": {}, "events": [], "links": [], "resource": { "attributes": { "service.name": "orclpdb1" }, "schema_url": "" }}
The two query results precede OpenTelemetry’s tracing. The tracing then shows:
The start and end time of each operation.
Each “select” trace block’s association to the span “HR-span-1” via their
parent_id
values, which match the span’sspan_id
value.The bind variable value2200 in the attribute
db.statement.parameters
.Warning: it is a security risk to monitor bindvariable values this way. Keep thecapture_parameters
option set toFalse.The system and service name as set in the application.
The Python OpenTelemetry modules allow further customization for tracing. Seetheir documentation for more information.
When a graphical provider is used instead of ConsoleSpanExporter, the databasequery relationships and timings are easier to analyze.
25.3.Finding the python-oracledb Mode
The boolean attributesConnection.thin
andConnectionPool.thin
can be used to show the current mode of a python-oracledb connection or pool,respectively. The methodoracledb.is_thin_mode()
can also be used, butreview its usage notes about when its return value may change.
For example, to show the mode used by a connection:
print(connection.thin)
The python-oracledb version can be shown withoracledb.__version__
:
print(oracledb.__version__)
Version and mode information can also be seen in the Oracle Database datadictionary tableV$SESSION_CONNECT_INFO:
withconnection.cursor()ascursor:sql="""SELECT UNIQUE client_driver FROM V$SESSION_CONNECT_INFO WHERE sid = SYS_CONTEXT('USERENV', 'SID')"""forr,incursor.execute(sql):print(r)
In python-oracledb Thin mode, the output will be like:
python-oracledbthn:3.2.0
In python-oracledb Thick mode, the output will be like:
python-oracledbthk:3.2.0
Note that you may not see these values if you have setoracledb.defaults.driver_name
or thedriver_name
parameter inoracledb.init_oracle_client()
.
25.4.Low Level Python-oracledb Driver Tracing
Low level tracing is mostly useful to maintainers of python-oracledb.
For python-oracledb Thin mode, packets can be traced by setting theenvironment variable PYO_DEBUG_PACKETS in your terminal window before runningyour application.
For example, on Linux, you might use:
exportPYO_DEBUG_PACKETS=1
On Windows you might set the variable like:
setPYO_DEBUG_PACKETS=1
Alternatively, the variable can be set in the application:
importosos.environ["PYO_DEBUG_PACKETS"]="1"importoracledb
The output goes to stdout. The information logged is roughly similar to anOracle Net trace of level 16, seeOracle Net Services TRACE_LEVEL_CLIENT.
Python-oracledb Thick mode can be traced using:
DPI_DEBUG_LEVEL as documented inODPI-C Debugging.
Oracle Call Interface (OCI) tracing as directed by Oracle Support.
Oracle Net services tracing as documented inOracle Net Services TracingParameters.