profilis 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.
- profilis-0.1.0/LICENSE +21 -0
- profilis-0.1.0/PKG-INFO +406 -0
- profilis-0.1.0/README.md +337 -0
- profilis-0.1.0/pyproject.toml +93 -0
- profilis-0.1.0/setup.cfg +4 -0
- profilis-0.1.0/src/profilis/__init__.py +2 -0
- profilis-0.1.0/src/profilis/core/async_collector.py +153 -0
- profilis-0.1.0/src/profilis/core/emitter.py +43 -0
- profilis-0.1.0/src/profilis/core/stats.py +66 -0
- profilis-0.1.0/src/profilis/decorators/profile.py +121 -0
- profilis-0.1.0/src/profilis/exporters/console.py +45 -0
- profilis-0.1.0/src/profilis/exporters/jsonl.py +146 -0
- profilis-0.1.0/src/profilis/flask/adapter.py +193 -0
- profilis-0.1.0/src/profilis/flask/ui.py +378 -0
- profilis-0.1.0/src/profilis/py.typed +1 -0
- profilis-0.1.0/src/profilis/runtime/__init__.py +34 -0
- profilis-0.1.0/src/profilis/runtime/clock.py +21 -0
- profilis-0.1.0/src/profilis/runtime/context.py +77 -0
- profilis-0.1.0/src/profilis/runtime/ids.py +34 -0
- profilis-0.1.0/src/profilis/sqlalchemy/instrumentation.py +97 -0
- profilis-0.1.0/src/profilis.egg-info/PKG-INFO +406 -0
- profilis-0.1.0/src/profilis.egg-info/SOURCES.txt +34 -0
- profilis-0.1.0/src/profilis.egg-info/dependency_links.txt +1 -0
- profilis-0.1.0/src/profilis.egg-info/requires.txt +52 -0
- profilis-0.1.0/src/profilis.egg-info/top_level.txt +1 -0
- profilis-0.1.0/tests/test_async_collector.py +70 -0
- profilis-0.1.0/tests/test_emitter_and_stats.py +44 -0
- profilis-0.1.0/tests/test_exporters.py +65 -0
- profilis-0.1.0/tests/test_flask_adapter.py +107 -0
- profilis-0.1.0/tests/test_flask_ui.py +68 -0
- profilis-0.1.0/tests/test_import.py +6 -0
- profilis-0.1.0/tests/test_profile_decorator.py +78 -0
- profilis-0.1.0/tests/test_runtime_clock.py +9 -0
- profilis-0.1.0/tests/test_runtime_context.py +59 -0
- profilis-0.1.0/tests/test_runtime_ids.py +19 -0
- profilis-0.1.0/tests/test_sqlalchemy_instrumentation.py +93 -0
profilis-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ankan Dutta
|
|
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.
|
profilis-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: profilis
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: High performance, non blocking profiler for Python web apps.
|
|
5
|
+
Author: Ankan Dutta
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ankan97dutta/profilis
|
|
8
|
+
Project-URL: Documentation, https://ankan97dutta.github.io/profilis/
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/ankan97dutta/profilis/issues
|
|
10
|
+
Keywords: profiler,python,flask,fastapi,sanic,sql,sqlalchemy,pyodbc,mongo,neo4j,asyncio,monitoring,performance
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Classifier: Topic :: Software Development :: Testing
|
|
15
|
+
Classifier: Topic :: System :: Monitoring
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: typing_extensions>=4.0
|
|
27
|
+
Provides-Extra: flask
|
|
28
|
+
Requires-Dist: flask[async]>=3.0; extra == "flask"
|
|
29
|
+
Provides-Extra: fastapi
|
|
30
|
+
Requires-Dist: fastapi>=0.110; extra == "fastapi"
|
|
31
|
+
Requires-Dist: starlette>=0.37; extra == "fastapi"
|
|
32
|
+
Provides-Extra: sanic
|
|
33
|
+
Requires-Dist: sanic>=23.0; extra == "sanic"
|
|
34
|
+
Provides-Extra: sqlalchemy
|
|
35
|
+
Requires-Dist: sqlalchemy>=2.0; extra == "sqlalchemy"
|
|
36
|
+
Requires-Dist: aiosqlite; extra == "sqlalchemy"
|
|
37
|
+
Requires-Dist: greenlet; extra == "sqlalchemy"
|
|
38
|
+
Provides-Extra: pyodbc
|
|
39
|
+
Requires-Dist: pyodbc; extra == "pyodbc"
|
|
40
|
+
Provides-Extra: mongo
|
|
41
|
+
Requires-Dist: pymongo>=4.3; extra == "mongo"
|
|
42
|
+
Requires-Dist: motor>=3.3; extra == "mongo"
|
|
43
|
+
Provides-Extra: neo4j
|
|
44
|
+
Requires-Dist: neo4j>=5.14; extra == "neo4j"
|
|
45
|
+
Provides-Extra: perf
|
|
46
|
+
Requires-Dist: orjson>=3.8; extra == "perf"
|
|
47
|
+
Provides-Extra: all
|
|
48
|
+
Requires-Dist: flask[async]>=3.0; extra == "all"
|
|
49
|
+
Requires-Dist: fastapi>=0.110; extra == "all"
|
|
50
|
+
Requires-Dist: starlette>=0.37; extra == "all"
|
|
51
|
+
Requires-Dist: sanic>=23.0; extra == "all"
|
|
52
|
+
Requires-Dist: sqlalchemy>=2.0; extra == "all"
|
|
53
|
+
Requires-Dist: aiosqlite; extra == "all"
|
|
54
|
+
Requires-Dist: greenlet; extra == "all"
|
|
55
|
+
Requires-Dist: pyodbc; extra == "all"
|
|
56
|
+
Requires-Dist: pymongo>=4.3; extra == "all"
|
|
57
|
+
Requires-Dist: motor>=3.3; extra == "all"
|
|
58
|
+
Requires-Dist: neo4j>=5.14; extra == "all"
|
|
59
|
+
Requires-Dist: orjson>=3.8; extra == "all"
|
|
60
|
+
Provides-Extra: dev
|
|
61
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
62
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
63
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
64
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
65
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
66
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
67
|
+
Requires-Dist: pre-commit>=3.0; extra == "dev"
|
|
68
|
+
Dynamic: license-file
|
|
69
|
+
|
|
70
|
+
<img width="64" height="64" alt="image" src="https://github.com/user-attachments/assets/663b4497-d023-49a6-9ce9-60c50c86df02" />
|
|
71
|
+
|
|
72
|
+
# Profilis
|
|
73
|
+
|
|
74
|
+
> A high performance, non-blocking profiler for Python web applications.
|
|
75
|
+
|
|
76
|
+
[](https://ankan97dutta.github.io/profilis/)
|
|
77
|
+
[](https://github.com/ankan97dutta/profilis/actions/workflows/ci.yml)
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Overview
|
|
81
|
+
|
|
82
|
+
Profilis provides drop-in observability across APIs, functions, and database queries with minimal performance impact. It's designed to be:
|
|
83
|
+
|
|
84
|
+
- **Non blocking**: Async collection with configurable batching and backpressure handling
|
|
85
|
+
- **Framework agnostic**: Works with Flask and custom applications (FastAPI/Sanic planned)
|
|
86
|
+
- **Database aware**: Built-in support for SQLAlchemy (pyodbc/MongoDB/Neo4j planned)
|
|
87
|
+
- **Production ready**: Configurable sampling, error tracking, and multiple export formats
|
|
88
|
+
|
|
89
|
+
<img width="1126" height="642" alt="Screenshot 2025-09-01 at 12 38 50 PM" src="https://github.com/user-attachments/assets/7c9d541b-4984-4575-92fb-8c0ec48dff55" />
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
## Features
|
|
93
|
+
|
|
94
|
+
- **Request Profiling**: Automatic HTTP request/response timing and status tracking
|
|
95
|
+
- **Function Profiling**: Decorator-based function timing with exception tracking
|
|
96
|
+
- **Database Instrumentation**: SQLAlchemy query performance monitoring with row counts
|
|
97
|
+
- **Built-in UI**: Real-time dashboard for monitoring and debugging
|
|
98
|
+
- **Multiple Exporters**: JSONL (with rotation), Console
|
|
99
|
+
- **Runtime Context**: Distributed tracing with trace/span ID management
|
|
100
|
+
- **Configurable Sampling**: Control data collection volume in production
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
## Installation
|
|
104
|
+
|
|
105
|
+
Install the core package with optional dependencies for your specific needs:
|
|
106
|
+
|
|
107
|
+
### Option 1: Using pip with extras (Recommended)
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Core package only
|
|
111
|
+
pip install profilis
|
|
112
|
+
|
|
113
|
+
# With Flask support
|
|
114
|
+
pip install profilis[flask]
|
|
115
|
+
|
|
116
|
+
# With database support
|
|
117
|
+
pip install profilis[flask,sqlalchemy]
|
|
118
|
+
|
|
119
|
+
# With all integrations
|
|
120
|
+
pip install profilis[all]
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Option 2: Using requirements files
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Minimal setup (core only)
|
|
127
|
+
pip install -r requirements-minimal.txt
|
|
128
|
+
|
|
129
|
+
# Flask integration
|
|
130
|
+
pip install -r requirements-flask.txt
|
|
131
|
+
|
|
132
|
+
# SQLAlchemy integration
|
|
133
|
+
pip install -r requirements-sqlalchemy.txt
|
|
134
|
+
|
|
135
|
+
# All integrations
|
|
136
|
+
pip install -r requirements-all.txt
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Option 3: Manual installation
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Core dependencies
|
|
143
|
+
pip install typing_extensions>=4.0
|
|
144
|
+
|
|
145
|
+
# Flask support
|
|
146
|
+
pip install flask[async]>=3.0
|
|
147
|
+
|
|
148
|
+
# SQLAlchemy support
|
|
149
|
+
pip install sqlalchemy>=2.0 aiosqlite greenlet
|
|
150
|
+
|
|
151
|
+
# Performance optimization
|
|
152
|
+
pip install orjson>=3.8
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Quick Start
|
|
156
|
+
|
|
157
|
+
### Flask Integration
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from flask import Flask
|
|
161
|
+
from profilis.flask.adapter import ProfilisFlask
|
|
162
|
+
from profilis.exporters.jsonl import JSONLExporter
|
|
163
|
+
from profilis.core.async_collector import AsyncCollector
|
|
164
|
+
|
|
165
|
+
# Setup exporter and collector
|
|
166
|
+
exporter = JSONLExporter(dir="./logs", rotate_bytes=1024*1024, rotate_secs=3600)
|
|
167
|
+
collector = AsyncCollector(exporter, queue_size=2048, batch_max=128, flush_interval=0.1)
|
|
168
|
+
|
|
169
|
+
# Create Flask app and integrate Profilis
|
|
170
|
+
app = Flask(__name__)
|
|
171
|
+
profilis = ProfilisFlask(
|
|
172
|
+
app,
|
|
173
|
+
collector=collector,
|
|
174
|
+
exclude_routes=["/health", "/metrics"],
|
|
175
|
+
sample=1.0 # 100% sampling
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
@app.route('/api/users')
|
|
179
|
+
def get_users():
|
|
180
|
+
return {"users": ["alice", "bob"]}
|
|
181
|
+
|
|
182
|
+
# Start the app
|
|
183
|
+
if __name__ == "__main__":
|
|
184
|
+
app.run(debug=True)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Function Profiling
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from profilis.decorators.profile import profile_function
|
|
191
|
+
from profilis.core.emitter import Emitter
|
|
192
|
+
from profilis.exporters.console import ConsoleExporter
|
|
193
|
+
from profilis.core.async_collector import AsyncCollector
|
|
194
|
+
|
|
195
|
+
# Setup profiling
|
|
196
|
+
exporter = ConsoleExporter(pretty=True)
|
|
197
|
+
collector = AsyncCollector(exporter, queue_size=128, flush_interval=0.2)
|
|
198
|
+
emitter = Emitter(collector)
|
|
199
|
+
|
|
200
|
+
@profile_function(emitter)
|
|
201
|
+
def expensive_calculation(n: int) -> int:
|
|
202
|
+
"""This function will be automatically profiled."""
|
|
203
|
+
result = sum(i * i for i in range(n))
|
|
204
|
+
return result
|
|
205
|
+
|
|
206
|
+
@profile_function(emitter)
|
|
207
|
+
async def async_operation(data: list) -> list:
|
|
208
|
+
"""Async functions are also supported."""
|
|
209
|
+
processed = [item * 2 for item in data]
|
|
210
|
+
return processed
|
|
211
|
+
|
|
212
|
+
# Use the profiled functions
|
|
213
|
+
result = expensive_calculation(1000)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Manual Event Emission
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from profilis.core.emitter import Emitter
|
|
220
|
+
from profilis.exporters.jsonl import JSONLExporter
|
|
221
|
+
from profilis.core.async_collector import AsyncCollector
|
|
222
|
+
from profilis.runtime import use_span, span_id
|
|
223
|
+
|
|
224
|
+
# Setup
|
|
225
|
+
exporter = JSONLExporter(dir="./logs")
|
|
226
|
+
collector = AsyncCollector(exporter)
|
|
227
|
+
emitter = Emitter(collector)
|
|
228
|
+
|
|
229
|
+
# Create a trace context
|
|
230
|
+
with use_span(trace_id=span_id()):
|
|
231
|
+
# Emit custom events
|
|
232
|
+
emitter.emit_req("/api/custom", 200, dur_ns=15000000) # 15ms
|
|
233
|
+
emitter.emit_fn("custom_function", dur_ns=5000000) # 5ms
|
|
234
|
+
emitter.emit_db("SELECT * FROM users", dur_ns=8000000, rows=100)
|
|
235
|
+
|
|
236
|
+
# Close collector to flush remaining events
|
|
237
|
+
collector.close()
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Built-in Dashboard
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
from flask import Flask
|
|
244
|
+
from profilis.flask.ui import make_ui_blueprint
|
|
245
|
+
from profilis.core.stats import StatsStore
|
|
246
|
+
|
|
247
|
+
app = Flask(__name__)
|
|
248
|
+
stats = StatsStore() # 15-minute rolling window
|
|
249
|
+
|
|
250
|
+
# Mount the dashboard at /_profilis
|
|
251
|
+
ui_bp = make_ui_blueprint(stats, ui_prefix="/_profilis")
|
|
252
|
+
app.register_blueprint(ui_bp)
|
|
253
|
+
|
|
254
|
+
# Visit http://localhost:5000/_profilis to see the dashboard
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Advanced Usage
|
|
258
|
+
|
|
259
|
+
### Custom Exporters
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
from profilis.core.async_collector import AsyncCollector
|
|
263
|
+
from profilis.exporters.base import BaseExporter
|
|
264
|
+
|
|
265
|
+
class CustomExporter(BaseExporter):
|
|
266
|
+
def export(self, events: list[dict]) -> None:
|
|
267
|
+
for event in events:
|
|
268
|
+
# Custom export logic
|
|
269
|
+
print(f"Custom export: {event}")
|
|
270
|
+
|
|
271
|
+
# Use custom exporter
|
|
272
|
+
exporter = CustomExporter()
|
|
273
|
+
collector = AsyncCollector(exporter)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Runtime Context Management
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
from profilis.runtime import use_span, span_id, get_trace_id, get_span_id
|
|
280
|
+
|
|
281
|
+
# Create distributed trace context
|
|
282
|
+
with use_span(trace_id="trace-123", span_id="span-456"):
|
|
283
|
+
current_trace = get_trace_id() # "trace-123"
|
|
284
|
+
current_span = get_span_id() # "span-456"
|
|
285
|
+
|
|
286
|
+
# Nested spans inherit trace context
|
|
287
|
+
with use_span(span_id="span-789"):
|
|
288
|
+
nested_span = get_span_id() # "span-789"
|
|
289
|
+
parent_trace = get_trace_id() # "trace-123"
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Performance Tuning
|
|
293
|
+
|
|
294
|
+
```python
|
|
295
|
+
from profilis.core.async_collector import AsyncCollector
|
|
296
|
+
|
|
297
|
+
# High-throughput configuration
|
|
298
|
+
collector = AsyncCollector(
|
|
299
|
+
exporter,
|
|
300
|
+
queue_size=8192, # Large queue for high concurrency
|
|
301
|
+
batch_max=256, # Larger batches for efficiency
|
|
302
|
+
flush_interval=0.05, # More frequent flushing
|
|
303
|
+
drop_oldest=True # Drop events under backpressure
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# Low-latency configuration
|
|
307
|
+
collector = AsyncCollector(
|
|
308
|
+
exporter,
|
|
309
|
+
queue_size=512, # Smaller queue for lower latency
|
|
310
|
+
batch_max=32, # Smaller batches for faster processing
|
|
311
|
+
flush_interval=0.01, # Very frequent flushing
|
|
312
|
+
drop_oldest=False # Don't drop events
|
|
313
|
+
)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Configuration
|
|
317
|
+
|
|
318
|
+
### Environment Variables
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
# Note: Environment variable support is planned for future releases
|
|
322
|
+
# Currently, all configuration is done programmatically
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Sampling Strategies
|
|
326
|
+
|
|
327
|
+
```python
|
|
328
|
+
# Random sampling
|
|
329
|
+
profilis = ProfilisFlask(app, collector=collector, sample=0.1) # 10% of requests
|
|
330
|
+
|
|
331
|
+
# Route-based sampling
|
|
332
|
+
profilis = ProfilisFlask(
|
|
333
|
+
app,
|
|
334
|
+
collector=collector,
|
|
335
|
+
exclude_routes=["/health", "/metrics", "/static"],
|
|
336
|
+
sample=1.0
|
|
337
|
+
)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Exporters
|
|
341
|
+
|
|
342
|
+
### JSONL Exporter
|
|
343
|
+
```python
|
|
344
|
+
from profilis.exporters.jsonl import JSONLExporter
|
|
345
|
+
|
|
346
|
+
# With rotation
|
|
347
|
+
exporter = JSONLExporter(
|
|
348
|
+
dir="./logs",
|
|
349
|
+
rotate_bytes=1024*1024, # 1MB per file
|
|
350
|
+
rotate_secs=3600 # Rotate every hour
|
|
351
|
+
)
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Console Exporter
|
|
355
|
+
```python
|
|
356
|
+
from profilis.exporters.console import ConsoleExporter
|
|
357
|
+
|
|
358
|
+
# Pretty-printed output for development
|
|
359
|
+
exporter = ConsoleExporter(pretty=True)
|
|
360
|
+
|
|
361
|
+
# Compact output for production
|
|
362
|
+
exporter = ConsoleExporter(pretty=False)
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## Performance Characteristics
|
|
366
|
+
|
|
367
|
+
- **Event Creation**: ≤15µs per event
|
|
368
|
+
- **Memory Overhead**: ~100 bytes per event
|
|
369
|
+
- **Throughput**: 100K+ events/second on modern hardware
|
|
370
|
+
- **Latency**: Sub-millisecond collection overhead
|
|
371
|
+
|
|
372
|
+
## Documentation
|
|
373
|
+
|
|
374
|
+
Full documentation is available at: [Profilis Docs](https://ankan97dutta.github.io/profilis/)
|
|
375
|
+
|
|
376
|
+
Docs are written in Markdown under [`docs/`](./docs) and built with [MkDocs Material](https://squidfunk.github.io/mkdocs-material/).
|
|
377
|
+
|
|
378
|
+
### Available Documentation
|
|
379
|
+
|
|
380
|
+
- **[Getting Started](https://ankan97dutta.github.io/profilis/guides/getting-started/)** - Quick setup and basic usage
|
|
381
|
+
- **[Configuration](https://ankan97dutta.github.io/profilis/guides/configuration/)** - Tuning and customization
|
|
382
|
+
- **[Flask Integration](https://ankan97dutta.github.io/profilis/adapters/flask/)** - Flask adapter documentation
|
|
383
|
+
- **[SQLAlchemy Support](https://ankan97dutta.github.io/profilis/databases/sqlalchemy/)** - Database instrumentation
|
|
384
|
+
- **[JSONL Exporter](https://ankan97dutta.github.io/profilis/exporters/jsonl/)** - Log file output
|
|
385
|
+
- **[Built-in UI](https://ankan97dutta.github.io/profilis/ui/ui/)** - Dashboard documentation
|
|
386
|
+
- **[Architecture](https://ankan97dutta.github.io/profilis/architecture/architecture/)** - System design
|
|
387
|
+
|
|
388
|
+
To preview locally:
|
|
389
|
+
```bash
|
|
390
|
+
pip install mkdocs mkdocs-material mkdocs-mermaid2-plugin
|
|
391
|
+
mkdocs serve
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Development
|
|
395
|
+
|
|
396
|
+
- See [Contributing](./docs/meta/contributing.md) and [Development Guidelines](./docs/meta/development-guidelines.md).
|
|
397
|
+
- Branch strategy: trunk‑based (`feat/*`, `fix/*`, `perf/*`, `chore/*`).
|
|
398
|
+
- Commits follow [Conventional Commits](https://www.conventionalcommits.org/).
|
|
399
|
+
|
|
400
|
+
## Roadmap
|
|
401
|
+
|
|
402
|
+
See [Profilis – v0 Roadmap Project](https://github.com/ankan97dutta/profilis/projects) and [`docs/overview/roadmap.md`](./docs/overview/roadmap.md).
|
|
403
|
+
|
|
404
|
+
## License
|
|
405
|
+
|
|
406
|
+
[MIT](./LICENSE)
|