django-analytics-middleware 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,105 @@
1
+ import os
2
+ import sys
3
+ import logging
4
+ from django.conf import settings
5
+ from django.apps import AppConfig
6
+ from django.core.exceptions import ImproperlyConfigured
7
+
8
+
9
+ class AnalyticsMiddlewareConfig(AppConfig):
10
+ """Django app configuration for the analytics middleware"""
11
+
12
+ name = "django_analytics_middleware"
13
+ verbose_name = "Django Analytics Middleware"
14
+ default_auto_field = "django.db.models.BigAutoField"
15
+
16
+ def ready(self):
17
+ """
18
+ Called once when Django starts
19
+ """
20
+ if self._is_running_management_command():
21
+ return
22
+
23
+ # Validation Configuration
24
+ self._validate_configuration()
25
+ self._setup_package_logging()
26
+
27
+ logger = logging.getLogger(__name__)
28
+ logger.info("Analytics middleware initiated successfully")
29
+
30
+ def _is_running_management_command(self):
31
+ """Check if Django is running a command"""
32
+ return len(sys.argv) > 1 and sys.argv[1] in [
33
+ "migrate",
34
+ "makemigrations",
35
+ "collectstatic",
36
+ "flush",
37
+ "loaddata",
38
+ "dumpdata",
39
+ ]
40
+
41
+ def _validate_configuration(self):
42
+ """Validate user settings at startup"""
43
+ log_path = getattr(settings, "ANALYTICS_LOG_PATH", None)
44
+
45
+ if not log_path:
46
+ print(
47
+ "Analytics middleware: You must set ANALYTICS_LOG_PATH in your settings.py"
48
+ )
49
+ print(
50
+ "Example: ANALYTICS_LOG_PATH = os.path.join(BASEDIR, 'logs', 'analytics.log')"
51
+ )
52
+ print("Or in .env ANALYTICS_LOG_PATH=<LOG PATH>")
53
+ raise ImproperlyConfigured(
54
+ "Analytics middleware: You must set ANALYTICS_LOG_PATH in your settings.py\n"
55
+ "Example: ANALYTICS_LOG_PATH = os.path.join(BASEDIR, 'logs', 'analytics.log')\n"
56
+ "Or in .env ANALYTICS_LOG_PATH=<LOG PATH>"
57
+ )
58
+
59
+ # Test directory actually exists and create
60
+ log_dir = os.path.dirname(log_path)
61
+ if log_dir and not os.path.exists(log_dir):
62
+ try:
63
+ os.makedirs(log_dir, exist_ok=True)
64
+ print(f"Created log directory: {log_dir}")
65
+
66
+ except PermissionError:
67
+ raise RuntimeError(
68
+ f"Analytics middleware: Cannot create directory '{log_dir}'."
69
+ f"Either fix permissions or change ANALYTICS_LOG_PATH within settings.py."
70
+ )
71
+
72
+ # Tries to write to log to test permissions
73
+ try:
74
+ with open(log_path, "a") as test_file:
75
+ test_file.write("")
76
+ except PermissionError:
77
+ raise ImproperlyConfigured(
78
+ "Can't write to log file. Please ensure you have the correct permissions on your log folder."
79
+ )
80
+
81
+ # Retrieves noise paths list from settings.py
82
+ noise_paths = getattr(settings, "ANALYTICS_NOISE_PATHS", None)
83
+ if noise_paths is None:
84
+ print("No noise path field discovered within settings.py.")
85
+ print("Using default noise paths: /health, /admin, /favicon.ico")
86
+ noise_paths = ["/health", "/admin", "/favicon.ico"] # Set default
87
+
88
+ def _setup_package_logging(self):
89
+ """Configure logging"""
90
+
91
+ log_level_name = getattr(settings, "ANALYTICS_LOG_LEVEL", "WARNING")
92
+ log_level = getattr(logging, log_level_name.upper(), logging.WARNING)
93
+
94
+ # Configure package logger
95
+ logger = logging.getLogger(__name__)
96
+ logger.setLevel(log_level)
97
+
98
+ # Dont add handlers if already configured
99
+ if not logger.handlers:
100
+ handler = logging.StreamHandler()
101
+ formatter = logging.Formatter(
102
+ "[%(asctime)s] %(levelname)s: %(message)s", datefmt="%d-%m-%Y %H:%M:%S"
103
+ )
104
+ handler.setFormatter(formatter)
105
+ logger.addHandler(handler)
@@ -0,0 +1,58 @@
1
+ from django.utils import timezone
2
+ from django.conf import settings
3
+ import json
4
+
5
+
6
+ class AnalyticsMiddleware:
7
+ def __init__(self, get_response):
8
+ self.get_response = get_response
9
+ self.log_path = getattr(settings, "ANALYTICS_LOG_PATH", None)
10
+ self.noise_paths = getattr(
11
+ settings, "ANALYTICS_NOISE_PATHS", ["/health", "/admin", "/favicon.ico"]
12
+ )
13
+ self.disabled = not self.log_path
14
+
15
+ def __call__(self, request):
16
+ if self.disabled:
17
+ return self.get_response(request)
18
+
19
+ if any(request.path.startswith(path) for path in self.noise_paths):
20
+ return self.get_response(request)
21
+
22
+ start = timezone.now()
23
+ response = self.get_response(request)
24
+ duration = timezone.now() - start
25
+
26
+ x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
27
+ ip = (
28
+ x_forwarded_for.split(",")[0].strip()
29
+ if x_forwarded_for
30
+ else request.META.get("REMOTE_ADDR")
31
+ )
32
+
33
+ log_entry = {
34
+ "path": request.path,
35
+ "method": request.method,
36
+ "status": response.status_code,
37
+ "user_uuid": str(request.user.uuid)
38
+ if request.user.is_authenticated
39
+ else "unauthorized user",
40
+ "duration_ms": int(round(duration.total_seconds() * 1000)),
41
+ "ip": ip,
42
+ "user_agent": request.META.get("HTTP_USER_AGENT", ""),
43
+ "referrer": request.META.get("HTTP_REFERER", ""),
44
+ "timestamp": timezone.now().isoformat(),
45
+ "month": timezone.now().strftime("%b"),
46
+ "week": timezone.now().strftime("%V"),
47
+ "day": timezone.now().strftime("%a"),
48
+ "hour": timezone.now().strftime("%H"),
49
+ }
50
+
51
+ try:
52
+ with open(self.log_path, "a") as f:
53
+ f.write(json.dumps(log_entry) + "\n")
54
+
55
+ except Exception as e:
56
+ print(f"[Analytics Middleware Error]: {str(e)}")
57
+
58
+ return response
@@ -0,0 +1,144 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-analytics-middleware
3
+ Version: 0.1.0
4
+ Summary: Django middleware for request analytics logging
5
+ Author-email: Aaron Browne <github@futurumlabs.net>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Knowledgex187/django-audit-analytics-middleware.git
8
+ Project-URL: Source, https://github.com/Knowledgex187/django-audit-analytics-middleware.git
9
+ Project-URL: Issues, https://github.com/Knowledgex187/django-audit-analytics-middleware.git/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Framework :: Django
15
+ Requires-Python: >=3.7
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: Django>=2.2
19
+ Dynamic: license-file
20
+
21
+ # django-audit-analytics-middleware
22
+
23
+ **One middleware. Audit logs for compliance. Analytics for product.**
24
+
25
+ ## Status: 🏗️ Building in public
26
+
27
+ This package is under active development. I'm posting every step on LinkedIn.
28
+
29
+ ## What it will do (already working locally)
30
+
31
+ - [x] Log every request (path, method, status, user, IP, user agent)
32
+ - [x] Filter noise paths (/admin, /health, /static)
33
+ - [x] Duration tracking in milliseconds
34
+ - [x] IP extraction behind proxies (X-Forwarded-For)
35
+ - [ ] Configurable log file path
36
+ - [ ] Django admin view for logs
37
+ - [ ] Export to CSV/JSON command
38
+ - [ ] Tests (coming this week)
39
+ - [ ] PyPI release
40
+
41
+ ## Features
42
+
43
+ - 📊 Logs all HTTP requests with timing data
44
+ - 👤 Captures authenticated user UUIDs
45
+ - 🌐 Extracts real IP addresses (handles proxies)
46
+ - 🚫 Skips configurable noise paths (health checks, admin, etc.)
47
+ - 📝 Writes JSON logs for easy parsing
48
+ - ⚡ Minimal performance impact
49
+ - 🔒 Never breaks your application if logging fails
50
+
51
+ ## Want to help?
52
+
53
+ - Open an issue with your wishlist
54
+ - Star the repo to follow progress
55
+ - DM me on LinkedIn
56
+
57
+ ## Installation
58
+
59
+ ```bash
60
+ pip install django-analytics-middleware
61
+
62
+
63
+ # Add to INSTALLED_APPS
64
+ INSTALLED_APPS = [
65
+ ...
66
+ 'django_analytics_middleware',
67
+ ]
68
+
69
+ # Add to MIDDLEWARE
70
+ MIDDLEWARE = [
71
+ ...
72
+ 'django_analytics_middleware.middleware.AnalyticsMiddleware',
73
+ ]
74
+
75
+ # Configure log path
76
+ ANALYTICS_LOG_PATH = os.path.join(BASE_DIR, 'logs', 'analytics.log')
77
+
78
+ # For .env in settings.py
79
+ ANALYTICS_LOG_PATH = ANALYTICS_LOG_PATH=<env_handler>(<LOG PATH>)
80
+
81
+ Configuration
82
+ Required Settings
83
+ Setting Description Example
84
+ ANALYTICS_LOG_PATH Where to write log files os.path.join(BASE_DIR, 'logs', 'analytics.log')
85
+ Optional Settings
86
+ Setting Default Description
87
+ ANALYTICS_NOISE_PATHS ['/health', '/admin', '/favicon.ico'] Paths to skip logging
88
+ ANALYTICS_LOG_LEVEL 'WARNING' Logging level for the package
89
+
90
+
91
+ # Example settings.py
92
+
93
+ # Required
94
+ ANALYTICS_LOG_PATH = os.path.join(BASE_DIR, 'logs', 'analytics.log')
95
+
96
+ # Optional - Custom noise paths
97
+ ANALYTICS_NOISE_PATHS = [
98
+ '/health',
99
+ '/metrics',
100
+ '/admin',
101
+ '/favicon.ico',
102
+ '/robots.txt'
103
+ ]
104
+
105
+ # Optional - Set log level (DEBUG, INFO, WARNING, ERROR)
106
+ ANALYTICS_LOG_LEVEL = 'INFO'
107
+
108
+
109
+ # Log Format
110
+ {
111
+ "path": "/api/users/",
112
+ "method": "GET",
113
+ "status": 200,
114
+ "user_uuid": "550e8400-e29b-41d4-a716-446655440000",
115
+ "duration_ms": 45,
116
+ "ip": "192.168.1.100",
117
+ "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
118
+ "referrer": "https://example.com/",
119
+ "timestamp": "2024-01-15T10:30:45.123456+00:00",
120
+ "month": "Jan",
121
+ "week": "03",
122
+ "day": "Mon",
123
+ "hour": "10"
124
+ }
125
+
126
+ # Log Field Descriptions
127
+ Field Type Description
128
+ path string Request URL path
129
+ method string HTTP method (GET, POST, PUT, DELETE, etc.)
130
+ status integer HTTP response status code
131
+ user_uuid string Authenticated user's UUID or "unauthorized user"
132
+ duration_ms integer Request processing time in milliseconds
133
+ ip string Client IP address (handles proxy forwarding)
134
+ user_agent string Browser/device user agent string
135
+ referrer string Referring URL (where user came from)
136
+ timestamp string ISO 8601 timestamp with timezone
137
+ month string Three-letter month abbreviation (Jan, Feb, Mar)
138
+ week string ISO week number (01-53)
139
+ day string Three-letter day abbreviation (Mon, Tue, Wed)
140
+ hour string Hour in 24-hour format (00-23)
141
+
142
+ ## License
143
+
144
+ MIT – because audit logs shouldn't be paywalled.
@@ -0,0 +1,8 @@
1
+ django-audit-analytics-middleware/__init__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
2
+ django-audit-analytics-middleware/apps.py,sha256=SltiFWtPir85UqAUrDMJGgPZL7fc8yMzePtL-v8iPwg,3889
3
+ django-audit-analytics-middleware/middleware.py,sha256=USE8indBk8ss_ia3S_a72R2ciA2_W_-2BEtqS-v8e6o,1996
4
+ django_analytics_middleware-0.1.0.dist-info/licenses/LICENSE,sha256=F5eAheQ2ng9GuuSo5_mJJVKvAbyN41fyb2Vj1Fsa45I,1072
5
+ django_analytics_middleware-0.1.0.dist-info/METADATA,sha256=227twJVnodlpFHkKI3iDAXN0jhhusfIA1axHUWrqVU4,4396
6
+ django_analytics_middleware-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
7
+ django_analytics_middleware-0.1.0.dist-info/top_level.txt,sha256=kEMpjYS0hzHWI0-ToyrDdS-2q9GiMGVa7z7rAjavGk0,34
8
+ django_analytics_middleware-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Futurumlabs Ltd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ django-audit-analytics-middleware