Skip to content

Commit a95b0db

Browse files
committed
Enhanced logger config
Colored output added for readability Improved formatting Added more logging to spot unwanted behavior easily
1 parent 3a30d4a commit a95b0db

File tree

12 files changed

+118
-50
lines changed

12 files changed

+118
-50
lines changed

appointment/email_sender/email_sender.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
from django.template import loader
66
from django_q.tasks import async_task
77

8+
from appointment.logger_config import get_logger
89
from appointment.settings import APP_DEFAULT_FROM_EMAIL, check_q_cluster
910

11+
logger = get_logger(__name__)
12+
1013

1114
def has_required_email_settings():
1215
"""Check if all required email settings are configured and warn if any are missing."""
@@ -22,8 +25,8 @@ def has_required_email_settings():
2225

2326
if missing_settings:
2427
missing_settings_str = ", ".join(missing_settings)
25-
print(f"Warning: The following settings are missing in settings.py: {missing_settings_str}. "
26-
"Email functionality will be disabled.")
28+
logger.warning(f"Warning: The following settings are missing in settings.py: {missing_settings_str}. "
29+
"Email functionality will be disabled.")
2730
return False
2831
return True
2932

@@ -57,7 +60,7 @@ def send_email(recipient_list, subject: str, template_url: str = None, context:
5760
recipient_list=recipient_list, fail_silently=False,
5861
)
5962
except Exception as e:
60-
print(f"Error sending email: {e}")
63+
logger.error(f"Error sending email: {e}")
6164

6265

6366
def notify_admin(subject: str, template_url: str = None, context: dict = None, message: str = None):
@@ -77,7 +80,7 @@ def notify_admin(subject: str, template_url: str = None, context: dict = None, m
7780
html_message=html_message if template_url else None
7881
)
7982
except Exception as e:
80-
print(f"Error sending email to admin: {e}")
83+
logger.error(f"Error sending email to admin: {e}")
8184

8285

8386
def get_use_django_q_for_emails():
@@ -86,5 +89,5 @@ def get_use_django_q_for_emails():
8689
from django.conf import settings
8790
return getattr(settings, 'USE_DJANGO_Q_FOR_EMAILS', False)
8891
except AttributeError:
89-
print("Error accessing USE_DJANGO_Q_FOR_EMAILS. Defaulting to False.")
92+
logger.error("Error accessing USE_DJANGO_Q_FOR_EMAILS. Defaulting to False.")
9093
return False

appointment/logger_config.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,51 @@
88

99
import logging
1010
import sys
11+
from datetime import datetime
1112

12-
logger = logging.getLogger(__name__)
13-
logger.setLevel(logging.DEBUG)
13+
import colorama
1414

15-
# TODO: change the logger format configuration later
16-
# configure basicConfig with the formatter, log level, and handlers
17-
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.DEBUG,
18-
handlers=[logging.StreamHandler(sys.stdout)])
15+
# Initialize colorama for cross-platform color support
16+
colorama.init()
17+
18+
19+
class ColoredFormatter(logging.Formatter):
20+
COLORS = {
21+
'DEBUG': colorama.Fore.BLUE,
22+
'INFO': colorama.Fore.GREEN,
23+
'WARNING': colorama.Fore.YELLOW,
24+
'ERROR': colorama.Fore.RED,
25+
'CRITICAL': colorama.Fore.RED + colorama.Style.BRIGHT,
26+
}
27+
28+
def format(self, record):
29+
log_color = self.COLORS.get(record.levelname, colorama.Fore.WHITE)
30+
log_time = datetime.fromtimestamp(record.created).strftime('%d/%b/%Y %H:%M:%S')
31+
32+
log_msg = (
33+
f"{log_color}[{log_time}] {record.levelname:<4}{colorama.Style.RESET_ALL} "
34+
f"{colorama.Fore.LIGHTBLUE_EX}{record.name}:{record.funcName}:{record.lineno}{colorama.Style.RESET_ALL} "
35+
f"- {record.getMessage()}"
36+
)
37+
38+
if record.exc_info:
39+
log_msg += '\n' + self.formatException(record.exc_info)
40+
return log_msg
41+
42+
43+
def get_logger(name):
44+
logger = logging.getLogger(name)
45+
logger.setLevel(logging.DEBUG)
46+
47+
# Create a colored formatter
48+
formatter = ColoredFormatter()
49+
50+
# Create a stream handler
51+
stream_handler = logging.StreamHandler(sys.stdout)
52+
stream_handler.setLevel(logging.DEBUG)
53+
stream_handler.setFormatter(formatter)
54+
55+
# Add the handler to the logger
56+
logger.addHandler(stream_handler)
57+
58+
return logger

