refactor(logging): use logger.exception to preserve stack traces

Unify error logging across services: replace logger.error(f"...{e}")
and logger.error(..., exc_info=True) with logger.exception() so the
stack trace is consistently captured.
This commit is contained in:
3252a8
2026-04-27 08:43:48 +03:00
parent f1113eb80a
commit d6b703debb
9 changed files with 68 additions and 71 deletions
+14 -14
View File
@@ -121,16 +121,16 @@ class CryptoPayService:
str(invoice.status),
)
await session.commit()
except Exception as e_db_update:
except Exception:
await session.rollback()
logging.error(
f"Failed to update cryptopay payment record {payment_record.payment_id}: {e_db_update}",
exc_info=True,
logging.exception(
"Failed to update cryptopay payment record %s.",
payment_record.payment_id,
)
return None
return invoice.bot_invoice_url
except Exception as e:
logging.error(f"CryptoPay invoice creation failed: {e}", exc_info=True)
except Exception:
logging.exception("CryptoPay invoice creation failed.")
return None
async def _invoice_paid_handler(self, update: Update, app: web.Application):
@@ -145,8 +145,8 @@ class CryptoPayService:
payment_db_id = int(meta["payment_db_id"])
sale_mode = meta.get("sale_mode") or ("traffic" if self.settings.traffic_sale_mode else "subscription")
traffic_gb = float(meta.get("traffic_gb")) if meta.get("traffic_gb") else months
except Exception as e:
logging.error(f"Failed to parse CryptoPay payload: {e}")
except Exception:
logging.exception("Failed to parse CryptoPay payload.")
return
async_session_factory: sessionmaker = app["async_session_factory"]
@@ -184,9 +184,9 @@ class CryptoPayService:
skip_if_active_before_payment=False,
)
await session.commit()
except Exception as e:
except Exception:
await session.rollback()
logging.error(f"Failed to process CryptoPay invoice: {e}", exc_info=True)
logging.exception("Failed to process CryptoPay invoice.")
return
db_user = await user_dal.get_user_by_id(session, user_id)
@@ -247,8 +247,8 @@ class CryptoPayService:
parse_mode="HTML",
disable_web_page_preview=True,
)
except Exception as e:
logging.error(f"Failed to send CryptoPay success message: {e}")
except Exception:
logging.exception("Failed to send CryptoPay success message.")
# Send notification about payment
try:
@@ -263,8 +263,8 @@ class CryptoPayService:
payment_provider="crypto_pay",
username=user.username if user else None
)
except Exception as e:
logging.error(f"Failed to send crypto_pay payment notification: {e}")
except Exception:
logging.exception("Failed to send crypto_pay payment notification.")
def _validate_webhook_signature(self, raw_body: bytes, signature: str) -> bool:
if not self.token:
+9 -9
View File
@@ -137,7 +137,7 @@ class FreeKassaService:
return True, response_data
except Exception as exc:
logging.error("FreeKassa create_order: request failed: %s", exc, exc_info=True)
logging.exception("FreeKassa create_order: request failed.")
return False, {"message": str(exc)}
async def _get_session(self) -> ClientSession:
@@ -196,8 +196,8 @@ class FreeKassaService:
return web.Response(status=403)
raw_body = await request.read()
except Exception as e:
logging.error("FreeKassa webhook: failed to read request body: %s", e)
except Exception:
logging.exception("FreeKassa webhook: failed to read request body.")
return web.Response(status=400, text="bad_request")
payload_dict: Dict[str, Any] = {}
@@ -299,9 +299,9 @@ class FreeKassaService:
)
await session.commit()
except Exception as e:
except Exception:
await session.rollback()
logging.error(f"FreeKassa webhook: failed to process payment {payment_db_id}: {e}", exc_info=True)
logging.exception("FreeKassa webhook: failed to process payment %s.", payment_db_id)
return web.Response(status=500, text="processing_error")
db_user = payment.user or await user_dal.get_user_by_id(session, payment.user_id)
@@ -385,8 +385,8 @@ class FreeKassaService:
parse_mode="HTML",
disable_web_page_preview=True,
)
except Exception as e:
logging.error(f"FreeKassa notification: failed to send message to user {payment.user_id}: {e}")
except Exception:
logging.exception("FreeKassa notification: failed to send message to user %s.", payment.user_id)
try:
notification_service = NotificationService(self.bot, self.settings, self.i18n)
@@ -399,8 +399,8 @@ class FreeKassaService:
payment_provider="freekassa",
username=db_user.username if db_user else None,
)
except Exception as e:
logging.error(f"FreeKassa notification: failed to notify admins: {e}")
except Exception:
logging.exception("FreeKassa notification: failed to notify admins.")
return web.Response(text="YES")
+8 -8
View File
@@ -120,8 +120,8 @@ class NotificationService:
logging.error(
f"Failed to send notification to log channel {self.settings.LOG_CHAT_ID}: {exc}"
)
except Exception as e:
logging.error(f"Failed to send notification to log channel {self.settings.LOG_CHAT_ID}: {e}")
except Exception:
logging.exception("Failed to send notification to log channel %s.", self.settings.LOG_CHAT_ID)
return
try:
@@ -143,8 +143,8 @@ class NotificationService:
# Queue message for sending (groups are rate limited to 15/minute)
await queue_manager.send_message(self.settings.LOG_CHAT_ID, **kwargs)
except Exception as e:
logging.error(f"Failed to queue notification to log channel {self.settings.LOG_CHAT_ID}: {e}")
except Exception:
logging.exception("Failed to queue notification to log channel %s.", self.settings.LOG_CHAT_ID)
async def _send_to_admins(self, message: str):
"""Send message to all admin users using message queue"""
@@ -162,8 +162,8 @@ class NotificationService:
parse_mode="HTML",
disable_web_page_preview=True
)
except Exception as e:
logging.error(f"Failed to send notification to admin {admin_id}: {e}")
except Exception:
logging.exception("Failed to send notification to admin %s.", admin_id)
return
for admin_id in self.settings.ADMIN_IDS:
@@ -174,8 +174,8 @@ class NotificationService:
parse_mode="HTML",
disable_web_page_preview=True
)
except Exception as e:
logging.error(f"Failed to queue notification to admin {admin_id}: {e}")
except Exception:
logging.exception("Failed to queue notification to admin %s.", admin_id)
async def notify_new_user_registration(self, user_id: int, username: Optional[str] = None,
first_name: Optional[str] = None,
+1 -1
View File
@@ -174,7 +174,7 @@ class PanelApiService:
"message": f"Connection error: {str(e)}"
}
except aiohttp.ClientError as e:
logging.error(f"Panel API ClientError to {url_for_request}: {e}")
logging.exception("Panel API ClientError to %s.", url_for_request)
return {
"error": True,
"status_code": -2,
+11 -11
View File
@@ -127,7 +127,7 @@ class PlategaService:
return True, response_data
except Exception as exc:
logging.error("Platega create_transaction: request failed: %s", exc, exc_info=True)
logging.exception("Platega create_transaction: request failed.")
return False, {"message": str(exc)}
async def webhook_route(self, request: web.Request) -> web.Response:
@@ -136,8 +136,8 @@ class PlategaService:
try:
data = await request.json()
except Exception as exc:
logging.error("Platega webhook: failed to parse JSON: %s", exc)
except Exception:
logging.exception("Platega webhook: failed to parse JSON.")
return web.Response(status=400, text="bad_request")
header_merchant = request.headers.get("X-MerchantId")
@@ -215,9 +215,9 @@ class PlategaService:
)
await session.commit()
except Exception as exc:
except Exception:
await session.rollback()
logging.error("Platega webhook: failed to process payment %s: %s", transaction_id, exc, exc_info=True)
logging.exception("Platega webhook: failed to process payment %s.", transaction_id)
return web.Response(status=500, text="processing_error")
db_user = await user_dal.get_user_by_id(session, payment.user_id)
@@ -296,8 +296,8 @@ class PlategaService:
parse_mode="HTML",
disable_web_page_preview=True,
)
except Exception as exc:
logging.error("Platega webhook: failed to notify user %s: %s", payment.user_id, exc)
except Exception:
logging.exception("Platega webhook: failed to notify user %s.", payment.user_id)
try:
notification_service = NotificationService(self.bot, self.settings, self.i18n)
@@ -310,8 +310,8 @@ class PlategaService:
payment_provider="platega",
username=db_user.username if db_user else None,
)
except Exception as exc:
logging.error("Platega webhook: failed to notify admins: %s", exc)
except Exception:
logging.exception("Platega webhook: failed to notify admins.")
return web.Response(text="ok")
@@ -324,9 +324,9 @@ class PlategaService:
"canceled",
)
await session.commit()
except Exception as exc:
except Exception:
await session.rollback()
logging.error("Platega webhook: failed to cancel payment %s: %s", transaction_id, exc)
logging.exception("Platega webhook: failed to cancel payment %s.", transaction_id)
return web.Response(status=500, text="processing_error")
db_user = await user_dal.get_user_by_id(session, payment.user_id)
+13 -13
View File
@@ -142,7 +142,7 @@ class SeverPayService:
return True, response_data.get("data") or response_data
except Exception as exc:
logging.error("SeverPay create_payment: request failed: %s", exc, exc_info=True)
logging.exception("SeverPay create_payment: request failed.")
return False, {"message": str(exc)}
async def webhook_route(self, request: web.Request) -> web.Response:
@@ -151,8 +151,8 @@ class SeverPayService:
try:
payload = await request.json()
except Exception as exc:
logging.error("SeverPay webhook: failed to parse JSON: %s", exc)
except Exception:
logging.exception("SeverPay webhook: failed to parse JSON.")
return web.json_response({"status": False, "msg": "bad_request"}, status=400)
if not isinstance(payload, dict) or not self._validate_signature(payload):
@@ -223,9 +223,9 @@ class SeverPayService:
)
await session.commit()
except Exception as exc:
except Exception:
await session.rollback()
logging.error("SeverPay webhook: failed to process payment %s: %s", provider_payment_id, exc, exc_info=True)
logging.exception("SeverPay webhook: failed to process payment %s.", provider_payment_id)
return web.json_response({"status": False, "msg": "processing_error"}, status=500)
db_user = payment.user or await user_dal.get_user_by_id(session, payment.user_id)
@@ -304,8 +304,8 @@ class SeverPayService:
parse_mode="HTML",
disable_web_page_preview=True,
)
except Exception as exc:
logging.error("SeverPay webhook: failed to notify user %s: %s", payment.user_id, exc)
except Exception:
logging.exception("SeverPay webhook: failed to notify user %s.", payment.user_id)
try:
notification_service = NotificationService(self.bot, self.settings, self.i18n)
@@ -318,8 +318,8 @@ class SeverPayService:
payment_provider="severpay",
username=db_user.username if db_user else None,
)
except Exception as exc:
logging.error("SeverPay webhook: failed to notify admins: %s", exc)
except Exception:
logging.exception("SeverPay webhook: failed to notify admins.")
return web.json_response({"status": True})
@@ -332,9 +332,9 @@ class SeverPayService:
"failed",
)
await session.commit()
except Exception as exc:
except Exception:
await session.rollback()
logging.error("SeverPay webhook: failed to mark payment %s as failed: %s", provider_payment_id, exc)
logging.exception("SeverPay webhook: failed to mark payment %s as failed.", provider_payment_id)
return web.json_response({"status": False, "msg": "processing_error"}, status=500)
db_user = payment.user or await user_dal.get_user_by_id(session, payment.user_id)
@@ -355,9 +355,9 @@ class SeverPayService:
"pending_severpay",
)
await session.commit()
except Exception as exc:
except Exception:
await session.rollback()
logging.error("SeverPay webhook: failed to update pending status for %s: %s", provider_payment_id, exc)
logging.exception("SeverPay webhook: failed to update pending status for %s.", provider_payment_id)
return web.json_response({"status": True})
logging.warning("SeverPay webhook: unhandled status '%s' for payment %s", status, provider_payment_id)
+1 -1
View File
@@ -55,7 +55,7 @@ class StarsService:
title=description,
description=description,
payload=payload,
provider_token="",
provider_token="", # Required to be empty for Telegram Stars (XTR) per Telegram Bot API.
currency="XTR",
prices=prices,
)
+9 -12
View File
@@ -35,9 +35,8 @@ class YooKassaService:
self.configured = True
logging.info(
f"YooKassa SDK configured for shop_id: {shop_id[:5]}...")
except Exception as e:
logging.error(f"Failed to configure YooKassa SDK: {e}",
exc_info=True)
except Exception:
logging.exception("Failed to configure YooKassa SDK.")
self.configured = False
if configured_return_url:
@@ -201,9 +200,8 @@ class YooKassaService:
response.test if hasattr(response, 'test') else None,
"payment_method": getattr(response, 'payment_method', None),
}
except Exception as e:
logging.error(f"YooKassa payment creation failed: {e}",
exc_info=True)
except Exception:
logging.exception("YooKassa payment creation failed.")
return None
async def get_payment_info(
@@ -266,10 +264,9 @@ class YooKassaService:
f"No payment info found in YooKassa for ID: {payment_id_in_yookassa}"
)
return None
except Exception as e:
logging.error(
f"YooKassa get payment info for {payment_id_in_yookassa} failed: {e}",
exc_info=True)
except Exception:
logging.exception(
"YooKassa get payment info for %s failed.", payment_id_in_yookassa)
return None
async def cancel_payment(self, payment_id_in_yookassa: str) -> bool:
@@ -280,6 +277,6 @@ class YooKassaService:
await asyncio.to_thread(YooKassaPayment.cancel, payment_id_in_yookassa)
logging.info(f"Cancelled YooKassa payment {payment_id_in_yookassa}")
return True
except Exception as e:
logging.error(f"Failed to cancel YooKassa payment {payment_id_in_yookassa}: {e}")
except Exception:
logging.exception("Failed to cancel YooKassa payment %s.", payment_id_in_yookassa)
return False