Added support for logging in JSON format as well. (#1985)

* Added functionality to have json format as well for the logs

* Added additional comments, refractored logging functionality

* Fixed documentation to include the new paramter

* Fixed typo

* Added a Pydantic Error Check between output_log_file and save_as_json parameter

* Removed the save_to_json parameter, incorporated the functionality directly with output_log_file

* Fixed typo

* Sorted the imports using isort

---------

Co-authored-by: Vidit Ostwal <vidit.ostwal@piramal.com>
Co-authored-by: Brandon Hancock (bhancock_ai) <109994880+bhancockio@users.noreply.github.com>
This commit is contained in:
Vidit Ostwal
2025-02-07 23:46:44 +05:30
committed by GitHub
parent fa26f6ebae
commit 0cc02d9492
3 changed files with 74 additions and 22 deletions

View File

@@ -184,9 +184,9 @@ class Crew(BaseModel):
default=None,
description="Path to the prompt json file to be used for the crew.",
)
output_log_file: Optional[str] = Field(
output_log_file: Optional[Union[bool, str]] = Field(
default=None,
description="output_log_file",
description="Path to the log file to be saved",
)
planning: Optional[bool] = Field(
default=False,
@@ -440,6 +440,7 @@ class Crew(BaseModel):
)
return self
@property
def key(self) -> str:
source = [agent.key for agent in self.agents] + [

View File

@@ -1,30 +1,64 @@
import json
import os
import pickle
from datetime import datetime
from typing import Union
class FileHandler:
"""take care of file operations, currently it only logs messages to a file"""
"""Handler for file operations supporting both JSON and text-based logging.
Args:
file_path (Union[bool, str]): Path to the log file or boolean flag
"""
def __init__(self, file_path):
if isinstance(file_path, bool):
def __init__(self, file_path: Union[bool, str]):
self._initialize_path(file_path)
def _initialize_path(self, file_path: Union[bool, str]):
if file_path is True: # File path is boolean True
self._path = os.path.join(os.curdir, "logs.txt")
elif isinstance(file_path, str):
self._path = file_path
elif isinstance(file_path, str): # File path is a string
if file_path.endswith((".json", ".txt")):
self._path = file_path # No modification if the file ends with .json or .txt
else:
self._path = file_path + ".txt" # Append .txt if the file doesn't end with .json or .txt
else:
raise ValueError("file_path must be either a boolean or a string.")
raise ValueError("file_path must be a string or boolean.") # Handle the case where file_path isn't valid
def log(self, **kwargs):
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
message = (
f"{now}: "
+ ", ".join([f'{key}="{value}"' for key, value in kwargs.items()])
+ "\n"
)
with open(self._path, "a", encoding="utf-8") as file:
file.write(message + "\n")
try:
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
log_entry = {"timestamp": now, **kwargs}
if self._path.endswith(".json"):
# Append log in JSON format
with open(self._path, "a", encoding="utf-8") as file:
# If the file is empty, start with a list; else, append to it
try:
# Try reading existing content to avoid overwriting
with open(self._path, "r", encoding="utf-8") as read_file:
existing_data = json.load(read_file)
existing_data.append(log_entry)
except (json.JSONDecodeError, FileNotFoundError):
# If no valid JSON or file doesn't exist, start with an empty list
existing_data = [log_entry]
with open(self._path, "w", encoding="utf-8") as write_file:
json.dump(existing_data, write_file, indent=4)
write_file.write("\n")
else:
# Append log in plain text format
message = f"{now}: " + ", ".join([f"{key}=\"{value}\"" for key, value in kwargs.items()]) + "\n"
with open(self._path, "a", encoding="utf-8") as file:
file.write(message)
except Exception as e:
raise ValueError(f"Failed to log message: {str(e)}")
class PickleHandler:
def __init__(self, file_name: str) -> None:
"""