Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changelog/4943.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`opentelemetry-instrumentation-sqlalchemy`: avoid `IndexError` in `_operation_name` for comment-only or whitespace-only statements
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,12 @@ def _operation_name(self, db_name, statement):
# use cases and uses the SQL statement in span name correctly as per the spec.
# For some very special cases it might not record the correct statement if the SQL
# dialect is too weird but in any case it shouldn't break anything.
# Strip leading comments so we get the operation name.
parts.append(self._leading_comment_remover.sub("", statement).split()[0])
# Strip leading comments so we get the operation name. A statement that
# is truthy but has no tokens left (comment-only or whitespace-only) must
# not raise IndexError; skip adding an operation part in that case.
tokens = self._leading_comment_remover.sub("", statement).split()
if tokens:
parts.append(tokens[0])
if db_name:
parts.append(db_name)
if not parts:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ def tearDown(self):
super().tearDown()
SQLAlchemyInstrumentor().uninstrument()

def test_operation_name_comment_or_whitespace_only(self):
# Regression: a comment-only or whitespace-only statement is truthy but has
# no tokens after leading-comment stripping; _operation_name must not raise
# IndexError and should fall back to the db name / vendor.
engine = create_engine("sqlite:///:memory:")
tracer = self.tracer_provider.get_tracer(__name__)
engine_tracer = EngineTracer(tracer, engine, mock.Mock())
self.assertEqual(
engine_tracer._operation_name("mydb", "/* comment only */"), "mydb"
)
self.assertEqual(
engine_tracer._operation_name(None, " "), engine_tracer.vendor
)

def test_trace_integration(self):
engine = create_engine("sqlite:///:memory:")
SQLAlchemyInstrumentor().instrument(
Expand Down