appointment/settings.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
from django.conf import settings
1010
from django.conf.global_settings import DEFAULT_FROM_EMAIL
1111

12-
from appointment.logger_config import logger
12+
from appointment.logger_config import get_logger
13+
14+
logger = get_logger(__name__)
1315

1416
APPOINTMENT_BASE_TEMPLATE = getattr(settings, 'APPOINTMENT_BASE_TEMPLATE', 'base_templates/base.html')
1517
APPOINTMENT_ADMIN_BASE_TEMPLATE = getattr(settings, 'APPOINTMENT_ADMIN_BASE_TEMPLATE', 'base_templates/base.html')
@@ -32,7 +34,7 @@ def check_q_cluster():
3234
Returns True if configurations are correct, otherwise False.
3335
"""
3436
missing_conf = []
35-
37+
logger.info("Checking missing configuration for django q cluster")
3638
# Check if Django Q is installed
3739
if 'django_q' not in settings.INSTALLED_APPS:
3840
missing_conf.append("Django Q is not in settings.INSTALLED_APPS. Please add it to the list.\n"
@@ -64,6 +66,6 @@ def check_q_cluster():
6466
for warning in missing_conf:
6567
logger.warning(warning)
6668
return False
67-
print(f"Missing conf: {missing_conf}")
6869
# Both 'django_q' is installed and 'Q_CLUSTER' is configured
70+
logger.info("Django Q cluster is properly configured")
6971
return True

appointment/tasks.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
from django.utils.translation import gettext as _
99

1010
from appointment.email_sender import notify_admin, send_email
11-
from appointment.logger_config import logger
11+
from appointment.logger_config import get_logger
1212
from appointment.models import Appointment
1313

14+
logger = get_logger(__name__)
15+
1416

1517
def send_email_reminder(to_email, first_name, reschedule_link, appointment_id):
1618
"""
@@ -32,6 +34,7 @@ def send_email_reminder(to_email, first_name, reschedule_link, appointment_id):
3234
template_url='email_sender/reminder_email.html', context=email_context
3335
)
3436
# Notify the admin
37+
logger.info(f"Sending admin reminder for appointment {appointment_id}")
3538
email_context['recipient_type'] = 'admin'
3639
notify_admin(
3740
subject=_("Admin Reminder: Upcoming Appointment"),
@@ -46,12 +49,13 @@ def send_email_task(recipient_list, subject, message, html_message, from_email):
4649
"""
4750
try:
4851
from django.core.mail import send_mail
52+
logger.info(f"Sending email to {recipient_list} with subject: {subject}")
4953
send_mail(
5054
subject=subject, message=message, html_message=html_message, from_email=from_email,
5155
recipient_list=recipient_list, fail_silently=False,
5256
)
5357
except Exception as e:
54-
print(f"Error sending email from task: {e}")
58+
logger.error(f"Error sending email from task: {e}")
5559

5660

5761
def notify_admin_task(subject, message, html_message):
@@ -60,6 +64,7 @@ def notify_admin_task(subject, message, html_message):
6064
"""
6165
try:
6266
from django.core.mail import mail_admins
67+
logger.info(f"Sending admin email with subject: {subject}")
6368
mail_admins(subject=subject, message=message, html_message=html_message, fail_silently=False)
6469
except Exception as e:
65-
print(f"Error sending admin email from task: {e}")
70+
logger.error(f"Error sending admin email from task: {e}")

appointment/utils/db_helpers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from django_q.models import Schedule
2020
from django_q.tasks import schedule
2121

22-
from appointment.logger_config import logger
22+
from appointment.logger_config import get_logger
2323
from appointment.settings import (
2424
APPOINTMENT_BUFFER_TIME, APPOINTMENT_FINISH_TIME, APPOINTMENT_LEAD_TIME, APPOINTMENT_PAYMENT_URL,
2525
APPOINTMENT_SLOT_DURATION, APPOINTMENT_WEBSITE_NAME
@@ -37,6 +37,8 @@
3737
EmailVerificationCode = apps.get_model('appointment', 'EmailVerificationCode')
3838
AppointmentRescheduleHistory = apps.get_model('appointment', 'AppointmentRescheduleHistory')
3939

40+
logger = get_logger(__name__)
41+
4042

4143
def calculate_slots(start_time, end_time, buffer_time, slot_duration):
4244
"""Calculate the available slots between the given start and end times using the given buffer time and slot duration
@@ -109,6 +111,7 @@ def create_and_save_appointment(ar, client_data: dict, appointment_data: dict, r
109111
appointment.save()
110112
logger.info(f"New appointment created: {appointment.to_dict()}")
111113
if appointment.want_reminder:
114+
logger.info(f"User wants a reminder for appointment {appointment.id}, scheduling it...")
112115
schedule_email_reminder(appointment, request)
113116
return appointment
114117

appointment/utils/email_ops.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616

1717
from appointment import messages_ as email_messages
1818
from appointment.email_sender import notify_admin, send_email
19+
from appointment.logger_config import get_logger
1920
from appointment.models import AppointmentRequest, EmailVerificationCode, PasswordResetToken
2021
from appointment.settings import APPOINTMENT_PAYMENT_URL
2122
from appointment.utils.date_time import convert_24_hour_time_to_12_hour_time
2223
from appointment.utils.db_helpers import get_absolute_url_, get_website_name
2324

25+
logger = get_logger(__name__)
26+
2427

2528
def get_thank_you_message(ar: AppointmentRequest) -> str:
2629
"""
@@ -83,8 +86,8 @@ def send_thank_you_email(ar: AppointmentRequest, user, request, email: str, appo
8386
'reschedule_link': reschedule_link,
8487
}
8588
send_email(
86-
recipient_list=[email], subject=_("Thank you for booking us."),
87-
template_url='email_sender/thank_you_email.html', context=email_context
89+
recipient_list=[email], subject=_("Thank you for booking us."),
90+
template_url='email_sender/thank_you_email.html', context=email_context
8891
)
8992

9093

@@ -121,34 +124,36 @@ def send_reset_link_to_staff_member(user, request, email: str, account_details=N
121124
Regards,
122125
{company}
123126
""").format(
124-
first_name=user.first_name,
125-
current_year=datetime.datetime.now().year,
126-
company=website_name,
127-
activation_link=set_passwd_link,
128-
account_details=account_details if account_details else _("No additional details provided."),
129-
username=user.username
127+
first_name=user.first_name,
128+
current_year=datetime.datetime.now().year,
129+
company=website_name,
130+
activation_link=set_passwd_link,
131+
account_details=account_details if account_details else _("No additional details provided."),
132+
username=user.username
130133
)
131134

132135
# Assuming send_email is a method you have that sends an email
133136
send_email(
134-
recipient_list=[email],
135-
subject=_("Set Your Password for {company}").format(company=website_name),
136-
message=message,
137+
recipient_list=[email],
138+
subject=_("Set Your Password for {company}").format(company=website_name),
139+
message=message,
137140
)
138141

139142

140143
def notify_admin_about_appointment(appointment, client_name: str):
141144
"""Notify the admin and the staff member about a new appointment request."""
145+
logger.info(f"Sending admin notification for new appointment {appointment.id}")
142146
email_context = {
143147
'client_name': client_name,
144148
'appointment': appointment
145149
}
146150

147151
subject = _("New Appointment Request for ") + client_name
148152
staff_member = appointment.get_staff_member()
149-
# Assuming notify_admin and send_email are previously defined functions
150153
notify_admin(subject=subject, template_url='email_sender/admin_new_appointment_email.html', context=email_context)
151154
if staff_member.user.email not in settings.ADMINS:
155+
logger.info(
156+
f"Let's notify the staff member as well for new appointment {appointment.id} since they are not an admin.")
152157
send_email(recipient_list=[staff_member.user.email], subject=subject,
153158
template_url='email_sender/admin_new_appointment_email.html', context=email_context)
154159

@@ -190,8 +195,8 @@ def send_reschedule_confirmation_email(request, reschedule_history, appointment_
190195

191196
subject = _("Confirm Your Appointment Rescheduling")
192197
send_email(
193-
recipient_list=[email], subject=subject,
194-
template_url='email_sender/reschedule_email.html', context=email_context
198+
recipient_list=[email], subject=subject,
199+
template_url='email_sender/reschedule_email.html', context=email_context
195200
)
196201

197202

appointment/utils/session.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
from django.utils.translation import gettext as _
1212
from phonenumber_field.phonenumber import PhoneNumber
1313

14-
from appointment.logger_config import logger
14+
from appointment.logger_config import get_logger
1515
from appointment.utils.db_helpers import get_user_by_email
1616
from appointment.utils.email_ops import send_verification_email
1717

18+
logger = get_logger(__name__)
19+
1820

1921
def handle_existing_email(request, client_data, appointment_data, appointment_request_id, id_request):
2022
"""

appointment/utils/view_helpers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@
88

99
import uuid
1010

11-
from django.conf import settings
1211
from django.utils.translation import get_language, to_locale
1312

1413

1514
def get_locale() -> str:
1615
"""Get the current locale based on the user's language settings, without the country code.
17-
Used in the javascript files.
16+
Used in the JavaScript files.
1817
Can't use the lang_country format because it is not supported.
1918
2019
:return: The current locale as a string (language code only)

0 commit comments

Comments
 (0)