vnai 2.0.3__tar.gz → 2.0.4__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.
- {vnai-2.0.3 → vnai-2.0.4}/PKG-INFO +4 -5
- vnai-2.0.4/README.md +21 -0
- {vnai-2.0.3 → vnai-2.0.4}/setup.py +5 -6
- {vnai-2.0.3 → vnai-2.0.4}/vnai/__init__.py +55 -81
- vnai-2.0.4/vnai/beam/__init__.py +6 -0
- {vnai-2.0.3 → vnai-2.0.4}/vnai/beam/metrics.py +32 -57
- {vnai-2.0.3 → vnai-2.0.4}/vnai/beam/pulse.py +21 -36
- {vnai-2.0.3 → vnai-2.0.4}/vnai/beam/quota.py +109 -137
- {vnai-2.0.3 → vnai-2.0.4}/vnai/flow/__init__.py +2 -4
- {vnai-2.0.3 → vnai-2.0.4}/vnai/flow/queue.py +20 -31
- {vnai-2.0.3 → vnai-2.0.4}/vnai/flow/relay.py +64 -101
- {vnai-2.0.3 → vnai-2.0.4}/vnai/scope/__init__.py +2 -4
- {vnai-2.0.3 → vnai-2.0.4}/vnai/scope/profile.py +110 -206
- {vnai-2.0.3 → vnai-2.0.4}/vnai/scope/promo.py +80 -28
- {vnai-2.0.3 → vnai-2.0.4}/vnai/scope/state.py +38 -64
- {vnai-2.0.3 → vnai-2.0.4}/vnai.egg-info/PKG-INFO +4 -5
- {vnai-2.0.3 → vnai-2.0.4}/vnai.egg-info/requires.txt +0 -1
- vnai-2.0.3/README.md +0 -17
- vnai-2.0.3/vnai/beam/__init__.py +0 -3
- {vnai-2.0.3 → vnai-2.0.4}/setup.cfg +0 -0
- {vnai-2.0.3 → vnai-2.0.4}/vnai.egg-info/SOURCES.txt +0 -0
- {vnai-2.0.3 → vnai-2.0.4}/vnai.egg-info/dependency_links.txt +0 -0
- {vnai-2.0.3 → vnai-2.0.4}/vnai.egg-info/top_level.txt +0 -0
@@ -1,10 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: vnai
|
3
|
-
Version: 2.0.
|
3
|
+
Version: 2.0.4
|
4
4
|
Summary: System optimization and resource management toolkit
|
5
|
-
Home-page: https://github.com/
|
6
|
-
Author:
|
7
|
-
Author-email:
|
5
|
+
Home-page: https://github.com/vnstock-hq/initialization/new/main
|
6
|
+
Author: Vnstock HQ
|
7
|
+
Author-email: support@vnstocks.com
|
8
8
|
License: MIT
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
10
10
|
Classifier: Operating System :: OS Independent
|
@@ -17,7 +17,6 @@ Requires-Dist: requests>=2.25.0
|
|
17
17
|
Requires-Dist: psutil>=5.8.0
|
18
18
|
Provides-Extra: dev
|
19
19
|
Requires-Dist: pytest>=6.0.0; extra == "dev"
|
20
|
-
Requires-Dist: black>=21.5b2; extra == "dev"
|
21
20
|
Dynamic: author
|
22
21
|
Dynamic: author-email
|
23
22
|
Dynamic: classifier
|
vnai-2.0.4/README.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# VNAI
|
2
|
+
|
3
|
+
System resource management and performance optimization toolkit.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```bash
|
8
|
+
pip install vnai
|
9
|
+
```
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
```python
|
14
|
+
from vnai import beam, flow, scope
|
15
|
+
|
16
|
+
# Your code here
|
17
|
+
```
|
18
|
+
|
19
|
+
## License
|
20
|
+
|
21
|
+
MIT License
|
@@ -7,13 +7,13 @@ long_description = (
|
|
7
7
|
|
8
8
|
setup(
|
9
9
|
name="vnai",
|
10
|
-
version='2.0.
|
10
|
+
version='2.0.4',
|
11
11
|
description="System optimization and resource management toolkit",
|
12
12
|
long_description=long_description,
|
13
13
|
long_description_content_type="text/markdown",
|
14
|
-
author="
|
15
|
-
author_email="
|
16
|
-
url="https://github.com/
|
14
|
+
author="Vnstock HQ",
|
15
|
+
author_email="support@vnstocks.com",
|
16
|
+
url="https://github.com/vnstock-hq/initialization/new/main",
|
17
17
|
packages=find_packages(),
|
18
18
|
classifiers=[
|
19
19
|
"Programming Language :: Python :: 3",
|
@@ -30,8 +30,7 @@ setup(
|
|
30
30
|
extras_require={
|
31
31
|
"dev": [
|
32
32
|
"pytest>=6.0.0",
|
33
|
-
"black>=21.5b2",
|
34
33
|
],
|
35
34
|
},
|
36
35
|
license="MIT",
|
37
|
-
)
|
36
|
+
)
|
@@ -1,7 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
##
|
4
|
-
|
1
|
+
# vnai/__init__.py
|
2
|
+
# Main entry point for vnai package
|
5
3
|
|
6
4
|
import os
|
7
5
|
import pathlib
|
@@ -11,8 +9,7 @@ import threading
|
|
11
9
|
import functools
|
12
10
|
from datetime import datetime
|
13
11
|
|
14
|
-
|
15
|
-
|
12
|
+
# Import core functionality
|
16
13
|
from vnai.beam.quota import guardian, optimize
|
17
14
|
from vnai.beam.metrics import collector, capture
|
18
15
|
from vnai.beam.pulse import monitor
|
@@ -22,8 +19,7 @@ from vnai.scope.profile import inspector
|
|
22
19
|
from vnai.scope.state import tracker, record
|
23
20
|
from vnai.scope.promo import present
|
24
21
|
|
25
|
-
|
26
|
-
|
22
|
+
# Constants for terms and conditions
|
27
23
|
TC_VAR = "ACCEPT_TC"
|
28
24
|
TC_VAL = "tôi đồng ý"
|
29
25
|
TC_PATH = pathlib.Path.home() / ".vnstock" / "id" / "terms_agreement.txt"
|
@@ -37,10 +33,10 @@ Chi tiết:
|
|
37
33
|
"""
|
38
34
|
|
39
35
|
class Core:
|
40
|
-
|
36
|
+
"""Core functionality for system optimization"""
|
41
37
|
|
42
38
|
def __init__(self):
|
43
|
-
|
39
|
+
"""Initialize core"""
|
44
40
|
self.initialized = False
|
45
41
|
self.webhook_url = None
|
46
42
|
self.init_time = datetime.now().isoformat()
|
@@ -50,50 +46,41 @@ class Core:
|
|
50
46
|
self.terms_file_path = TC_PATH
|
51
47
|
self.system_info = None
|
52
48
|
|
53
|
-
|
54
|
-
|
49
|
+
# Create necessary directories
|
55
50
|
self.project_dir.mkdir(exist_ok=True)
|
56
51
|
self.id_dir.mkdir(exist_ok=True)
|
57
52
|
|
58
|
-
|
59
|
-
|
53
|
+
# Auto-initialize
|
60
54
|
self.initialize()
|
61
55
|
|
62
56
|
def initialize(self, webhook_url=None):
|
63
|
-
|
57
|
+
"""Initialize the system"""
|
64
58
|
if self.initialized:
|
65
59
|
return True
|
66
60
|
|
67
|
-
|
68
|
-
|
61
|
+
# Check terms acceptance
|
69
62
|
if not self._check_terms():
|
70
63
|
self._accept_terms()
|
71
64
|
|
72
|
-
|
73
|
-
|
65
|
+
# Set up vnstock environment
|
74
66
|
from vnai.scope.profile import inspector
|
75
67
|
inspector.setup_vnstock_environment()
|
76
68
|
|
77
|
-
|
78
|
-
|
69
|
+
# Display content during initialization
|
79
70
|
present()
|
80
71
|
|
81
|
-
|
82
|
-
|
72
|
+
# Configure webhook if provided
|
83
73
|
if webhook_url:
|
84
74
|
self.webhook_url = webhook_url
|
85
75
|
configure(webhook_url)
|
86
76
|
|
87
|
-
|
88
|
-
|
77
|
+
# Record initialization
|
89
78
|
record("initialization", {"timestamp": datetime.now().isoformat()})
|
90
79
|
|
91
|
-
|
92
|
-
|
80
|
+
# Get system information ONCE and store it in the class
|
93
81
|
self.system_info = inspector.examine()
|
94
82
|
|
95
|
-
|
96
|
-
|
83
|
+
# Queue system data with optimal structure
|
97
84
|
conduit.queue({
|
98
85
|
"type": "system_info",
|
99
86
|
"data": {
|
@@ -106,27 +93,23 @@ class Core:
|
|
106
93
|
return True
|
107
94
|
|
108
95
|
def _check_terms(self):
|
109
|
-
|
96
|
+
"""Check if terms have been accepted"""
|
110
97
|
return os.path.exists(self.terms_file_path)
|
111
98
|
|
112
99
|
def _accept_terms(self):
|
113
|
-
|
114
|
-
|
115
|
-
|
100
|
+
"""Record terms acceptance"""
|
101
|
+
# Get system information
|
116
102
|
system_info = inspector.examine()
|
117
103
|
|
118
|
-
|
119
|
-
|
104
|
+
# Auto-accept terms
|
120
105
|
if TC_VAR in os.environ and os.environ[TC_VAR] == TC_VAL:
|
121
106
|
response = TC_VAL
|
122
107
|
else:
|
123
|
-
|
124
|
-
|
108
|
+
# For non-interactive environments, accept by default
|
125
109
|
response = TC_VAL
|
126
110
|
os.environ[TC_VAR] = TC_VAL
|
127
111
|
|
128
|
-
|
129
|
-
|
112
|
+
# Store the acceptance with hardware info
|
130
113
|
now = datetime.now()
|
131
114
|
signed_agreement = (
|
132
115
|
f"Người dùng có mã nhận dạng {system_info['machine_id']} đã chấp nhận "
|
@@ -137,13 +120,11 @@ class Core:
|
|
137
120
|
f"{TERMS_AND_CONDITIONS}"
|
138
121
|
)
|
139
122
|
|
140
|
-
|
141
|
-
|
123
|
+
# Store the acceptance
|
142
124
|
with open(self.terms_file_path, "w", encoding="utf-8") as f:
|
143
125
|
f.write(signed_agreement)
|
144
126
|
|
145
|
-
|
146
|
-
|
127
|
+
# Create the environment.json file that vnstock expects
|
147
128
|
env_file = self.id_dir / "environment.json"
|
148
129
|
env_data = {
|
149
130
|
"accepted_agreement": True,
|
@@ -157,59 +138,53 @@ class Core:
|
|
157
138
|
return True
|
158
139
|
|
159
140
|
def status(self):
|
160
|
-
|
141
|
+
"""Get system status"""
|
161
142
|
return {
|
162
143
|
"initialized": self.initialized,
|
163
144
|
"health": monitor.report(),
|
164
145
|
"metrics": tracker.get_metrics()
|
165
|
-
|
166
|
-
|
146
|
+
# Environment information available via self.system_info
|
167
147
|
}
|
168
148
|
|
169
149
|
def configure_privacy(self, level="standard"):
|
170
|
-
|
150
|
+
"""Configure privacy settings"""
|
171
151
|
from vnai.scope.state import tracker
|
172
152
|
return tracker.setup_privacy(level)
|
173
153
|
|
174
154
|
|
175
|
-
|
176
|
-
|
155
|
+
# Create singleton instance
|
177
156
|
core = Core()
|
178
157
|
|
179
|
-
|
180
|
-
|
158
|
+
# Backward support
|
181
159
|
def tc_init(webhook_url=None):
|
182
160
|
return core.initialize(webhook_url)
|
183
161
|
|
184
|
-
|
185
|
-
|
162
|
+
# Public API
|
186
163
|
def setup(webhook_url=None):
|
187
|
-
|
164
|
+
"""Setup vnai with optional webhook URL"""
|
188
165
|
return core.initialize(webhook_url)
|
189
166
|
|
190
167
|
def optimize_execution(resource_type="default"):
|
191
|
-
|
168
|
+
"""Decorator for optimizing function execution"""
|
192
169
|
return optimize(resource_type)
|
193
170
|
|
194
171
|
def agg_execution(resource_type="default"):
|
195
|
-
|
172
|
+
"""Decorator for aggregating function execution"""
|
196
173
|
return optimize(resource_type, ad_cooldown=1500, content_trigger_threshold=100000)
|
197
174
|
|
198
175
|
def measure_performance(module_type="function"):
|
199
|
-
|
176
|
+
"""Decorator for measuring function performance"""
|
200
177
|
return capture(module_type)
|
201
178
|
|
202
179
|
def accept_license_terms(terms_text=None):
|
203
|
-
|
180
|
+
"""Accept license terms and conditions"""
|
204
181
|
if terms_text is None:
|
205
182
|
terms_text = TERMS_AND_CONDITIONS
|
206
183
|
|
207
|
-
|
208
|
-
|
184
|
+
# Get system information
|
209
185
|
system_info = inspector.examine()
|
210
186
|
|
211
|
-
|
212
|
-
|
187
|
+
# Record acceptance
|
213
188
|
terms_file = pathlib.Path.home() / ".vnstock" / "id" / "terms_agreement.txt"
|
214
189
|
os.makedirs(os.path.dirname(terms_file), exist_ok=True)
|
215
190
|
|
@@ -221,22 +196,19 @@ def accept_license_terms(terms_text=None):
|
|
221
196
|
return True
|
222
197
|
|
223
198
|
def accept_vnstock_terms():
|
224
|
-
|
225
|
-
|
226
|
-
|
199
|
+
"""Accept vnstock terms and create necessary files"""
|
200
|
+
# Get system information
|
227
201
|
from vnai.scope.profile import inspector
|
228
202
|
system_info = inspector.examine()
|
229
203
|
|
230
|
-
|
231
|
-
|
204
|
+
# Create necessary directories
|
232
205
|
home_dir = pathlib.Path.home()
|
233
206
|
project_dir = home_dir / ".vnstock"
|
234
207
|
project_dir.mkdir(exist_ok=True)
|
235
208
|
id_dir = project_dir / 'id'
|
236
209
|
id_dir.mkdir(exist_ok=True)
|
237
210
|
|
238
|
-
|
239
|
-
|
211
|
+
# Create environment.json file that vnstock looks for
|
240
212
|
env_file = id_dir / "environment.json"
|
241
213
|
env_data = {
|
242
214
|
"accepted_agreement": True,
|
@@ -254,40 +226,43 @@ def accept_vnstock_terms():
|
|
254
226
|
return False
|
255
227
|
|
256
228
|
def setup_for_colab():
|
257
|
-
|
229
|
+
"""Special setup for Google Colab environments"""
|
258
230
|
from vnai.scope.profile import inspector
|
259
231
|
|
260
|
-
|
261
|
-
|
232
|
+
# Immediate authentication for Colab
|
262
233
|
inspector.detect_colab_with_delayed_auth(immediate=True)
|
263
234
|
|
264
|
-
|
265
|
-
|
235
|
+
# Setup vnstock environment
|
266
236
|
inspector.setup_vnstock_environment()
|
267
237
|
|
268
238
|
return "Environment set up for Google Colab"
|
269
239
|
|
270
240
|
def display_content():
|
271
|
-
|
241
|
+
"""Display promotional content appropriate for the current environment"""
|
272
242
|
return present()
|
273
243
|
|
274
244
|
def configure_privacy(level="standard"):
|
275
|
-
|
245
|
+
"""Configure privacy level for analytics data"""
|
276
246
|
from vnai.scope.state import tracker
|
277
247
|
return tracker.setup_privacy(level)
|
278
248
|
|
279
249
|
def check_commercial_usage():
|
280
|
-
|
250
|
+
"""Check if running in commercial environment"""
|
281
251
|
from vnai.scope.profile import inspector
|
282
252
|
return inspector.detect_commercial_usage()
|
283
253
|
|
284
254
|
def authenticate_for_persistence():
|
285
|
-
|
255
|
+
"""Authenticate to Google Drive for persistent settings (Colab only)"""
|
286
256
|
from vnai.scope.profile import inspector
|
287
257
|
return inspector.get_or_create_user_id()
|
288
258
|
|
289
259
|
def configure_webhook(webhook_id='80b8832b694a75c8ddc811ac7882a3de'):
|
290
|
-
|
260
|
+
"""Configure webhook URL for analytics data transmission
|
261
|
+
|
262
|
+
This method should be called once during application initialization
|
263
|
+
to set up the analytics endpoint. For security reasons, the URL should
|
264
|
+
not be hardcoded in user-facing code.
|
265
|
+
"""
|
291
266
|
if not webhook_id:
|
292
267
|
return False
|
293
268
|
|
@@ -295,6 +270,5 @@ def configure_webhook(webhook_id='80b8832b694a75c8ddc811ac7882a3de'):
|
|
295
270
|
webhook_url = f'https://botbuilder.larksuite.com/api/trigger-webhook/{webhook_id}'
|
296
271
|
return configure(webhook_url)
|
297
272
|
|
298
|
-
|
299
|
-
|
273
|
+
# Set the webhook
|
300
274
|
configure_webhook()
|
@@ -1,7 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
##
|
4
|
-
|
1
|
+
# vnai/beam/metrics.py
|
2
|
+
# System performance metrics collection (formerly analytics)
|
5
3
|
|
6
4
|
import sys
|
7
5
|
import time
|
@@ -9,7 +7,7 @@ import threading
|
|
9
7
|
from datetime import datetime
|
10
8
|
|
11
9
|
class Collector:
|
12
|
-
|
10
|
+
"""Collects operation metrics for system optimization"""
|
13
11
|
|
14
12
|
_instance = None
|
15
13
|
_lock = threading.Lock()
|
@@ -22,7 +20,7 @@ class Collector:
|
|
22
20
|
return cls._instance
|
23
21
|
|
24
22
|
def _initialize(self):
|
25
|
-
|
23
|
+
"""Initialize collector"""
|
26
24
|
self.metrics = {
|
27
25
|
"function": [],
|
28
26
|
"rate_limit": [],
|
@@ -38,93 +36,76 @@ class Collector:
|
|
38
36
|
self.colab_auth_triggered = False
|
39
37
|
|
40
38
|
def record(self, metric_type, data, priority=None):
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
"""Record operation metrics"""
|
40
|
+
# Ensure data is a dictionary
|
44
41
|
if not isinstance(data, dict):
|
45
42
|
data = {"value": str(data)}
|
46
43
|
|
47
|
-
|
48
|
-
|
44
|
+
# Add timestamp if not present
|
49
45
|
if "timestamp" not in data:
|
50
46
|
data["timestamp"] = datetime.now().isoformat()
|
51
47
|
|
52
|
-
|
53
|
-
|
54
|
-
##
|
55
|
-
|
48
|
+
# For system_info type, keep full data
|
49
|
+
# For other types, only include machine_id reference
|
56
50
|
if metric_type != "system_info" and isinstance(data, dict):
|
57
|
-
|
58
|
-
|
51
|
+
# Remove any system info and just reference machine_id
|
59
52
|
if "system" in data:
|
60
53
|
del data["system"]
|
61
54
|
|
62
|
-
|
63
|
-
|
55
|
+
# Get machine_id for reference
|
64
56
|
from vnai.scope.profile import inspector
|
65
57
|
data["machine_id"] = inspector.fingerprint()
|
66
58
|
|
67
|
-
|
68
|
-
|
59
|
+
# Add to appropriate metrics collection
|
69
60
|
if metric_type in self.metrics:
|
70
61
|
self.metrics[metric_type].append(data)
|
71
62
|
else:
|
72
63
|
self.metrics["function"].append(data)
|
73
64
|
|
74
|
-
|
75
|
-
|
65
|
+
# Keep track of function call count for Colab auth trigger
|
76
66
|
if metric_type == "function":
|
77
67
|
self.function_count += 1
|
78
68
|
|
79
|
-
|
80
|
-
|
69
|
+
# Check if we should trigger Colab authentication
|
81
70
|
if self.function_count > 10 and not self.colab_auth_triggered and 'google.colab' in sys.modules:
|
82
71
|
self.colab_auth_triggered = True
|
83
|
-
|
84
|
-
|
72
|
+
# Trigger in a separate thread to avoid blocking
|
85
73
|
threading.Thread(
|
86
74
|
target=self._trigger_colab_auth,
|
87
75
|
daemon=True
|
88
76
|
).start()
|
89
77
|
|
90
|
-
|
91
|
-
|
78
|
+
# Check buffer size and send if threshold reached
|
92
79
|
if sum(len(metric_list) for metric_list in self.metrics.values()) >= self.thresholds["buffer_size"]:
|
93
80
|
self._send_metrics()
|
94
81
|
|
95
|
-
|
96
|
-
|
82
|
+
# Send immediately for high priority metrics
|
97
83
|
if priority == "high" or (metric_type == "error"):
|
98
84
|
self._send_metrics()
|
99
85
|
|
100
86
|
def _trigger_colab_auth(self):
|
101
|
-
|
87
|
+
"""Trigger Google Colab authentication in a background thread"""
|
102
88
|
try:
|
103
89
|
from vnai.scope.profile import inspector
|
104
90
|
inspector.get_or_create_user_id()
|
105
91
|
except:
|
106
|
-
pass
|
107
|
-
|
92
|
+
pass # Silently fail if there's an issue
|
108
93
|
|
109
94
|
def _send_metrics(self):
|
110
|
-
|
111
|
-
|
112
|
-
|
95
|
+
"""Send collected metrics to data relay"""
|
96
|
+
# Import here to avoid circular imports
|
113
97
|
from vnai.flow.relay import track_function_call, track_rate_limit, track_api_request
|
114
98
|
|
115
|
-
|
116
|
-
|
99
|
+
# Process and send each type of metric using the appropriate tracking function
|
117
100
|
for metric_type, data_list in self.metrics.items():
|
118
101
|
if not data_list:
|
119
102
|
continue
|
120
103
|
|
121
|
-
|
122
|
-
|
104
|
+
# Process each metric by type
|
123
105
|
for data in data_list:
|
124
106
|
try:
|
125
107
|
if metric_type == "function":
|
126
|
-
|
127
|
-
|
108
|
+
# Use the track_function_call interface
|
128
109
|
track_function_call(
|
129
110
|
function_name=data.get("function", "unknown"),
|
130
111
|
source=data.get("source", "vnai"),
|
@@ -134,8 +115,7 @@ class Collector:
|
|
134
115
|
args=data.get("args")
|
135
116
|
)
|
136
117
|
elif metric_type == "rate_limit":
|
137
|
-
|
138
|
-
|
118
|
+
# Use the track_rate_limit interface
|
139
119
|
track_rate_limit(
|
140
120
|
source=data.get("source", "vnai"),
|
141
121
|
limit_type=data.get("limit_type", "unknown"),
|
@@ -144,8 +124,7 @@ class Collector:
|
|
144
124
|
is_exceeded=data.get("is_exceeded", False)
|
145
125
|
)
|
146
126
|
elif metric_type == "request":
|
147
|
-
|
148
|
-
|
127
|
+
# Use the track_api_request interface
|
149
128
|
track_api_request(
|
150
129
|
endpoint=data.get("endpoint", "unknown"),
|
151
130
|
source=data.get("source", "vnai"),
|
@@ -156,27 +135,24 @@ class Collector:
|
|
156
135
|
response_size=data.get("response_size", 0)
|
157
136
|
)
|
158
137
|
except Exception as e:
|
159
|
-
|
160
|
-
|
138
|
+
# If tracking fails, just continue with the next item
|
161
139
|
continue
|
162
140
|
|
163
|
-
|
164
|
-
|
141
|
+
# Clear the processed metrics
|
165
142
|
self.metrics[metric_type] = []
|
166
143
|
|
167
144
|
def get_metrics_summary(self):
|
168
|
-
|
145
|
+
"""Get summary of collected metrics"""
|
169
146
|
return {
|
170
147
|
metric_type: len(data_list)
|
171
148
|
for metric_type, data_list in self.metrics.items()
|
172
149
|
}
|
173
150
|
|
174
|
-
|
175
|
-
|
151
|
+
# Create singleton instance
|
176
152
|
collector = Collector()
|
177
153
|
|
178
154
|
def capture(module_type="function"):
|
179
|
-
|
155
|
+
"""Decorator to capture metrics for any function"""
|
180
156
|
def decorator(func):
|
181
157
|
def wrapper(*args, **kwargs):
|
182
158
|
start_time = time.time()
|
@@ -201,8 +177,7 @@ def capture(module_type="function"):
|
|
201
177
|
"success": success,
|
202
178
|
"error": error,
|
203
179
|
"timestamp": datetime.now().isoformat(),
|
204
|
-
"args": str(args)[:100] if args else None
|
205
|
-
|
180
|
+
"args": str(args)[:100] if args else None # Truncate for privacy
|
206
181
|
}
|
207
182
|
)
|
208
183
|
return wrapper
|