smartpylogger 0.1.1__tar.gz → 0.1.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smartpylogger
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Lightweight structured logger for Py projects with AI analysis!
5
5
  Author-email: Your Name <your@email.com>
6
6
  License: MIT
@@ -77,7 +77,7 @@ Special thanks goes out to the Couchbase team and AWS for sponsoring this projec
77
77
  ## Installation
78
78
 
79
79
  ```bash
80
- pip install -e .
80
+ pip install smartpylogger .
81
81
  ```
82
82
 
83
83
  ## Usage
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "smartpylogger"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  description = "Lightweight structured logger for Py projects with AI analysis!"
9
9
  readme = "smartpylogger/README.md"
10
10
  requires-python = ">=3.7"
@@ -4,7 +4,7 @@ with open("smartpylogger/README.md", "r", encoding="utf-8") as f:
4
4
  long_description = f.read()
5
5
  setup(
6
6
  name="smartpylogger",
7
- version="0.1.1",
7
+ version="0.1.2",
8
8
  description="Lightweight structured logger for Py projects with AI analysis!",
9
9
  packages=find_packages(),
10
10
  # install_requires=[], # or just remove this line entirely
@@ -52,7 +52,7 @@ Special thanks goes out to the Couchbase team and AWS for sponsoring this projec
52
52
  ## Installation
53
53
 
54
54
  ```bash
55
- pip install -e .
55
+ pip install smartpylogger .
56
56
  ```
57
57
 
58
58
  ## Usage
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smartpylogger
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Lightweight structured logger for Py projects with AI analysis!
5
5
  Author-email: Your Name <your@email.com>
6
6
  License: MIT
@@ -77,7 +77,7 @@ Special thanks goes out to the Couchbase team and AWS for sponsoring this projec
77
77
  ## Installation
78
78
 
79
79
  ```bash
80
- pip install -e .
80
+ pip install smartpylogger .
81
81
  ```
82
82
 
83
83
  ## Usage
@@ -2,9 +2,6 @@ LICENSE
2
2
  pyproject.toml
3
3
  setup.py
4
4
  smartpylogger/README.md
5
- smartpylogger/__init__.py
6
- smartpylogger/logger.py
7
- smartpylogger/utils.py
8
5
  smartpylogger.egg-info/PKG-INFO
9
6
  smartpylogger.egg-info/SOURCES.txt
10
7
  smartpylogger.egg-info/dependency_links.txt
@@ -1,11 +0,0 @@
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"]
@@ -1,283 +0,0 @@
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://51.12.61.210: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
@@ -1,28 +0,0 @@
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
-
File without changes
File without changes