Match exceptions with multiple lines

We were creating regexes without the DOTALL flag, which meant '.' wasn't
matching newlines. This meant exceptions that contained multiple lines
would not be caught. For example, in my environment where Kerberos is
used, I see the following otherwise harmless message:

  (psycopg2.OperationalError) connection to server at "localhost" (::1),
  port 5432 failed: could not initiate GSSAPI security context: No
  credentials were supplied, or the credentials were unavailable or
  inaccessible: Configuration file does not specify default realm

  connection to server at "localhost" (::1), port 5432 failed: FATAL:
  database "non_existent_database" does not exist

The presence of that newline causes our matchers to fail and the
exception is not wrapped. Correct this.

In the meanwhile, we reformat the function that does the wrapping to
make it a little flatter. This was difficult to modify (for debugging
purposes) due to the level of indentation.

Change-Id: I5396a5a3272e6984954d819cfc71507283c775db
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2023-03-22 12:05:06 +00:00
parent 04acea8cbb
commit 7d62b3664e

View File

@ -44,7 +44,7 @@ def filters(dbname, exception_type, regex):
"""
def _receive(fn):
_registry[dbname][exception_type].extend(
(fn, re.compile(reg))
(fn, re.compile(reg, re.DOTALL))
for reg in
((regex,) if not isinstance(regex, tuple) else regex)
)
@ -432,35 +432,36 @@ def handler(context):
dialect = compat.dialect_from_exception_context(context)
for per_dialect in _dialect_registries(dialect):
for exc in (
context.sqlalchemy_exception,
context.original_exception):
for exc in (context.sqlalchemy_exception, context.original_exception):
for super_ in exc.__class__.__mro__:
if super_ in per_dialect:
if super_ not in per_dialect:
continue
regexp_reg = per_dialect[super_]
for fn, regexp in regexp_reg:
match = regexp.match(exc.args[0])
if match:
if not match:
continue
try:
fn(
exc,
match,
dialect.name,
context.is_disconnect)
context.is_disconnect,
)
except exception.DBError as dbe:
if (
context.connection is not None and
not context.connection.closed and
not context.connection.invalidated and
ROLLBACK_CAUSE_KEY
in context.connection.info
ROLLBACK_CAUSE_KEY in context.connection.info
):
dbe.cause = \
context.connection.info.pop(
ROLLBACK_CAUSE_KEY)
dbe.cause = context.connection.info.pop(
ROLLBACK_CAUSE_KEY,
)
if isinstance(
dbe, exception.DBConnectionError):
if isinstance(dbe, exception.DBConnectionError):
context.is_disconnect = True
# new in 2.0.5