Skip to content

Commit

Permalink
fix: Improve logging messages
Browse files Browse the repository at this point in the history
  • Loading branch information
attiyaIshaque committed Jan 2, 2025
1 parent 59ab5f8 commit 2acf8ce
Show file tree
Hide file tree
Showing 17 changed files with 110 additions and 141 deletions.
16 changes: 10 additions & 6 deletions commerce_coordinator/apps/commercetools/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@ def create_return_for_order(self, order_id: str, order_version: int, order_line_
)
return returned_order
except CommercetoolsError as err:
handle_commercetools_error(err, f"Unable to create return for order {order_id}")
handle_commercetools_error("[CommercetoolsAPIClient.create_return_for_order]",
err, f"Unable to create return for order {order_id}")
raise err

def update_return_payment_state_after_successful_refund(
Expand Down Expand Up @@ -497,7 +498,8 @@ def update_return_payment_state_after_successful_refund(
logger.info("Updated transaction with return item id")
return updated_order
except CommercetoolsError as err:
handle_commercetools_error(err, f"Unable to update ReturnPaymentState of order {order_id}")
handle_commercetools_error("[CommercetoolsAPIClient.update_return_payment_state_after_successful_refund]",
err, f"Unable to update ReturnPaymentState of order {order_id}")
raise OpenEdxFilterException(str(err)) from err

def _preprocess_refund_object(self, refund: Refund, psp: str) -> Refund:
Expand Down Expand Up @@ -559,7 +561,7 @@ def create_return_payment_transaction(
f"Unable to create refund payment transaction for payment {payment_id}, refund {refund['id']} "
f"with PSP: {psp}"
)
handle_commercetools_error(err, context)
handle_commercetools_error("[CommercetoolsAPIClient.create_return_payment_transaction]", err, context)
raise err

def update_line_item_transition_state_on_fulfillment(
Expand Down Expand Up @@ -610,13 +612,15 @@ def update_line_item_transition_state_on_fulfillment(
return updated_fulfillment_line_item_order
else:
logger.info(
f"The line item {line_item_id} already has the correct state {new_state_key}. "
"Not attempting to transition LineItemState"
f"[CommercetoolsAPIClient] - The line item {line_item_id} "
f"already has the correct state {new_state_key}. "
f"Not attempting to transition LineItemState for order id {order_id}"
)
return self.get_order_by_id(order_id)
except CommercetoolsError as err:
context_prefix = "[CommercetoolsAPIClient.update_line_item_state_on_fulfillment_completion]"
# Logs & ignores version conflict errors due to duplicate Commercetools messages
handle_commercetools_error(err, f"Unable to update LineItemState of order {order_id}", True)
handle_commercetools_error(context_prefix, err, f"Unable to update LineItemState of order {order_id}")
return None

def retire_customer_anonymize_fields(
Expand Down
14 changes: 7 additions & 7 deletions commerce_coordinator/apps/commercetools/sub_messages/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ def fulfill_order_placed_message_signal_task(
return False

if not (customer and order and is_edx_lms_order(order)):
logger.debug(f'[CT-{tag}] order {order_id} is not an edX order, message id: {message_id}')
logger.info(f'[CT-{tag}] order {order_id} is not an edX order, message id: {message_id}')

return True

logger.debug(f'[CT-{tag}] processing edX order {order_id}, message id: {message_id}')
logger.info(f'[CT-{tag}] processing edX order {order_id}, message id: {message_id}')

lms_user_id = get_edx_lms_user_id(customer)

Expand All @@ -99,8 +99,8 @@ def fulfill_order_placed_message_signal_task(
canvas_entry_properties.update(extract_ct_order_information_for_braze_canvas(customer, order))

for item in get_edx_items(order):
logger.debug(f'[CT-{tag}] processing edX order {order_id}, line item {item.variant.sku}, '
f'message id: {message_id}')
logger.info(f'[CT-{tag}] processing edX order {order_id}, line item {item.variant.sku}, '
f'message id: {message_id}')
updated_order = client.update_line_item_transition_state_on_fulfillment(
order.id,
order.version,
Expand Down Expand Up @@ -263,7 +263,7 @@ def _prepare_segment_event_properties(in_order, return_line_item_return_id):
return False

if not (customer and order and is_edx_lms_order(order)): # pragma no cover
logger.debug(f'[CT-{tag}] order {order_id} is not an edX order, message id: {message_id}')
logger.info(f'[CT-{tag}] order {order_id} is not an edX order, message id: {message_id}')
return True

payment_intent_id = get_edx_payment_intent_id(order)
Expand All @@ -283,13 +283,13 @@ def _prepare_segment_event_properties(in_order, return_line_item_return_id):
logger.info(f'[CT-{tag}] payment intent {payment_intent_id} already has refunded transaction, '
f'sending Slack notification, message id: {message_id}')
else:
logger.debug(f'[CT-{tag}] payment intent {payment_intent_id} refunded. message id: {message_id}')
logger.info(f'[CT-{tag}] payment intent {payment_intent_id} refunded. message id: {message_id}')
segment_event_properties = _prepare_segment_event_properties(order, return_line_item_return_id)

for line_item in get_edx_items(order):
course_run = get_edx_product_course_run_key(line_item)
# TODO: Remove LMS Enrollment
logger.debug(
logger.info(
f'[CT-{tag}] calling lms to unenroll user {lms_user_name} in {course_run}'
f', message id: {message_id}'
)
Expand Down
38 changes: 18 additions & 20 deletions commerce_coordinator/apps/commercetools/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,16 @@ def update_line_item_state_on_fulfillment_completion(
Task for fulfillment completed and order line item state update via Commercetools API.
"""
client = CommercetoolsAPIClient()
try:
updated_order = client.update_line_item_transition_state_on_fulfillment(
order_id,
order_version,
line_item_id,
item_quantity,
from_state_id,
to_state_key
)
return updated_order
except CommercetoolsError as err:
logger.error(f"Unable to update line item [ {line_item_id} ] state on fulfillment "
f"result with error {err.errors} and correlation id {err.correlation_id}")
return None

updated_order = client.update_line_item_transition_state_on_fulfillment(
order_id,
order_version,
line_item_id,
item_quantity,
from_state_id,
to_state_key
)
return updated_order


@shared_task(autoretry_for=(CommercetoolsError,), retry_kwargs={'max_retries': 5, 'countdown': 3})
Expand All @@ -58,9 +54,12 @@ def refund_from_stripe_task(
"""
client = CommercetoolsAPIClient()
try:
logger.info(
f"[refund_from_stripe_task] Initiating creation of CT payment's refund transaction object "
f"for payment Intent ID {payment_intent_id}.")
payment = client.get_payment_by_key(payment_intent_id)
if has_full_refund_transaction(payment):
logger.info(f"Stripe charge.refunded event received, but Payment with ID {payment.id} "
logger.info(f"[refund_from_stripe_task] Event 'charge.refunded' received, but Payment with ID {payment.id} "
f"already has a full refund. Skipping task to add refund transaction")
return None
updated_payment = client.create_return_payment_transaction(
Expand All @@ -70,8 +69,8 @@ def refund_from_stripe_task(
)
return updated_payment
except CommercetoolsError as err:
logger.error(f"Unable to create refund transaction for payment [ {payment.id} ] "
f"on Stripe refund {stripe_refund['id']} "
logger.error(f"[refund_from_stripe_task] Unable to create CT payment's refund transaction "
f"object for [ {payment.id} ] on Stripe refund {stripe_refund['id']} "
f"with error {err.errors} and correlation id {err.correlation_id}")
return None

Expand All @@ -89,8 +88,6 @@ def refund_from_paypal_task(
try:
payment = client.get_payment_by_transaction_interaction_id(paypal_capture_id)
if has_full_refund_transaction(payment):
logger.info(f"PayPal PAYMENT.CAPTURE.REFUNDED event received, but Payment with ID {payment.id} "
f"already has a refund with ID: {refund.get('id')}. Skipping task to add refund transaction.")
return None
updated_payment = client.create_return_payment_transaction(
payment_id=payment.id,
Expand All @@ -100,7 +97,8 @@ def refund_from_paypal_task(
)
return updated_payment
except CommercetoolsError as err:
logger.error(f"Unable to create refund transaction for payment {payment.key} "
logger.error(f"[refund_from_paypal_task] Unable to create CT payment's refund "

Check failure on line 100 in commerce_coordinator/apps/commercetools/tasks.py

View workflow job for this annotation

GitHub Actions / tests (ubuntu-20.04, 3.12, django42)

Missing coverage

Missing coverage on line 100
f"transaction object for payment {payment.key} "
f"on PayPal refund {refund.get('id')} "
f"with error {err.errors} and correlation id {err.correlation_id}")
return None
16 changes: 9 additions & 7 deletions commerce_coordinator/apps/commercetools/tests/test_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,8 @@ def test_create_return_for_order_exception(self):
exception = cm.exception

expected_message = (
f"[CommercetoolsError] Unable to create return for "
f"order mock_order_id "
f"[CommercetoolsError] [CommercetoolsAPIClient.create_return_for_order] "
f"Unable to create return for order mock_order_id "
f"- Correlation ID: {exception.correlation_id}, Details: {exception.errors}"
)

Expand Down Expand Up @@ -604,7 +604,8 @@ def test_create_refund_transaction_exception(self):
exception = cm.exception

expected_message = (
f"[CommercetoolsError] Unable to create refund payment transaction for "
f"[CommercetoolsError] [CommercetoolsAPIClient.create_return_payment_transaction] "
f"Unable to create refund payment transaction for "
f"payment mock_payment_id, refund {mock_stripe_refund.id} with PSP: stripe_edx "
f"- Correlation ID: {exception.correlation_id}, Details: {exception.errors}"
)
Expand Down Expand Up @@ -672,7 +673,7 @@ def test_update_line_item_state_exception(self, mock_state_by_id):
status_code=409
)

with patch('commerce_coordinator.apps.commercetools.clients.logging.Logger.info') as log_mock:
with patch('commerce_coordinator.apps.commercetools.clients.logging.Logger.error') as log_mock:
self.client_set.client.update_line_item_transition_state_on_fulfillment(
"mock_order_id",
1,
Expand All @@ -683,7 +684,8 @@ def test_update_line_item_state_exception(self, mock_state_by_id):
)

expected_message = (
f"[CommercetoolsError] Unable to update LineItemState "
f"[CommercetoolsError] [CommercetoolsAPIClient.update_line_item_state_on_fulfillment_completion] "
f"Unable to update LineItemState "
f"of order mock_order_id "
f"- Correlation ID: {mock_error_response['correlation_id']}, "
f"Details: {mock_error_response['errors']}"
Expand Down Expand Up @@ -715,8 +717,8 @@ def test_order_line_item_in_correct_state(self, mock_order_by_id, mock_state_by_
)

expected_message = (
f"The line item {line_item_id} already has the correct state {mock_line_item_state.key}. "
f"Not attempting to transition LineItemState"
f"[CommercetoolsAPIClient] - The line item {line_item_id} already has the correct state "
f"{mock_line_item_state.key}. Not attempting to transition LineItemState for order id mock_order_id"
)

log_mock.assert_called_with(expected_message)
Expand Down
50 changes: 19 additions & 31 deletions commerce_coordinator/apps/commercetools/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""

import logging
from unittest.mock import patch
from unittest.mock import call, patch

import stripe
from commercetools import CommercetoolsError
Expand Down Expand Up @@ -62,28 +62,6 @@ def test_correct_arguments_passed(self, mock_client):
*list(EXAMPLE_UPDATE_LINE_ITEM_SIGNAL_PAYLOAD.values())
)

@patch('commerce_coordinator.apps.commercetools.tasks.logger')
def test_exception_handling(self, mock_logger, mock_client):
'''
Check if an error in the client results in a logged error
and None returned.
'''
mock_client().update_line_item_transition_state_on_fulfillment.side_effect = CommercetoolsError(
message="Could not update ReturnPaymentState",
errors="Some error message",
response={},
correlation_id="123456"
)

result = fulfillment_uut(*self.unpack_for_uut(EXAMPLE_UPDATE_LINE_ITEM_SIGNAL_PAYLOAD))

mock_logger.error.assert_called_once_with(
f"Unable to update line item [ {EXAMPLE_UPDATE_LINE_ITEM_SIGNAL_PAYLOAD['line_item_id']} ] "
"state on fulfillment result with error Some error message and correlation id 123456"
)

assert result is None


@patch('commerce_coordinator.apps.commercetools.tasks.CommercetoolsAPIClient')
class ReturnedOrderfromStripeTaskTest(TestCase):
Expand Down Expand Up @@ -123,10 +101,10 @@ def test_correct_arguments_passed(self, mock_client):
)

def test_full_refund_already_exists(self, mock_client):
'''
"""
Check if the payment already has a full refund, the task logs the
appropriate message and skips creating a refund transaction.
'''
appropriate messages and skips creating a refund transaction.
"""
mock_payment = gen_payment_with_multiple_transactions(
TransactionType.CHARGE, 4900,
TransactionType.REFUND, 4900
Expand All @@ -135,13 +113,22 @@ def test_full_refund_already_exists(self, mock_client):

mock_client.return_value.get_payment_by_key.return_value = mock_payment

payment_intent_id = EXAMPLE_RETURNED_ORDER_STRIPE_SIGNAL_PAYLOAD['payment_intent_id']

with patch('commerce_coordinator.apps.commercetools.tasks.logger') as mock_logger:
result = refund_from_stripe_task(*self.unpack_for_uut(EXAMPLE_RETURNED_ORDER_STRIPE_SIGNAL_PAYLOAD))
self.assertIsNone(result)
mock_logger.info.assert_called_once_with(
f"Stripe charge.refunded event received, but Payment with ID {mock_payment.id} "
f"already has a full refund. Skipping task to add refund transaction"
)

# Check that both info messages were logged in the expected order
mock_logger.info.assert_has_calls([
call(
f"[refund_from_stripe_task] "
f"Initiating creation of CT payment's refund transaction object "
f"for payment Intent ID {payment_intent_id}."),
call(f"[refund_from_stripe_task] Event 'charge.refunded' received, "
f"but Payment with ID {mock_payment.id} "
f"already has a full refund. Skipping task to add refund transaction")
])

@patch('commerce_coordinator.apps.commercetools.tasks.logger')
def test_exception_handling(self, mock_logger, mock_client):
Expand All @@ -162,7 +149,8 @@ def test_exception_handling(self, mock_logger, mock_client):
returned_uut(*self.unpack_for_uut(EXAMPLE_RETURNED_ORDER_STRIPE_SIGNAL_PAYLOAD))

mock_logger.error.assert_called_once_with(
f"Unable to create refund transaction for payment [ {mock_payment.id} ] "
f"[refund_from_stripe_task] Unable to create CT payment's refund transaction "
f"object for [ {mock_payment.id} ] "
f"on Stripe refund {EXAMPLE_RETURNED_ORDER_STRIPE_CLIENT_PAYLOAD['stripe_refund']['id']} "
f"with error Some error message and correlation id 123456"
)
5 changes: 3 additions & 2 deletions commerce_coordinator/apps/commercetools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ def get_braze_client():
)


def handle_commercetools_error(err: CommercetoolsError, context: str, is_info=False):
def handle_commercetools_error(context_prefix, err: CommercetoolsError, context: str, is_info=False):
"""Handles commercetools errors."""
error_message = f"[CommercetoolsError] {context} - Correlation ID: {err.correlation_id}, Details: {err.errors}"
error_message = (f"[CommercetoolsError] {context_prefix} {context} "
f"- Correlation ID: {err.correlation_id}, Details: {err.errors}")
if is_info:
logger.info(error_message)
else:
Expand Down
6 changes: 3 additions & 3 deletions commerce_coordinator/apps/commercetools/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def post(self, request):
**request.data
}

logger.debug(f'[CT-{tag}] Message received from commercetools with details: {input_data}')
logger.info(f'[CT-{tag}] Message received from commercetools with details: {input_data}')

message_details = OrderLineItemMessageInputSerializer(data=input_data)
message_details.is_valid(raise_exception=True)
Expand Down Expand Up @@ -85,7 +85,7 @@ def post(self, request):
**request.data
}

logger.debug(f'[CT-{tag}] Message received from commercetools with details: {input_data}')
logger.info(f'[CT-{tag}] Message received from commercetools with details: {input_data}')

message_details = OrderSanctionedViewMessageInputSerializer(data=input_data)
message_details.is_valid(raise_exception=True)
Expand Down Expand Up @@ -127,7 +127,7 @@ def post(self, request):
**request.data
}

logger.debug(f'[CT-{tag}] Message received from commercetools with details: {input_data}')
logger.info(f'[CT-{tag}] Message received from commercetools with details: {input_data}')

message_details = OrderReturnedViewMessageInputSerializer(data=input_data)
message_details.is_valid(raise_exception=True)
Expand Down
30 changes: 5 additions & 25 deletions commerce_coordinator/apps/core/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,38 +64,18 @@ def normal_timeout(self):
settings.REQUEST_READ_TIMEOUT_SECONDS
)

def log_request_response(self, ext_logger, response):
"""
Log requests.Request Response.
Args:
ext_logger: The logger of the module the Client (or Client-
derived class) is running in.
response: A successful Response object from the requests library.
"""
ext_logger.debug('Request URL: %s', response.request.url)
ext_logger.debug('Request method: %s', response.request.method)
ext_logger.debug('Request body: %s', response.request.body)
ext_logger.debug('Request headers: %s', response.request.headers)
ext_logger.debug('Response status: %s %s', response.status_code, response.reason)
ext_logger.debug('Response text: %s', response.text)

def log_request_exception(self, ext_logger, exc):
def log_request_exception(self, context_prefix, ext_logger, exc):
"""
Log requests.Request exceptions.
Args:
ext_logger: The logger of the module the Client (or Client-
derived class) is running in.
response: A RequestException object from the requests library.
exc: A RequestException object from the requests library.
"""
ext_logger.error(exc)
ext_logger.info('Request URL: %s', exc.request.url)
ext_logger.info('Request method: %s', exc.request.method)
ext_logger.info('Request body: %s', exc.request.body)
ext_logger.debug('Request headers: %s', exc.request.headers)
ext_logger.info('Response status: %s %s', exc.response.status_code, exc.response.reason)
ext_logger.info('Response body: %s', exc.response.text)
ext_logger.error(
f"{context_prefix} - The API call failed with status code: "
f"{exc.response.status_code if exc.response else ''}. Reason: {exc}.")


class BaseEdxOAuthClient(Client):
Expand Down
Loading

0 comments on commit 2acf8ce

Please sign in to comment.