smartpylogger 0.1.0__tar.gz

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,7 @@
1
+ Copyright (c) 2025 bombaclaat inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: smartpylogger
3
+ Version: 0.1.0
4
+ Summary: Lightweight structured logger for Py projects with AI analysis!
5
+ Author-email: Your Name <your@email.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/yourusername/smartpylogger
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.7
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: colorama
15
+ Requires-Dist: httpx
16
+ Requires-Dist: fastapi
17
+ Requires-Dist: starlette
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest>=6.0; extra == "dev"
20
+ Requires-Dist: pytest-cov>=2.0; extra == "dev"
21
+ Requires-Dist: black>=21.0; extra == "dev"
22
+ Requires-Dist: flake8>=3.8; extra == "dev"
23
+ Requires-Dist: mypy>=0.800; extra == "dev"
24
+ Dynamic: license-file
25
+ Dynamic: requires-python
26
+
27
+ # SmartPyLogger
28
+
29
+ ```text
30
+ ....................................................................................
31
+ ....................................................................................
32
+ ..........................................-++=..:...................................
33
+ .............-.........................=**#######+:.........-.......................
34
+ .............................-.......:=#***##**##*=.....................-...........
35
+ ......-.............................:+******#**##*#=................................
36
+ .............-...................:=*********####%##*:...............................
37
+ ..............................:+************#*####=..................-..............
38
+ ...-*+=:.................-=****##*****####*######%+:................................
39
+ ...-*#*#**##*********##**#*******#######**#%%#***#%+................................
40
+ ...:=*****#*##*######****#*****#####*#*++--*%##***##=.........-.....................
41
+ ....-******###*##**###**###*#*###****+-...:-*%%#**##%-..................-...........
42
+ ....:=******###*###****#**#**#####**+:......-*%##***%#-.............................
43
+ .....:+*#***##***###******##**###**+:.......:-*%##**#%*-............................
44
+ ......-*#****######***#**#*##*##**+:.........:-*%#*+*#%#:...........................
45
+ ......:-*******#**********#***##**-...........-:=*##***#%*:.........................
46
+ ........:-+#***************##**##**-............:=*##****#%*-.......................
47
+ ............:=*#************+*###*#+.............-=*###**#%@%#-.....................
48
+ .............:-+#*************+*###*-......-......:-+*#%####%%*:....................
49
+ .......-.......:-=*#***************+.................-=*#%%%*###%=..................
50
+ ..................:--##*************-.................:-+*%#****#%*.................
51
+ ............-.......:--+#************#..................-=*#%#**#%%%-...............
52
+ ........................::*********--+:...................:-=*###***#%*.............
53
+ .../PPPP/PPPPPPPPP..........++#*****--#....................:-=+###*#%%%.............
54
+ ..| PPPPPPPPPPPPPPP..............-'++-#......................:=#%#***%%+............
55
+ ..| PPPP_______/PPPP..-.........................-.............:=#%#***%%+...........
56
+ ..| PPPP......| PPPP..........................................:=#%#***%%+...........
57
+ ..| PPPPPPPPPPPPPPP./YYYY..../YYYY........-...................:=#%#***%%+...........
58
+ ..| PPPP/PPPPPPPP..| YYYY...| YYYY............................:=*%##**#%#-..........
59
+ ..| PPPP_______/...| YYYY...| YYYY.............................=*%%##*#%%=..........
60
+ ..| PPPP............\ YYYYYYYYYYYY.....ooo....................=+%%%#**%%+...........
61
+ ..| PPPP.............\ YYYYY_/YYYY.../OOOOO....-.............:=+###**#%#:...........
62
+ ../____/..............\___/.| YYYY...| OOO...................=+#%#**#%#:............
63
+ ...................../YYYY..| YYYY....\__/.................:=+***++++**-............
64
+ .............-......| YYYYY/ YYYYY...-..............................................
65
+ .....................\ YYYYYYYYYY...................................................
66
+ .......-..............\________/....................................................
67
+ ....................................................................................
68
+ ....................................................................................
69
+ ```
70
+
71
+ Thank you so much for downloading and using SmartPyLogger!
72
+ Developed by Niklavs Visockis, Ludvig Bergström and Jonas Lorenz -
73
+ in June of 2025 at the Couchbase x AWS x Cillers Hackathon.
74
+ Special thanks goes out to the Couchbase team and AWS for sponsoring this project.
75
+
76
+ ### FastAPI middleware for comprehensive request/response logging.
77
+
78
+ ## Installation
79
+
80
+ ```bash
81
+ pip install -e .
82
+ ```
83
+
84
+ ## Usage
85
+
86
+ ```python
87
+ from fastapi import FastAPI
88
+ from smartpylogger import LoggingMiddleware
89
+
90
+ app = FastAPI()
91
+
92
+ # Add your middleware
93
+ app.add_middleware(
94
+ LoggingMiddleware,
95
+ api_key="YOUR_API_KEY",
96
+ allowed_origins=["IP", ...]
97
+ )
98
+ ```
99
+
100
+ ## What it logs:
101
+
102
+ - **Request details**: Nothing yet
@@ -0,0 +1,60 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "smartpylogger"
7
+ version = "0.1.0"
8
+ description = "Lightweight structured logger for Py projects with AI analysis!"
9
+ readme = "smartpylogger/README.md"
10
+ requires-python = ">=3.7"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "Your Name", email = "your@email.com"}
14
+ ]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: OS Independent"
19
+ ]
20
+
21
+ dependencies = [
22
+ "colorama",
23
+ "httpx",
24
+ "fastapi",
25
+ "starlette"
26
+ ]
27
+
28
+ [tool.setuptools]
29
+ packages = ["smartpylogger"]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/yourusername/smartpylogger"
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "pytest>=6.0",
37
+ "pytest-cov>=2.0",
38
+ "black>=21.0",
39
+ "flake8>=3.8",
40
+ "mypy>=0.800",
41
+ ]
42
+
43
+ [project.scripts]
44
+ couchbase-middleware = "couchbase_middleware.cli:main"
45
+
46
+ [tool.black]
47
+ line-length = 88
48
+ target-version = ['py38']
49
+
50
+ [tool.mypy]
51
+ python_version = "3.8"
52
+ warn_return_any = true
53
+ warn_unused_configs = true
54
+ disallow_untyped_defs = true
55
+
56
+ [tool.pytest.ini_options]
57
+ testpaths = ["tests"]
58
+ python_files = ["test_*.py"]
59
+ python_classes = ["Test*"]
60
+ python_functions = ["test_*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,20 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ with open("smartpylogger/README.md", "r", encoding="utf-8") as f:
4
+ long_description = f.read()
5
+ setup(
6
+ name="smartpylogger",
7
+ version="0.1.0",
8
+ description="Lightweight structured logger for Py projects with AI analysis!",
9
+ packages=find_packages(),
10
+ # install_requires=[], # or just remove this line entirely
11
+ long_description=long_description,
12
+ long_description_content_type="text/markdown",
13
+ classifiers=[
14
+ "Programming Language :: Python :: 3",
15
+ "License :: OSI Approved :: MIT License", # or whichever license
16
+ "Operating System :: OS Independent",
17
+ ],
18
+ python_requires='>=3.7',
19
+ )
20
+
@@ -0,0 +1,76 @@
1
+ # SmartPyLogger
2
+
3
+ ```text
4
+ ....................................................................................
5
+ ....................................................................................
6
+ ..........................................-++=..:...................................
7
+ .............-.........................=**#######+:.........-.......................
8
+ .............................-.......:=#***##**##*=.....................-...........
9
+ ......-.............................:+******#**##*#=................................
10
+ .............-...................:=*********####%##*:...............................
11
+ ..............................:+************#*####=..................-..............
12
+ ...-*+=:.................-=****##*****####*######%+:................................
13
+ ...-*#*#**##*********##**#*******#######**#%%#***#%+................................
14
+ ...:=*****#*##*######****#*****#####*#*++--*%##***##=.........-.....................
15
+ ....-******###*##**###**###*#*###****+-...:-*%%#**##%-..................-...........
16
+ ....:=******###*###****#**#**#####**+:......-*%##***%#-.............................
17
+ .....:+*#***##***###******##**###**+:.......:-*%##**#%*-............................
18
+ ......-*#****######***#**#*##*##**+:.........:-*%#*+*#%#:...........................
19
+ ......:-*******#**********#***##**-...........-:=*##***#%*:.........................
20
+ ........:-+#***************##**##**-............:=*##****#%*-.......................
21
+ ............:=*#************+*###*#+.............-=*###**#%@%#-.....................
22
+ .............:-+#*************+*###*-......-......:-+*#%####%%*:....................
23
+ .......-.......:-=*#***************+.................-=*#%%%*###%=..................
24
+ ..................:--##*************-.................:-+*%#****#%*.................
25
+ ............-.......:--+#************#..................-=*#%#**#%%%-...............
26
+ ........................::*********--+:...................:-=*###***#%*.............
27
+ .../PPPP/PPPPPPPPP..........++#*****--#....................:-=+###*#%%%.............
28
+ ..| PPPPPPPPPPPPPPP..............-'++-#......................:=#%#***%%+............
29
+ ..| PPPP_______/PPPP..-.........................-.............:=#%#***%%+...........
30
+ ..| PPPP......| PPPP..........................................:=#%#***%%+...........
31
+ ..| PPPPPPPPPPPPPPP./YYYY..../YYYY........-...................:=#%#***%%+...........
32
+ ..| PPPP/PPPPPPPP..| YYYY...| YYYY............................:=*%##**#%#-..........
33
+ ..| PPPP_______/...| YYYY...| YYYY.............................=*%%##*#%%=..........
34
+ ..| PPPP............\ YYYYYYYYYYYY.....ooo....................=+%%%#**%%+...........
35
+ ..| PPPP.............\ YYYYY_/YYYY.../OOOOO....-.............:=+###**#%#:...........
36
+ ../____/..............\___/.| YYYY...| OOO...................=+#%#**#%#:............
37
+ ...................../YYYY..| YYYY....\__/.................:=+***++++**-............
38
+ .............-......| YYYYY/ YYYYY...-..............................................
39
+ .....................\ YYYYYYYYYY...................................................
40
+ .......-..............\________/....................................................
41
+ ....................................................................................
42
+ ....................................................................................
43
+ ```
44
+
45
+ Thank you so much for downloading and using SmartPyLogger!
46
+ Developed by Niklavs Visockis, Ludvig Bergström and Jonas Lorenz -
47
+ in June of 2025 at the Couchbase x AWS x Cillers Hackathon.
48
+ Special thanks goes out to the Couchbase team and AWS for sponsoring this project.
49
+
50
+ ### FastAPI middleware for comprehensive request/response logging.
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ pip install -e .
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ ```python
61
+ from fastapi import FastAPI
62
+ from smartpylogger import LoggingMiddleware
63
+
64
+ app = FastAPI()
65
+
66
+ # Add your middleware
67
+ app.add_middleware(
68
+ LoggingMiddleware,
69
+ api_key="YOUR_API_KEY",
70
+ allowed_origins=["IP", ...]
71
+ )
72
+ ```
73
+
74
+ ## What it logs:
75
+
76
+ - **Request details**: Nothing yet
@@ -0,0 +1,11 @@
1
+ # backend/smartpylogger/__init__.py
2
+
3
+ # Version (optional, but good practice)
4
+ __version__ = "0.1.0"
5
+
6
+ # Import and expose your main classes/functions
7
+ from .logger import LoggingMiddleware
8
+ from .utils import * # if you want to expose all utils
9
+
10
+ # Define what is available for import *
11
+ __all__ = ["LoggingMiddleware"]
@@ -0,0 +1,283 @@
1
+ """
2
+ FastAPI middleware for request/response logging
3
+
4
+ This logger ONLY sends POST request data to api_server.py
5
+ api_server.py handles all database operations and dashboard communication
6
+ """
7
+
8
+ import subprocess
9
+ import os
10
+ import time
11
+ import platform
12
+ from datetime import datetime
13
+ from random import randint
14
+
15
+ # Colors for console output
16
+ from colorama import Fore, Style
17
+
18
+ import json
19
+ # import requests
20
+ import httpx # replace requests with httpx for async support & speed
21
+ from typing import Dict, Any, Optional
22
+
23
+ from fastapi import Request, Response, HTTPException
24
+ from starlette.middleware.base import BaseHTTPMiddleware
25
+ from starlette.middleware.base import RequestResponseEndpoint
26
+
27
+
28
+ API_URL="http://localhost:8000" ### CHANGE TO EXTERNAL IP LATER
29
+
30
+ class ClientError(Exception):
31
+ pass
32
+
33
+ class LoggingMiddleware(BaseHTTPMiddleware):
34
+ """FastAPI middleware - intercepts requests and sends to api_server.py"""
35
+
36
+ def __init__(self, app, api_key: str = "", allowed_origins: Optional[list[str]] = None, api_limit_daily: int = 1000, censored_words: Optional[list[str]] = None, banned_words_path: Optional[str] = None):
37
+ """Initialize middleware with API credentials"""
38
+
39
+ print(f"""{Fore.GREEN}
40
+ ..............................................................................
41
+ ..........................................-++=..:.............................
42
+ .............-.........................=**#######+:.........-.................
43
+ .............................-.......:=#***##**##*=.....................-.....
44
+ ......-.............................:+******#**##*#=..........................
45
+ .............-...................:=*********####%##*:.........................
46
+ ..............................:+************#*####=..................-........
47
+ ...-*+=:.................-=****##*****####*######%+:..........................
48
+ ...-*#*#**##*********##**#*******#######**#%%#***#%+..........................
49
+ ...:=*****#*##*######****#*****#####*#*++--*%##***##=.........-...............
50
+ ....-******###*##**###**###*#*###****+-...:-*%%#**##%-..................-.....
51
+ ....:=******###*###****#**#**#####**+:......-*%##***%#-.......................
52
+ .....:+*#***##***###******##**###**+:.......:-*%##**#%*-......................
53
+ ......-*#****######***#**#*##*##**+:.........:-*%#*+*#%#:.....................
54
+ ......:-*******#**********#***##**-...........-:=*##***#%*:...................
55
+ ........:-+#***************##**##**-............:=*##****#%*-.................
56
+ ............:=*#************+*###*#+.............-=*###**#%@%#-...............
57
+ .............:-+#*************+*###*-......-......:-+*#%####%%*:..............
58
+ .......-.......:-=*#***************+.................-=*#%%%*###%=............
59
+ ..................:--##*************-.................:-+*%#****#%*...........
60
+ ............-.......:--+#************#..................-=*#%#**#%%%-.........
61
+ ........................::*********--+:...................:-=*###***#%*.......
62
+ .../PPPP/PPPPPPPPP..........++#*****--#....................:-=+###*#%%%.......
63
+ ..| PPPPPPPPPPPPPPP..............-'++-#......................:=#%#***%%+......
64
+ ..| PPPP_______/PPPP..-.........................-.............:=#%#***%%+.....
65
+ ..| PPPP......| PPPP..........................................:=#%#***%%+.....
66
+ ..| PPPPPPPPPPPPPPP./YYYY..../YYYY........-...................:=#%#***%%+.....
67
+ ..| PPPP/PPPPPPPP..| YYYY...| YYYY............................:=*%##**#%#-....
68
+ ..| PPPP_______/...| YYYY...| YYYY.............................=*%%##*#%%=....
69
+ ..| PPPP............( YYYYYYYYYYYY.....ooo....................=+%%%#**%%+.....
70
+ ..| PPPP.............( YYYYY_/YYYY.../OOOOO....-.............:=+###**#%#:.....
71
+ ../____/..............(__/..| YYYY...| OOO....................=+#%#**#%#:.....
72
+ ...................../YYYY..| YYYY....(__/...................:=+***++++**-....
73
+ .............-......| YYYYY/ YYYYY...-........................................
74
+ .....................( YYYYYYYYYY.............................................
75
+ .......-..............(________/..............................................
76
+ ..............................................................................
77
+ ..............................................................................
78
+ {Style.RESET_ALL}
79
+ Thank you so much for downloading and using SmartPyLogger!
80
+ Developed by Niklavs Visockis, Ludvig Bergström and Jonas Lorenz -
81
+ in June of 2025 at the Couchbase x AWS x Cillers Hackathon.
82
+ Special thanks goes out to the Couchbase team and AWS for sponsoring this project.
83
+
84
+ """)
85
+
86
+
87
+ # Timing start:
88
+ start = time.perf_counter()
89
+
90
+ print(f"{Fore.MAGENTA}[STATUS]{Style.RESET_ALL}: Initializing LoggingMiddleware...")
91
+
92
+ # Basic configuration
93
+ self.api_key = api_key
94
+ self.api_url = API_URL
95
+ self.allowed_origins = allowed_origins or []
96
+ self.api_limit_daily = api_limit_daily # Limit for API requests, default to 1000
97
+ self.censored_words = censored_words or []
98
+ self.banned_words_path = banned_words_path
99
+
100
+ # Validator paths
101
+ self.content_validator_path = ""
102
+ self.ip_validator_path = ""
103
+
104
+ super().__init__(app) # Inhereting from BaseHTTPMiddleware
105
+
106
+ self.app_name = getattr(app, "title", None)
107
+
108
+ ### ---- VALIDATE USER ---- ###
109
+
110
+ ### Check if API key is provided and return session ID if it is, otherwise raise error
111
+ try:
112
+ response = httpx.post(
113
+ self.api_url + "/api/auth/validate",
114
+ json={"api_key": self.api_key, "appSessionName": self.app_name},
115
+ timeout=10.0 # 10 second timeout
116
+ )
117
+
118
+ self.auth = response.json()["app_session_id"] ### Get session ID to see if API key is valid
119
+
120
+ # print(self.auth)
121
+
122
+ if self.auth != "0":
123
+ print(f"{Fore.MAGENTA}[STATUS]{Style.RESET_ALL}: API key loaded successfully. Session initialization...")
124
+ print(f"{Fore.MAGENTA}[STATUS]{Style.RESET_ALL}: Session init success! Session ID: "
125
+ f"{Fore.BLUE}{str(self.auth)}")
126
+
127
+ elif self.auth == "0":
128
+ print(f"{Fore.RED}[ERROR]: Invalid API key")
129
+ raise HTTPException(
130
+ status_code=401,
131
+ detail="Invalid API key"
132
+ )
133
+
134
+ else:
135
+ print(f"{Fore.RED}[ERROR]: Unknown error during API key validation or session initialization")
136
+ raise HTTPException(
137
+ status_code=500,
138
+ detail="Unknown error during API key validation"
139
+ )
140
+
141
+ except httpx.ConnectError:
142
+ print(f"{Fore.RED}[ERROR]: Cannot connect to validation server at {self.api_url}")
143
+ raise HTTPException(
144
+ status_code=503,
145
+ detail="Validation server unavailable"
146
+ )
147
+ except httpx.TimeoutException:
148
+ print(f"{Fore.RED}[ERROR]: Timeout connecting to validation server")
149
+ raise HTTPException(
150
+ status_code=503,
151
+ detail="Validation server timeout"
152
+ )
153
+ except Exception as e:
154
+ print(f"{Fore.RED}[ERROR]: Unexpected error during validation: {e}")
155
+ raise HTTPException(
156
+ status_code=500,
157
+ detail="Validation error"
158
+ )
159
+
160
+ ### ---- CHECK USER MACHINE AND PICK EXEC. PATH ---- ###
161
+
162
+ current_dir = os.path.dirname(os.path.abspath(__file__))
163
+ system = platform.system().lower()
164
+ try:
165
+ if system == "windows": # obviously
166
+ self.ip_validator_path = os.path.join(current_dir, "validators", "ip_validator_windows.exe")
167
+ self.content_validator_path = os.path.join(current_dir, "validators", "contains_windows.exe")
168
+
169
+ elif system == "darwin": # macOS
170
+ self.ip_validator_path = os.path.join(current_dir, "validators", "ip_validator_mac")
171
+ self.content_validator_path = os.path.join(current_dir, "validators", "contains_mac")
172
+
173
+ else: # linux
174
+ self.ip_validator_path = os.path.join(current_dir, "validators", "ip_validator_linux")
175
+ self.content_validator_path = os.path.join(current_dir, "validators", "contains_linux")
176
+
177
+ except Exception as e:
178
+ print(f"{Fore.RED}[ERROR]: Error setting validator paths: {e}")
179
+ raise HTTPException(
180
+ status_code=500,
181
+ detail="Error setting validator paths"
182
+ )
183
+
184
+ print(f"{Fore.MAGENTA}[STATUS]{Style.RESET_ALL}: You're all set up! Using {system} validators.")
185
+
186
+ # Timing end:
187
+ end = time.perf_counter()
188
+
189
+ print(f"{Fore.MAGENTA}[STATUS]{Style.RESET_ALL}: LoggingMiddleware initialized in {1000 * (end - start):.3f} ms.")
190
+
191
+
192
+ ### ---- MAIN ASYNC DISPATCH METHOD ---- ###
193
+ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response: # type: ignore
194
+ """Intercept request/response, sensor for bad words quickly and send off to api_server.py"""
195
+ # Read the request body & load to JSON to send off to API
196
+ body = await request.body()
197
+ sender_ip = request.client.host # type: ignore
198
+ request_method = request.method
199
+ timestamp = datetime.now().strftime("%Y/%m/%d/%H:%M:%S")
200
+
201
+ try:
202
+ body_dict = json.loads(body)
203
+ except Exception:
204
+ body_dict = {}
205
+
206
+ # Wrap it for the /api/schemas endpoint
207
+ payload = {"api_key":self.api_key,
208
+ "session_id":self.auth,
209
+ "app_name": self.app_name,
210
+ "request_method": request_method,
211
+ "request_data": body_dict,
212
+ "allowed_origins": self.allowed_origins,
213
+ "sender_ip": sender_ip,
214
+ "timestamp": timestamp,
215
+ "flag": 0}
216
+
217
+ # 1. IP VALIDATION (fatal, but log first)
218
+ ip_validator_path = self.ip_validator_path
219
+ payload_json = json.dumps(payload)
220
+ result = subprocess.run(
221
+ [ip_validator_path, payload_json],
222
+ capture_output=True,
223
+ text=True,
224
+ timeout=5
225
+ )
226
+
227
+ # print("Go IP validator output:", repr(result.stdout))
228
+ if result.stdout:
229
+ try:
230
+ validated_payload = json.loads(result.stdout)
231
+ print("Go validator returned valid JSON:", validated_payload)
232
+ except json.JSONDecodeError:
233
+ print("Go validator did not return valid JSON:", result.stdout)
234
+ validated_payload = payload # fallback to original here
235
+ else:
236
+ print("Go validator returned no output!")
237
+ validated_payload = payload # fallback to original also
238
+
239
+
240
+ # 4. If IP was blocked, now raise the HTTP error COPY OF CORS BROTHA
241
+ if result.returncode != 0:
242
+
243
+ try:
244
+ httpx.post(
245
+ self.api_url + "/api/schemas",
246
+ json=validated_payload,
247
+ timeout=5.0
248
+ )
249
+ except Exception as e:
250
+ print(f"{Fore.YELLOW}[WARNING]: Could not send blocked request to API: {e}")
251
+
252
+ raise HTTPException(
253
+ status_code=403,
254
+ detail=f"Request blocked: Unauthorized IP address. {result.stdout.strip()}"
255
+ )
256
+
257
+
258
+ # 2. CONTENT VALIDATION (non-fatal, but log)
259
+ content_validator_path = self.content_validator_path
260
+ banned_words_path = self.banned_words_path or "bad_words.txt" # fallback if not set
261
+ result = subprocess.run(
262
+ [content_validator_path, payload_json, banned_words_path],
263
+ capture_output=True,
264
+ text=True,
265
+ timeout=5
266
+ )
267
+ # print("Go validator output:", repr(result.stdout))
268
+
269
+ try:
270
+ httpx.post(
271
+ self.api_url + "/api/schemas",
272
+ json=validated_payload,
273
+ timeout=5.0
274
+ )
275
+ except Exception as e:
276
+ print(f"{Fore.YELLOW}[WARNING]: Could not send request to API: {e}")
277
+
278
+ # Decriment the API limit
279
+ self.api_limit_daily -= 1
280
+
281
+ # 5. Otherwise, continue as normal
282
+ response = await call_next(request)
283
+ return response
@@ -0,0 +1,28 @@
1
+ """
2
+ Utility functions for the smartpylogger package
3
+
4
+ Unsure of what this will actually contain
5
+ """
6
+
7
+ import json
8
+ import hashlib
9
+ import time
10
+ from typing import Dict, Any, Optional
11
+
12
+
13
+ def format_schema(data: Dict[str, Any]) -> Dict[str, Any]:
14
+ """Formatting and structure schema data for API submission"""
15
+ return {
16
+ "schema_version": "1.0",
17
+ "timestamp": time.time(),
18
+ "data": data,
19
+ }
20
+
21
+ def format_timestamp(timestamp: float) -> str:
22
+ """Format timestamp for logging"""
23
+ return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp))
24
+
25
+ def create_request_id() -> str:
26
+ """Generate unique request ID"""
27
+ return f"req_{int(time.time() * 1000)}_{hash(time.time()) % 10000}"
28
+
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: smartpylogger
3
+ Version: 0.1.0
4
+ Summary: Lightweight structured logger for Py projects with AI analysis!
5
+ Author-email: Your Name <your@email.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/yourusername/smartpylogger
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.7
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: colorama
15
+ Requires-Dist: httpx
16
+ Requires-Dist: fastapi
17
+ Requires-Dist: starlette
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest>=6.0; extra == "dev"
20
+ Requires-Dist: pytest-cov>=2.0; extra == "dev"
21
+ Requires-Dist: black>=21.0; extra == "dev"
22
+ Requires-Dist: flake8>=3.8; extra == "dev"
23
+ Requires-Dist: mypy>=0.800; extra == "dev"
24
+ Dynamic: license-file
25
+ Dynamic: requires-python
26
+
27
+ # SmartPyLogger
28
+
29
+ ```text
30
+ ....................................................................................
31
+ ....................................................................................
32
+ ..........................................-++=..:...................................
33
+ .............-.........................=**#######+:.........-.......................
34
+ .............................-.......:=#***##**##*=.....................-...........
35
+ ......-.............................:+******#**##*#=................................
36
+ .............-...................:=*********####%##*:...............................
37
+ ..............................:+************#*####=..................-..............
38
+ ...-*+=:.................-=****##*****####*######%+:................................
39
+ ...-*#*#**##*********##**#*******#######**#%%#***#%+................................
40
+ ...:=*****#*##*######****#*****#####*#*++--*%##***##=.........-.....................
41
+ ....-******###*##**###**###*#*###****+-...:-*%%#**##%-..................-...........
42
+ ....:=******###*###****#**#**#####**+:......-*%##***%#-.............................
43
+ .....:+*#***##***###******##**###**+:.......:-*%##**#%*-............................
44
+ ......-*#****######***#**#*##*##**+:.........:-*%#*+*#%#:...........................
45
+ ......:-*******#**********#***##**-...........-:=*##***#%*:.........................
46
+ ........:-+#***************##**##**-............:=*##****#%*-.......................
47
+ ............:=*#************+*###*#+.............-=*###**#%@%#-.....................
48
+ .............:-+#*************+*###*-......-......:-+*#%####%%*:....................
49
+ .......-.......:-=*#***************+.................-=*#%%%*###%=..................
50
+ ..................:--##*************-.................:-+*%#****#%*.................
51
+ ............-.......:--+#************#..................-=*#%#**#%%%-...............
52
+ ........................::*********--+:...................:-=*###***#%*.............
53
+ .../PPPP/PPPPPPPPP..........++#*****--#....................:-=+###*#%%%.............
54
+ ..| PPPPPPPPPPPPPPP..............-'++-#......................:=#%#***%%+............
55
+ ..| PPPP_______/PPPP..-.........................-.............:=#%#***%%+...........
56
+ ..| PPPP......| PPPP..........................................:=#%#***%%+...........
57
+ ..| PPPPPPPPPPPPPPP./YYYY..../YYYY........-...................:=#%#***%%+...........
58
+ ..| PPPP/PPPPPPPP..| YYYY...| YYYY............................:=*%##**#%#-..........
59
+ ..| PPPP_______/...| YYYY...| YYYY.............................=*%%##*#%%=..........
60
+ ..| PPPP............\ YYYYYYYYYYYY.....ooo....................=+%%%#**%%+...........
61
+ ..| PPPP.............\ YYYYY_/YYYY.../OOOOO....-.............:=+###**#%#:...........
62
+ ../____/..............\___/.| YYYY...| OOO...................=+#%#**#%#:............
63
+ ...................../YYYY..| YYYY....\__/.................:=+***++++**-............
64
+ .............-......| YYYYY/ YYYYY...-..............................................
65
+ .....................\ YYYYYYYYYY...................................................
66
+ .......-..............\________/....................................................
67
+ ....................................................................................
68
+ ....................................................................................
69
+ ```
70
+
71
+ Thank you so much for downloading and using SmartPyLogger!
72
+ Developed by Niklavs Visockis, Ludvig Bergström and Jonas Lorenz -
73
+ in June of 2025 at the Couchbase x AWS x Cillers Hackathon.
74
+ Special thanks goes out to the Couchbase team and AWS for sponsoring this project.
75
+
76
+ ### FastAPI middleware for comprehensive request/response logging.
77
+
78
+ ## Installation
79
+
80
+ ```bash
81
+ pip install -e .
82
+ ```
83
+
84
+ ## Usage
85
+
86
+ ```python
87
+ from fastapi import FastAPI
88
+ from smartpylogger import LoggingMiddleware
89
+
90
+ app = FastAPI()
91
+
92
+ # Add your middleware
93
+ app.add_middleware(
94
+ LoggingMiddleware,
95
+ api_key="YOUR_API_KEY",
96
+ allowed_origins=["IP", ...]
97
+ )
98
+ ```
99
+
100
+ ## What it logs:
101
+
102
+ - **Request details**: Nothing yet
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ pyproject.toml
3
+ setup.py
4
+ smartpylogger/README.md
5
+ smartpylogger/__init__.py
6
+ smartpylogger/logger.py
7
+ smartpylogger/utils.py
8
+ smartpylogger.egg-info/PKG-INFO
9
+ smartpylogger.egg-info/SOURCES.txt
10
+ smartpylogger.egg-info/dependency_links.txt
11
+ smartpylogger.egg-info/entry_points.txt
12
+ smartpylogger.egg-info/requires.txt
13
+ smartpylogger.egg-info/top_level.txt
14
+ tests/test_catch.py
15
+ tests/test_send.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ couchbase-middleware = couchbase_middleware.cli:main
@@ -0,0 +1,11 @@
1
+ colorama
2
+ httpx
3
+ fastapi
4
+ starlette
5
+
6
+ [dev]
7
+ pytest>=6.0
8
+ pytest-cov>=2.0
9
+ black>=21.0
10
+ flake8>=3.8
11
+ mypy>=0.800
@@ -0,0 +1 @@
1
+ smartpylogger
@@ -0,0 +1,33 @@
1
+ from smartpylogger import LoggingMiddleware
2
+ from fastapi import FastAPI, Request
3
+ import requests
4
+ import os
5
+ import dotenv
6
+
7
+ dotenv.load_dotenv()
8
+
9
+ app = FastAPI()
10
+ print(os.getenv("API_KEY"))
11
+
12
+ # Get the absolute path to the banned words file
13
+ current_dir = os.path.dirname(os.path.abspath(__file__))
14
+ banned_words_path = os.path.join(current_dir, "my_banned_words.txt")
15
+
16
+ app.add_middleware(
17
+ LoggingMiddleware,
18
+ api_key=os.getenv("API_KEY"), # This is where the middleware would forward, but the app itself runs on 8500
19
+ allowed_origins=["127.0.0.1"],
20
+ api_limit_daily=1000,
21
+ banned_words_path=banned_words_path
22
+ )
23
+
24
+ API_URL = "http://localhost:8500"
25
+
26
+ @app.post("/mock")
27
+ async def mock_post(request: Request):
28
+ data = await request.json()
29
+ return {"received": data}
30
+
31
+ if __name__ == "__main__":
32
+ import uvicorn
33
+ uvicorn.run(app, host="0.0.0.0", port=8500)
@@ -0,0 +1,12 @@
1
+ import requests
2
+
3
+ API_URL = "http://localhost:8500/mock"
4
+
5
+ def test_post():
6
+ payload = {"foo": "JS", "number": 123}
7
+ response = requests.post(API_URL, json=payload)
8
+ print("Status code:", response.status_code)
9
+ print("Response:", response.text)
10
+
11
+ if __name__ == "__main__":
12
+ test_post()