-
-
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 #103 from MEHRSHAD-MIRSHEKARY/feat/pretty-format
✨ Feat/pretty format
- Loading branch information
Showing
2 changed files
with
180 additions
and
0 deletions.
There are no files selected for viewing
103 changes: 103 additions & 0 deletions
103
django_logging/management/commands/generate_pretty_json.py
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,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 |
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,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") |