# Buggy code
def _new_transaction(
    self, conn, desc, after_callbacks, exception_callbacks, func, *args, **kwargs
):
    start = time.time()
    txn_id = self._TXN_ID

    # We don't really need these to be unique, so lets stop it from
    # growing really large.
    self._TXN_ID = (self._TXN_ID + 1) % (MAX_TXN_ID)

    name = "%s-%x" % (
        desc,
        txn_id,
    )

    transaction_logger.debug("[TXN START] {%s}", name)

    try:
        i = 0
        N = 5
        while True:
            try:
                txn = conn.cursor()
                txn = LoggingTransaction(
                    txn,
                    name,
                    self.database_engine,
                    after_callbacks,
                    exception_callbacks,
                )
                r = func(txn, *args, **kwargs)
                conn.commit()
                return r
            except self.database_engine.module.OperationalError as e:
                # This can happen if the database disappears mid
                # transaction.
                logger.warn("[TXN OPERROR] {%s} %s %d/%d", name, e, i, N)
                if i < N:
                    i += 1
                    try:
                        conn.rollback()
                    except self.database_engine.module.Error as e1:
                        logger.warn(
                            "[TXN EROLL] {%s} %s",
                            name,
                            e1,
                        )
                    continue
                raise
            except self.database_engine.module.DatabaseError as e:
                if self.database_engine.is_deadlock(e):
                    logger.warn("[TXN DEADLOCK] {%s} %d/%d", name, i, N)
                    if i < N:
                        i += 1
                        try:
                            conn.rollback()
                        except self.database_engine.module.Error as e1:
                            logger.warn(
                                "[TXN EROLL] {%s} %s",
                                name,
                                e1,
                            )
                        continue
                raise
    except Exception as e:
        logger.debug("[TXN FAIL] {%s} %s", name, e)
        raise
    finally:
        end = time.time()
        duration = end - start

        LoggingContext.current_context().add_database_transaction(duration)

        transaction_logger.debug("[TXN END] {%s} %f sec", name, duration)

        self._current_txn_total_time += duration
        self._txn_perf_counters.update(desc, start, end)
        sql_txn_timer.labels(desc).observe(duration)


# Traceback (UnicodeDecodeError)
2018-10-25 15:58:33,973 - twisted - 243 - ERROR - POST-299240- Traceback (most recent call last):
2018-10-25 15:58:33,973 - twisted - 243 - ERROR - POST-299240-   File "/usr/lib/python2.7/logging/handlers.py", line 76, in emit
2018-10-25 15:58:33,974 - twisted - 243 - ERROR - POST-299240-     if self.shouldRollover(record):
2018-10-25 15:58:33,974 - twisted - 243 - ERROR - POST-299240-   File "/usr/lib/python2.7/logging/handlers.py", line 156, in shouldRollover
2018-10-25 15:58:33,974 - twisted - 243 - ERROR - POST-299240-     msg = "%s\n" % self.format(record)
2018-10-25 15:58:33,974 - twisted - 243 - ERROR - POST-299240-   File "/usr/lib/python2.7/logging/__init__.py", line 734, in format
2018-10-25 15:58:33,975 - twisted - 243 - ERROR - POST-299240-     return fmt.format(record)
2018-10-25 15:58:33,975 - twisted - 243 - ERROR - POST-299240-   File "/usr/lib/python2.7/logging/__init__.py", line 476, in format
2018-10-25 15:58:33,975 - twisted - 243 - ERROR - POST-299240-     raise e
2018-10-25 15:58:33,977 - twisted - 243 - ERROR - POST-299240- UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 46: ordinal not in range(128)
2018-10-25 15:58:33,978 - twisted - 243 - ERROR - POST-299240- Logged from file _base.py, line 254
2018-10-25 15:58:33,978 - twisted - 243 - ERROR - POST-299240- Traceback (most recent call last):
2018-10-25 15:58:33,978 - twisted - 243 - ERROR - POST-299240-   File "/usr/lib/python2.7/logging/__init__.py", line 861, in emit
2018-10-25 15:58:33,978 - twisted - 243 - ERROR - POST-299240-     msg = self.format(record)
2018-10-25 15:58:33,979 - twisted - 243 - ERROR - POST-299240-   File "/usr/lib/python2.7/logging/__init__.py", line 734, in format
2018-10-25 15:58:33,979 - twisted - 243 - ERROR - POST-299240-     return fmt.format(record)
2018-10-25 15:58:33,979 - twisted - 243 - ERROR - POST-299240-   File "/usr/lib/python2.7/logging/__init__.py", line 476, in format
2018-10-25 15:58:33,979 - twisted - 243 - ERROR - POST-299240-     raise e
2018-10-25 15:58:33,980 - twisted - 243 - ERROR - POST-299240- UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 46: ordinal not in range(128)
2018-10-25 15:58:33,980 - twisted - 243 - ERROR - POST-299240- Logged from file _base.py, line 254

# Fixed code
def _new_transaction(
    self, conn, desc, after_callbacks, exception_callbacks, func, *args, **kwargs
):
    start = time.time()
    txn_id = self._TXN_ID

    # We don't really need these to be unique, so lets stop it from
    # growing really large.
    self._TXN_ID = (self._TXN_ID + 1) % (MAX_TXN_ID)

    name = "%s-%x" % (
        desc,
        txn_id,
    )

    transaction_logger.debug("[TXN START] {%s}", name)

    try:
        i = 0
        N = 5
        while True:
            try:
                txn = conn.cursor()
                txn = LoggingTransaction(
                    txn,
                    name,
                    self.database_engine,
                    after_callbacks,
                    exception_callbacks,
                )
                r = func(txn, *args, **kwargs)
                conn.commit()
                return r
            except self.database_engine.module.OperationalError as e:
                # This can happen if the database disappears mid
                # transaction.
                logger.warning(
                    "[TXN OPERROR] {%s} %s %d/%d", name, exception_to_unicode(e), i, N
                )
                if i < N:
                    i += 1
                    try:
                        conn.rollback()
                    except self.database_engine.module.Error as e1:
                        logger.warning(
                            "[TXN EROLL] {%s} %s",
                            name,
                            exception_to_unicode(e1),
                        )
                    continue
                raise
            except self.database_engine.module.DatabaseError as e:
                if self.database_engine.is_deadlock(e):
                    logger.warning("[TXN DEADLOCK] {%s} %d/%d", name, i, N)
                    if i < N:
                        i += 1
                        try:
                            conn.rollback()
                        except self.database_engine.module.Error as e1:
                            logger.warning(
                                "[TXN EROLL] {%s} %s",
                                name,
                                exception_to_unicode(e1),
                            )
                        continue
                raise
    except Exception as e:
        logger.debug("[TXN FAIL] {%s} %s", name, e)
        raise
    finally:
        end = time.time()
        duration = end - start

        LoggingContext.current_context().add_database_transaction(duration)

        transaction_logger.debug("[TXN END] {%s} %f sec", name, duration)

        self._current_txn_total_time += duration
        self._txn_perf_counters.update(desc, start, end)
        sql_txn_timer.labels(desc).observe(duration)