Repository: inventree/InvenTree

Issue:
[FR] Don't log 404 errors
Currently any "error" on the server generates an error log in the database and notifies any staff users.

However this should probably be ignored for 404 errors
[FR] Don't log 404 errors
Currently any "error" on the server generates an error log in the database and notifies any staff users.

However this should probably be ignored for 404 errors


Discussion:
@SchrodingersGat can you point me to anything that raises a 404? Everything seem to redirect to the home/index.
@SchrodingersGat can you point me to anything that raises a 404? Everything seem to redirect to the home/index.

Resolving patch:
diff --git a/InvenTree/InvenTree/exceptions.py b/InvenTree/InvenTree/exceptions.py
--- a/InvenTree/InvenTree/exceptions.py
+++ b/InvenTree/InvenTree/exceptions.py
@@ -25,7 +25,13 @@ def log_error(path):
     Arguments:
         path: The 'path' (most likely a URL) associated with this error (optional)
     """
+
     kind, info, data = sys.exc_info()
+
+    # Check if the eror is on the ignore list
+    if kind in settings.IGNORRED_ERRORS:
+        return
+
     Error.objects.create(
         kind=kind.__name__,
         info=info,
diff --git a/InvenTree/InvenTree/middleware.py b/InvenTree/InvenTree/middleware.py
--- a/InvenTree/InvenTree/middleware.py
+++ b/InvenTree/InvenTree/middleware.py
@@ -1,6 +1,7 @@
 """Middleware for InvenTree."""
 
 import logging
+import sys
 
 from django.conf import settings
 from django.contrib.auth.middleware import PersistentRemoteUserMiddleware
@@ -10,6 +11,7 @@
 
 from allauth_2fa.middleware import (AllauthTwoFactorMiddleware,
                                     BaseRequire2FAMiddleware)
+from error_report.middleware import ExceptionProcessor
 from rest_framework.authtoken.models import Token
 
 from common.models import InvenTreeSetting
@@ -145,3 +147,17 @@ def process_request(self, request):
             return
 
         return super().process_request(request)
+
+
+class InvenTreeExceptionProcessor(ExceptionProcessor):
+    """Custom exception processor that respects blocked errors."""
+
+    def process_exception(self, request, exception):
+        """Check if kind is ignored before procesing."""
+        kind, info, data = sys.exc_info()
+
+        # Check if the eror is on the ignore list
+        if kind in settings.IGNORRED_ERRORS:
+            return
+
+        return super().process_exception(request, exception)
diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py
--- a/InvenTree/InvenTree/settings.py
+++ b/InvenTree/InvenTree/settings.py
@@ -19,6 +19,7 @@
 
 import django.conf.locale
 from django.core.files.storage import default_storage
+from django.http import Http404
 from django.utils.translation import gettext_lazy as _
 
 import moneyed
@@ -292,11 +293,9 @@ def _is_true(x):
     'InvenTree.middleware.AuthRequiredMiddleware',
     'InvenTree.middleware.Check2FAMiddleware',                  # Check if the user should be forced to use MFA
     'maintenance_mode.middleware.MaintenanceModeMiddleware',
+    'InvenTree.middleware.InvenTreeExceptionProcessor',         # Error reporting
 ])
 
-# Error reporting middleware
-MIDDLEWARE.append('error_report.middleware.ExceptionProcessor')
-
 AUTHENTICATION_BACKENDS = CONFIG.get('authentication_backends', [
     'django.contrib.auth.backends.RemoteUserBackend',           # proxy login
     'django.contrib.auth.backends.ModelBackend',
@@ -467,6 +466,10 @@ def _is_true(x):
 db_name = db_config['NAME']
 db_host = db_config.get('HOST', "''")
 
+if 'sqlite' in db_engine:
+    db_name = str(Path(db_name).resolve())
+    db_config['NAME'] = db_name
+
 logger.info(f"DB_ENGINE: {db_engine}")
 logger.info(f"DB_NAME: {db_name}")
 logger.info(f"DB_HOST: {db_host}")
@@ -928,6 +931,11 @@ def _is_true(x):
     for key, val in inventree_tags.items():
         sentry_sdk.set_tag(f'inventree_{key}', val)
 
+# In-database error logging
+IGNORRED_ERRORS = [
+    Http404
+]
+
 # Maintenance mode
 MAINTENANCE_MODE_RETRY_AFTER = 60
 MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.DefaultStorageBackend'


Test patch:
diff --git a/InvenTree/InvenTree/test_middleware.py b/InvenTree/InvenTree/test_middleware.py
--- a/InvenTree/InvenTree/test_middleware.py
+++ b/InvenTree/InvenTree/test_middleware.py
@@ -1,7 +1,12 @@
 """Tests for middleware functions."""
 
+from django.conf import settings
+from django.http import Http404
 from django.urls import reverse
 
+from error_report.models import Error
+
+from InvenTree.exceptions import log_error
 from InvenTree.helpers import InvenTreeTestCase
 
 
@@ -58,3 +63,35 @@ def test_token_auth(self):
 
         # should still fail without token
         self.check_path(reverse('settings.js'), 401)
+
+    def test_error_exceptions(self):
+        """Test that ignored errors are not logged."""
+        def check(excpected_nbr=0):
+            # Check that errors are empty
+            errors = Error.objects.all()
+            self.assertEqual(len(errors), excpected_nbr)
+
+        # Test normal setup
+        check()
+        response = self.client.get(reverse('part-detail', kwargs={'pk': 9999}))
+        self.assertEqual(response.status_code, 404)
+        check()
+
+        # Test manual logging
+        try:
+            raise Http404
+        except Http404:
+            log_error('testpath')
+
+        # Test setup without ignored errors
+        settings.IGNORRED_ERRORS = []
+        response = self.client.get(reverse('part-detail', kwargs={'pk': 9999}))
+        self.assertEqual(response.status_code, 404)
+        check(1)
+
+        # Test manual logging
+        try:
+            raise Http404
+        except Http404:
+            log_error('testpath')
+        check(2)