Callback Error Logging - Implementation Status
Overview
A new CallbackErrorLogTable has been created to log errors from callback functions. The table has a secondary index on orderId for easy querying of errors by order.
Table Definition
- Table Name:
callback-error-log-{BRANCH} - Primary Key:
id(function_name-timestamp format) - Global Secondary Index:
orderId-index(orderId, created_at) - Location:
functions/callback/src/callback_error_log_table.py - Helper Function:
functions/callback/src/callback_error_logger.py
Implementation Status
✅ Completed
- callback.py - Error logging integrated
- notify.py - Error logging integrated
- delayednotify.py - Error logging integrated
⏳ TODO (Not Yet Implemented)
The following callback functions do NOT currently log errors to CallbackErrorLogTable. They were intentionally excluded to minimize dependencies, but can be added later when needed:
- qrcallback.py - Error logging not implemented
- amexcallback.py - Error logging not implemented
- walletcallback.py - Error logging not implemented
Note: These functions are currently back to their normal state (no error logging integration). To add error logging later, follow the implementation steps below.
Usage
Errors are automatically logged when exceptions occur in the implemented functions using log_callback_error() from src/callback_error_logger.py.
Example:
from src.callback_error_logger import log_callback_error
try:
# ... function logic ...
except Exception as e:
log_callback_error(
error=e,
function_name="callback",
event=event,
orderId=orderId,
chargeId=chargeId,
response_data=None
)
raise
IAM Policies
The following Lambda functions have write permissions to CallbackErrorLogTable:
CallbackfunctionNotifyfunctionDelayedNotifyfunction
Future Work - Adding Error Logging to Other Functions
When ready to expand error logging to qrcallback, amexcallback, or walletcallback:
Step 1: Update the Lambda Function Code
For qrcallback.py:
from src.callback_error_logger import log_callback_error
def lambda_handler(event, _):
processor = None
try:
body = dict(urllib.parse.parse_qsl(event["body"]))
order_id = body["orderId"]
status_string = body["status"]
amount = float(body["amount"])
charge_id = body["chargeId"]
processor = Processor(order_id, status_string, amount, charge_id)
except Exception as e:
charge_id = errorString()
order_id = body if isinstance(body, str) else body.get("orderId", "unknown")
processor = Processor(order_id, status_string, amount, charge_id)
# Log error
log_callback_error(
error=e,
function_name="qrcallback",
event=event,
orderId=order_id,
chargeId=charge_id,
response_data=None
)
return processor.error_html_response(str(e) + errorString())
try:
qr_processor = processor.qr_processor
success, paid_amount = qr_processor.check_kbank_record
if not success:
error_msg = f"Kbank record not found for charge id {charge_id}"
log_callback_error(
error=Exception(error_msg),
function_name="qrcallback",
event=event,
orderId=processor.order_id,
chargeId=processor.charge_id,
response_data=None
)
return processor.error_html_response(error_msg)
if abs(float(paid_amount) - float(processor.amount)) > 0.01:
error_msg = f"Kbank record amount {paid_amount} does not match order amount {processor.amount}"
log_callback_error(
error=Exception(error_msg),
function_name="qrcallback",
event=event,
orderId=processor.order_id,
chargeId=processor.charge_id,
response_data=None
)
return processor.error_html_response(error_msg)
qr_processor.save_record()
qr_processor.process_paid_order()
except Exception as e:
log_callback_error(
error=e,
function_name="qrcallback",
event=event,
orderId=processor.order_id if processor else None,
chargeId=processor.charge_id if processor else None,
response_data=None
)
return processor.error_html_response(str(e) + errorString())
return processor.response
For amexcallback.py:
from src.callback_error_logger import log_callback_error
def lambda_handler(event, _):
processor = None
try:
# ... existing code ...
processor = AmexCallbackProcessor(event=event)
processor.save()
# ... rest of existing code ...
except Exception as e:
# Extract orderId and paymentId if processor exists
orderId = None
chargeId = None
if processor:
try:
orderId = processor.order_id
chargeId = getattr(processor, 'payment_id', None)
except:
pass
log_callback_error(
error=e,
function_name="amexcallback",
event=event,
orderId=orderId,
chargeId=chargeId,
response_data=None
)
# ... existing error handling ...
For walletcallback.py:
from src.callback_error_logger import log_callback_error
def lambda_handler(event, _):
processor = None
try:
# ... existing code ...
processor = WalletCallbackProcessor(event=event)
processor.save()
# ... rest of existing code ...
except Exception as e:
# Extract orderId and paymentId if processor exists
orderId = None
chargeId = None
if processor:
try:
orderId = processor.order_id
chargeId = getattr(processor, 'payment_id', None)
except:
pass
log_callback_error(
error=e,
function_name="walletcallback",
event=event,
orderId=orderId,
chargeId=chargeId,
response_data=None
)
# ... existing error handling ...
Step 2: Update template.yaml
Add DynamoDBWritePolicy for CallbackErrorLogTable to the function's Policies:
QRCallback: # or AmexCallback, WalletCallback
Type: AWS::Serverless::Function
Properties:
Policies:
# ... existing policies ...
- DynamoDBWritePolicy:
TableName: !Ref CallbackErrorLogTable
Step 3: Test
After implementation, test each function to ensure errors are properly logged to CallbackErrorLogTable.
Querying Errors
To query errors by orderId:
from src.callback_error_log_table import CallbackErrorLogTable
# Query all errors for a specific order
errors = list(CallbackErrorLogTable.orderId_index.query(
orderId,
scan_index_forward=False # Sort descending (newest first)
))