How to log all errors related to an API request in Django Rest Framework along with multiple fields in a CSV file?
I want to log any type of error that occurs during an API request in Django Rest Framework into a CSV file, including the error message along with additional details like username, user ip, url, etc. I also want to capture errors that occur before reaching the view (e.g., errors related to JWT). I tried using middleware for this, but the issue was that some responses were not rendered correctly, and even after manually rendering, they still resulted in errors. I would appreciate it if you could suggest a solution.
The code below is the middleware I tried to use. I don't have an issue with logging errors that occur inside the view because if I only wanted to log errors within the view, I could use decorators or create a custom APIView. However, what I'm looking for is a way to log any type of error, even those that occur outside the view.
class ErrorLogMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.filename = settings.ERROR_LOG_PATH
self.fieldnames = ["Username", "IP", "User Agent", "Date/Time", "Time Interval", "Query", "Message", "URL"]
def __call__(self, request):
if not exists(self.filename):
with open(self.filename, "a", newline="", encoding="utf-8") as csvfile:
writer = DictWriter(csvfile, fieldnames=self.fieldnames)
writer.writeheader()
before = time()
try:
response = self.get_response(request)
if response.status_code != 200:
if hasattr(response, "render"):
if not response.is_rendered:
response.render()
error = None
if hasattr(response, "data"):
error = response.data
else:
html_content = response.content.decode("utf-8")
error = html_content.split("</title>")[0].split("<title>")[1]
self.submit_error(request, before, error)
return response
except Exception as e:
self.submit_error(request, before, e)
return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def submit_error(self, request, before, error):
after = time()
query = ""
for dic in connection.queries:
query += f"{dic['sql']}\n"
new_error_log = {
"Username": request.user.username,
"IP": get_user_ip(request),
"User Agent": request.META.get("HTTP_USER_AGENT"),
"Date/Time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"Time Interval": after - before,
"Query": query,
"Message": str(error),
"URL": request.get_full_path()
}
with open(self.filename, "a", newline="", encoding="utf-8") as csvfile:
writer = DictWriter(csvfile, fieldnames=self.fieldnames)
writer.writerow(new_error_log)
error: The response content must be rendered before it can be accessed