Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/pretty format #103

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions django_logging/management/commands/generate_pretty_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import json
import os
from typing import Dict, Tuple

from django.conf import settings
from django.core.management.base import BaseCommand

from django_logging.constants import DefaultLoggingSettings
from django_logging.constants.config_types import LogDir
from django_logging.utils.command.process_file import process_files, setup_directories


class Command(BaseCommand):
"""A Django management command to find JSON files within a specified log
directory and generate pretty JSON.

The command looks for `.json` files inside the `json` subdirectory of the log directory, attempts to
parse multiple JSON objects from a single file, and then formats them into a valid JSON array.

The reformatted JSON content is saved in a `pretty` subdirectory with the prefix `formatted_`.

"""

help = "Find JSON files in log directory and generates pretty JSON"

def handle(self, *args: Tuple, **kwargs: Dict) -> None:
"""Main command handler. This method retrieves the log directory, sets
up necessary directories, processes each `.json` file, and reformats
the content.

Args:
*args: Additional positional arguments (not used).
**kwargs: Additional keyword arguments (not used).

"""
default_settings = DefaultLoggingSettings()
log_dir: LogDir = settings.DJANGO_LOGGING.get(
"LOG_DIR", os.path.join(os.getcwd(), default_settings.log_dir)
)

try:
json_dir, pretty_dir = setup_directories(log_dir, "json")
except FileNotFoundError as e:
self.stdout.write(self.style.ERROR(str(e)))
return

for file_path, filename in process_files(json_dir, ".json", self.reformat_json):
self.stdout.write(self.style.NOTICE(f"Processing file: {file_path}"))

new_file_path: str = os.path.join(pretty_dir, f"formatted_{filename}")
self.reformat_json(file_path, new_file_path)

self.stdout.write(
self.style.SUCCESS(
f"File {filename} reformatted and generated new pretty file successfully."
)
)

def reformat_json(self, file_path: str, new_file_path: str) -> None:
"""Parses multiple JSON objects from a file incrementally and writes
them to a new file as a valid JSON array.

Args:
file_path (str): The path to the original JSON file.
new_file_path (str): The path where the reformatted JSON file will be saved.

"""
with open(file_path, encoding="utf-8") as infile, open(
new_file_path, "w", encoding="utf-8"
) as outfile:
outfile.write("[\n") # Start the JSON array
first_object = True # Flag to handle commas

buffer = "" # This will accumulate the JSON content

for line in infile:
line = line.strip()

if not line:
continue # Skip empty lines

buffer += line

# Try to parse the current buffer as a complete JSON object
try:
json_object = json.loads(buffer)
json_line = json.dumps(json_object, indent=4)

if not first_object:
outfile.write(",\n") # Add a comma before subsequent objects
outfile.write(json_line)

first_object = False
buffer = "" # Clear the buffer after successful parsing
except json.JSONDecodeError:
# Keep accumulating if it's not a complete JSON object yet
continue

if buffer:
# If any partial JSON is left in the buffer, log an error
self.stdout.write(self.style.ERROR(f"Incomplete JSON object: {buffer}"))

outfile.write("\n]") # End the JSON array
77 changes: 77 additions & 0 deletions django_logging/management/commands/generate_pretty_xml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import os
from typing import Any, Dict, Tuple

from django.conf import settings
from django.core.management.base import BaseCommand

from django_logging.constants import DefaultLoggingSettings
from django_logging.constants.config_types import LogDir
from django_logging.utils.command.process_file import process_files, setup_directories


class Command(BaseCommand):
"""Command to find and reformat XML files in a specified directory.

This command processes all XML files in the specified log directory, reformats
them by wrapping their content in a <logs> element, and saves the reformatted
files to a new directory. It handles parsing errors and logs the process steps.

Attributes:
help (str): A brief description of the command's functionality.

"""

help = "Find and reformat XML files in a directory"

def handle(self, *args: Tuple[Any], **kwargs: Dict[str, Any]) -> None:
"""Handles the command execution.

Args:
*args: Positional arguments passed to the command.
**kwargs: Keyword arguments passed to the command.

"""
default_settings = DefaultLoggingSettings()
log_dir: LogDir = settings.DJANGO_LOGGING.get(
"LOG_DIR", os.path.join(os.getcwd(), default_settings.log_dir)
)

try:
xml_dir, pretty_dir = setup_directories(log_dir, "xml")
except FileNotFoundError as e:
self.stdout.write(self.style.ERROR(str(e)))
return

for file_path, filename in process_files(
xml_dir, ".xml", self.reformat_and_write_xml
):
self.stdout.write(self.style.NOTICE(f"Processing file: {file_path}"))

new_file_path = os.path.join(pretty_dir, f"formatted_{filename}")
self.reformat_and_write_xml(file_path, new_file_path)
self.stdout.write(
self.style.SUCCESS(f"File {filename} reformatted successfully.")
)

def reformat_and_write_xml(self, file_path: str, new_file_path: str) -> None:
"""Reformats XML content by wrapping it in a <logs> element and writes
it to a new file.

Args:
file_path (str): The path of the original XML file to be reformatted.
new_file_path (str): The path where the reformatted XML file will be saved.

"""
with open(file_path, encoding="utf-8") as infile, open(
new_file_path, "w", encoding="utf-8"
) as outfile:
# Start the <logs> element
outfile.write("<logs>\n")

for line in infile:
# Write each line to the formatted file
if line.strip(): # Only process non-empty lines
outfile.write(line)

# End the <logs> element
outfile.write("</logs>\n")