-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨⚡💡feat: add Email-Notifier & log_and_notify
Introduced an EmailHandler to send email notifications for specific log levels. Configurable log levels for triggering email notifications, allowing granular control over email alerts. Added the log_and_notify method to log a message and send an email notification simultaneously: Uses the logger to create a LogRecord with the correct module, file, and line number. Handles the log record with the logger's handlers and sends an email using the EmailHandler. Supports customizable log messages with additional context data, such as request information. Includes error handling to raise a ValueError if logging fails due to invalid parameters. Asynchronously sends an email with the formatted log message to the administrator. Updated: Log Config: Added log_email_notifier_enable to enable or disable the email notifier feature. Added log_email_notifier_log_levels to specify which log levels should trigger email notifications. Updated the LogConfig class initializer to include new parameters for email notifier settings. apps.py: Introduced logic to fetch and apply email notifier settings from LOG_EMAIL_NOTIFIER. Set up conditions for enabling email notifications for ERROR and CRITICAL log levels based on settings. Updated the set_logging method call to pass the email notifier settings to the logging config. Docstrings: Included comprehensive docstrings for the email notifier feature, log_and_notify method, and configuration updates. Closes #8
- Loading branch information
1 parent
d4b4d04
commit 897272a
Showing
8 changed files
with
157 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .email_handler import EmailHandler |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import logging | ||
|
||
from django.conf import settings | ||
from django.template import engines | ||
from django.utils.timezone import now | ||
from django_logging.utils.email.notifier import send_email_async | ||
from django_logging.middleware import RequestLogMiddleware | ||
|
||
|
||
class EmailHandler(logging.Handler): | ||
def __init__(self, include_html=False, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.include_html = include_html | ||
|
||
def emit(self, record): | ||
try: | ||
request = getattr(record, "request", None) | ||
log_entry = self.format(record) | ||
|
||
if self.include_html: | ||
email_body = self.render_template(log_entry, request) | ||
else: | ||
email_body = log_entry # Use plain text format if HTML is not included | ||
|
||
subject = f"New Log Record: {record.levelname}" | ||
send_email_async(subject, email_body, [settings.ADMIN_EMAIL]) | ||
|
||
except Exception as e: | ||
self.handleError(record) | ||
|
||
@staticmethod | ||
def render_template(log_entry, request=None, template_path="email_notifier_template.html"): | ||
django_engine = engines["django"] | ||
template = django_engine.get_template(template_path) | ||
|
||
# Fetch IP address and user agent using middleware methods | ||
ip_address = RequestLogMiddleware.get_ip_address(request) if request else "Unknown" | ||
user_agent = RequestLogMiddleware.get_user_agent(request) if request else "Unknown" | ||
|
||
context = { | ||
"message": log_entry, | ||
"time": now(), | ||
"browser_type": user_agent, | ||
"ip_address": ip_address, | ||
} | ||
|
||
return template.render(context) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .notifier import send_email_async |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import logging | ||
import threading | ||
import smtplib | ||
from email.mime.text import MIMEText | ||
from email.mime.multipart import MIMEMultipart | ||
|
||
from django.conf import settings | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def send_email_async(subject, body, recipient_list): | ||
def send_email(): | ||
msg = MIMEMultipart() | ||
msg["From"] = settings.DEFAULT_FROM_EMAIL | ||
msg["To"] = ", ".join(recipient_list) | ||
msg["Subject"] = subject | ||
|
||
msg.attach(MIMEText(body, "html")) | ||
|
||
try: | ||
server = smtplib.SMTP(settings.EMAIL_HOST, settings.EMAIL_PORT) | ||
server.starttls() | ||
server.login(settings.EMAIL_HOST_USER, settings.EMAIL_HOST_PASSWORD) | ||
server.sendmail( | ||
settings.DEFAULT_FROM_EMAIL, recipient_list, msg.as_string() | ||
) | ||
server.quit() | ||
logger.info(f"Log Record has been sent to ADMIN EMAIL successfully.") | ||
|
||
except Exception as e: | ||
logger.warning(f"Email Notifier failed to send Log Record: {e}") | ||
|
||
# Start a new thread to send the email asynchronously | ||
email_thread = threading.Thread(target=send_email) | ||
email_thread.start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import logging | ||
import inspect | ||
from typing import Optional, Dict | ||
|
||
from django.conf import settings | ||
|
||
from django_logging.utils.email import send_email_async | ||
from django_logging.handlers import EmailHandler | ||
|
||
|
||
def log_and_notify(logger, level: int, message: str, extra: Optional[Dict] = None): | ||
# Get the caller's frame to capture the correct module, file, and line number | ||
frame = inspect.currentframe().f_back | ||
|
||
try: | ||
# create a LogRecord | ||
log_record = logger.makeRecord( | ||
name=logger.name, | ||
level=level, | ||
fn=frame.f_code.co_filename, | ||
lno=frame.f_lineno, | ||
msg=message, | ||
args=None, | ||
exc_info=None, | ||
func=frame.f_code.co_name, | ||
extra=extra, | ||
) | ||
|
||
# Pass the LogRecord to the logger's handlers | ||
logger.handle(log_record) | ||
except TypeError as e: | ||
raise ValueError( | ||
f"Failed to log message due to invalid param. Original error: {e}" | ||
) | ||
|
||
request = extra.get("request") if extra else None | ||
|
||
# Render the email template with the formatted message | ||
email_body = EmailHandler.render_template(log_record, request) | ||
|
||
subject = f"New Log Record: {logging.getLevelName(level)}" | ||
send_email_async(subject, email_body, [settings.ADMIN_EMAIL]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters