-
-
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.
Merge pull request #16 from ARYAN-NIKNEZHAD/develop
Develop To Main
- Loading branch information
Showing
18 changed files
with
924 additions
and
7 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 .format_options import FORMAT_OPTIONS |
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,38 @@ | ||
class AnsiColors: | ||
BLACK = "\033[0;30m" | ||
RED = "\033[0;31m" | ||
RED_BACKGROUND = "\033[1;41m" | ||
GREEN = "\033[0;32m" | ||
YELLOW = "\033[0;33m" | ||
BLUE = "\033[0;34m" | ||
MAGENTA = "\033[0;35m" | ||
CYAN = "\033[0;36m" | ||
GRAY = "\033[0;37m" | ||
WHITE = "\033[0;38m" | ||
RESET = "\033[0m" | ||
BRIGHT_BLACK = "\033[0;90m" | ||
BRIGHT_RED = "\033[0;91m" | ||
BRIGHT_GREEN = "\033[0;92m" | ||
BRIGHT_YELLOW = "\033[0;93m" | ||
BRIGHT_BLUE = "\033[0;94m" | ||
BRIGHT_MAGENTA = "\033[0;95m" | ||
BRIGHT_CYAN = "\033[0;96m" | ||
BRIGHT_WHITE = "\033[0;97m" | ||
BLACK_BACKGROUND = "\033[40m" | ||
RED_BACKGROUND = "\033[41m" | ||
GREEN_BACKGROUND = "\033[42m" | ||
YELLOW_BACKGROUND = "\033[43m" | ||
BLUE_BACKGROUND = "\033[44m" | ||
MAGENTA_BACKGROUND = "\033[45m" | ||
CYAN_BACKGROUND = "\033[46m" | ||
WHITE_BACKGROUND = "\033[47m" | ||
|
||
|
||
# Mapping log levels to ANSI colors | ||
LOG_LEVEL_COLORS = { | ||
"DEBUG": AnsiColors.BLUE, | ||
"INFO": AnsiColors.GREEN, | ||
"WARNING": AnsiColors.YELLOW, | ||
"ERROR": AnsiColors.RED, | ||
"CRITICAL": AnsiColors.RED_BACKGROUND, | ||
} |
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,15 @@ | ||
FORMAT_OPTIONS = { | ||
1: "%(levelname)s | %(asctime)s | %(module)s | %(message)s", | ||
2: "%(levelname)s | %(asctime)s | %(message)s", | ||
3: "%(levelname)s | %(message)s", | ||
4: "%(asctime)s - %(name)s - %(levelname)s - %(message)s", | ||
5: "%(levelname)s | %(message)s | [in %(pathname)s:%(lineno)d]", | ||
6: "%(asctime)s | %(levelname)s | %(message)s", | ||
7: "%(levelname)s | %(asctime)s | in %(module)s: %(message)s", | ||
8: "%(levelname)s | %(message)s | [%(filename)s:%(lineno)d]", | ||
9: "[%(asctime)s] | %(levelname)s | in %(module)s: %(message)s", | ||
10: "%(asctime)s | %(processName)s | %(name)s | %(levelname)s | %(message)s", | ||
11: "%(asctime)s | %(threadName)s | %(name)s | %(levelname)s | %(message)s", | ||
12: "%(levelname)s | [%(asctime)s] | (%(filename)s:%(lineno)d) | %(message)s", | ||
13: "%(levelname)s | [%(asctime)s] | {%(name)s} | (%(filename)s:%(lineno)d): %(message)s", | ||
} |
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 .colorized_formatter import ColorizedFormatter |
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,20 @@ | ||
import logging | ||
from django_logging.settings.conf import LogConfig | ||
from django_logging.utils.colorizer import colorize_log_format | ||
|
||
|
||
class ColorizedFormatter(logging.Formatter): | ||
def format(self, record): | ||
original_format = self._style._fmt | ||
|
||
# checks that the format does not have any color it's self | ||
if LogConfig.remove_ansi_escape_sequences(original_format) == original_format: | ||
colorized_format = colorize_log_format(original_format, record.levelname) | ||
self._style._fmt = colorized_format | ||
|
||
formatted_output = super().format(record) | ||
|
||
# Reset to the original format string | ||
self._style._fmt = original_format | ||
|
||
return formatted_output |
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,60 @@ | ||
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 | ||
|
||
try: | ||
# Attempt to retrieve the logging settings from the Django settings | ||
logging_settings = settings.DJANGO_LOGGING | ||
|
||
self.include_html = logging_settings.get("LOG_EMAIL_NOTIFIER", {}).get("USE_TEMPLATE", include_html) | ||
|
||
except AttributeError: | ||
logging.warning( | ||
f"DJANGO_LOGGING settings not found. Using default include_html value: {self.include_html}.") | ||
except Exception as e: | ||
logging.error(f"An unexpected error occurred while initializing EmailHandler: {e}") | ||
|
||
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 | ||
|
||
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) |
Empty file.
Empty file.
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,107 @@ | ||
import os | ||
import shutil | ||
import tempfile | ||
import logging | ||
from django.core.mail import EmailMessage | ||
from django.core.management.base import BaseCommand | ||
from django.conf import settings | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class Command(BaseCommand): | ||
""" | ||
A Django management command that zips the log directory and sends it to | ||
the specified email address. | ||
This command is used to send the log files to a specified email address. | ||
It zips the log directory, creates an email with the zipped file as an attachment, | ||
and sends it to the specified email address. | ||
""" | ||
|
||
help = "Send log folder to the specified email address" | ||
|
||
def add_arguments(self, parser): | ||
""" | ||
Add custom command arguments. | ||
Parameters: | ||
parser (ArgumentParser): The argument parser to add arguments to. | ||
""" | ||
parser.add_argument( | ||
"email", type=str, help="The email address to send the logs to" | ||
) | ||
|
||
def handle(self, *args, **kwargs): | ||
""" | ||
The main entry point for the command. | ||
Parameters: | ||
args (tuple): Positional arguments. | ||
kwargs (dict): Keyword arguments. | ||
""" | ||
email = kwargs["email"] | ||
|
||
log_dir = settings.DJANGO_LOGGING.get("LOG_DIR", os.path.join(os.getcwd(), "logs")) | ||
|
||
if not os.path.exists(log_dir): | ||
self.stdout.write( | ||
self.style.ERROR(f'Log directory "{log_dir}" does not exist.') | ||
) | ||
logger.error(f'Log directory "{log_dir}" does not exist.') | ||
return | ||
|
||
self.check_email_settings() | ||
|
||
# Create a temporary file to store the zipped logs | ||
with tempfile.NamedTemporaryFile(delete=False) as tmp_file: | ||
zip_path = f"{tmp_file.name}.zip" | ||
tmp_file.close() | ||
|
||
# Zip the log directory | ||
shutil.make_archive(tmp_file.name, "zip", log_dir) | ||
|
||
# Send the email with the zipped logs | ||
email_subject = "Log Files" | ||
email_body = "Please find the attached log files." | ||
email_message = EmailMessage( | ||
subject=email_subject, | ||
body=email_body, | ||
from_email=settings.DEFAULT_FROM_EMAIL, | ||
to=[email], | ||
) | ||
email_message.attach_file(zip_path) | ||
|
||
try: | ||
email_message.send() | ||
self.stdout.write(self.style.SUCCESS(f"Logs sent successfully to {email}.")) | ||
logger.info(f"Logs sent successfully to {email}.") | ||
except Exception as e: | ||
self.stdout.write(self.style.ERROR(f"Failed to send logs: {e}")) | ||
logger.error(f"Failed to send logs: {e}") | ||
finally: | ||
# Clean up the temporary file | ||
os.remove(zip_path) | ||
logger.info("Temporary zip file cleaned up successfully.") | ||
|
||
def check_email_settings(self): | ||
""" | ||
Check if all required email settings are present in the settings file. | ||
Raises an exception if any of the required email settings are missing. | ||
""" | ||
required_settings = [ | ||
"EMAIL_HOST", | ||
"EMAIL_PORT", | ||
"EMAIL_HOST_USER", | ||
"EMAIL_HOST_PASSWORD", | ||
"EMAIL_USE_TLS", | ||
"DEFAULT_FROM_EMAIL", | ||
] | ||
|
||
for setting in required_settings: | ||
if not getattr(settings, setting, None): | ||
error_message = f"Missing required email setting: {setting}" | ||
self.stdout.write(self.style.ERROR(error_message)) | ||
logger.error(f"Missing required email setting: {setting}") | ||
raise Exception(error_message) |
Oops, something went wrong.