pyquerytracker 0.1.0__py3-none-any.whl → 0.1.1__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.
Files changed (40) hide show
  1. examples/async_example.py +63 -0
  2. examples/core/async_usage.py +53 -0
  3. examples/core/basic_usage.py +17 -0
  4. examples/core/error_handling.py +24 -0
  5. examples/core/quick_test.py +39 -0
  6. examples/core/with_arguments.py +27 -0
  7. examples/core/with_config.py +30 -0
  8. examples/exporter/csv_exporter_1.py +36 -0
  9. examples/exporter/json_exporter.py +36 -0
  10. examples/fastapi_app.py +119 -0
  11. examples/test_endpoints.py +73 -0
  12. pyquerytracker/__init__.py +3 -2
  13. pyquerytracker/api.py +72 -0
  14. pyquerytracker/config.py +26 -10
  15. pyquerytracker/core.py +122 -58
  16. pyquerytracker/db/models.py +20 -0
  17. pyquerytracker/db/session.py +8 -0
  18. pyquerytracker/db/writer.py +64 -0
  19. pyquerytracker/exporter/__init__.py +0 -0
  20. pyquerytracker/exporter/base.py +25 -0
  21. pyquerytracker/exporter/csv_exporter.py +52 -0
  22. pyquerytracker/exporter/json_exporter.py +47 -0
  23. pyquerytracker/exporter/manager.py +32 -0
  24. pyquerytracker/main.py +6 -0
  25. pyquerytracker/tracker.py +17 -0
  26. pyquerytracker/utils/logger.py +18 -0
  27. pyquerytracker/websocket.py +33 -0
  28. {pyquerytracker-0.1.0.dist-info → pyquerytracker-0.1.1.dist-info}/METADATA +93 -12
  29. pyquerytracker-0.1.1.dist-info/RECORD +39 -0
  30. {pyquerytracker-0.1.0.dist-info → pyquerytracker-0.1.1.dist-info}/WHEEL +1 -1
  31. {pyquerytracker-0.1.0.dist-info → pyquerytracker-0.1.1.dist-info}/top_level.txt +2 -0
  32. tests/exporter/test_json_exporter.py +182 -0
  33. tests/test_async_core.py +93 -0
  34. tests/test_config.py +40 -0
  35. tests/test_core.py +72 -0
  36. tests/test_dashboard.py +31 -0
  37. tests/test_persist.py +9 -0
  38. tests/test_websocket.py +58 -0
  39. pyquerytracker-0.1.0.dist-info/RECORD +0 -8
  40. {pyquerytracker-0.1.0.dist-info → pyquerytracker-0.1.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,63 @@
1
+ import asyncio
2
+ import os
3
+ import sys
4
+
5
+ from pyquerytracker import TrackQuery
6
+
7
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
8
+
9
+
10
+ # Example 1: Basic async function
11
+ @TrackQuery()
12
+ async def fetch_data():
13
+ await asyncio.sleep(0.2)
14
+ return "fetched data"
15
+
16
+
17
+ # Example 2: Async function with parameters
18
+ @TrackQuery()
19
+ async def compute_sum(a, b):
20
+ await asyncio.sleep(0.1)
21
+ return a + b
22
+
23
+
24
+ # Example 3: Class method async tracking
25
+ class DatabaseService:
26
+ @TrackQuery()
27
+ async def query_users(self):
28
+ await asyncio.sleep(0.3)
29
+ return ["Alice", "Bob", "Charlie"]
30
+
31
+
32
+ # Example 4: Async function that raises an error
33
+ @TrackQuery()
34
+ async def fail_fast():
35
+ await asyncio.sleep(0.05)
36
+ raise RuntimeError("Database failure simulation")
37
+
38
+
39
+ # Example 5: Async function with slow duration to trigger logging thresholds
40
+ @TrackQuery()
41
+ async def slow_operation():
42
+ await asyncio.sleep(0.5)
43
+ return "slow complete"
44
+
45
+
46
+ # Run all examples
47
+ async def main():
48
+ print("Example 1: fetch_data →", await fetch_data())
49
+ print("Example 2: compute_sum(5, 7) →", await compute_sum(5, 7))
50
+
51
+ service = DatabaseService()
52
+ print("Example 3: query_users →", await service.query_users())
53
+
54
+ try:
55
+ await fail_fast()
56
+ except RuntimeError as e:
57
+ print("Example 4: fail_fast → raised:", e)
58
+
59
+ print("Example 5: slow_operation →", await slow_operation())
60
+
61
+
62
+ if __name__ == "__main__":
63
+ asyncio.run(main())
@@ -0,0 +1,53 @@
1
+ import asyncio
2
+ import logging
3
+
4
+ from pyquerytracker import TrackQuery, configure
5
+
6
+ # Configure logging to see the output
7
+ logging.basicConfig(
8
+ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
9
+ )
10
+
11
+ # Set a low threshold to easily see "slow" logs
12
+ configure(slow_log_threshold_ms=150, slow_log_level=logging.WARNING)
13
+
14
+
15
+ @TrackQuery()
16
+ async def fast_async_query():
17
+ """An async function that executes quickly."""
18
+ await asyncio.sleep(0.1)
19
+ return "Fast async query completed"
20
+
21
+
22
+ @TrackQuery()
23
+ async def slow_async_query():
24
+ """An async function that takes longer to execute."""
25
+ await asyncio.sleep(0.2)
26
+ return "Slow async query completed"
27
+
28
+
29
+ @TrackQuery()
30
+ async def failing_async_query():
31
+ """An async function that raises an error."""
32
+ await asyncio.sleep(0.1)
33
+ raise ConnectionError("Could not connect to async database")
34
+
35
+
36
+ async def main():
37
+ print("--- Testing fast async query (should be INFO log) ---")
38
+ result1 = await fast_async_query()
39
+ print(f"Result: {result1}\n")
40
+
41
+ print("--- Testing slow async query (should be WARNING log) ---")
42
+ result2 = await slow_async_query()
43
+ print(f"Result: {result2}\n")
44
+
45
+ print("--- Testing failing async query (should be ERROR log) ---")
46
+ try:
47
+ await failing_async_query()
48
+ except ConnectionError as e:
49
+ print(f"Caught expected error: {e}\n")
50
+
51
+
52
+ if __name__ == "__main__":
53
+ asyncio.run(main())
@@ -0,0 +1,17 @@
1
+ from pyquerytracker import TrackQuery, configure
2
+
3
+ configure(slow_log_threshold_ms=1000, slow_log_level=20)
4
+
5
+
6
+ @TrackQuery()
7
+ def simple_query():
8
+ """A simple function that simulates a database query."""
9
+ import time
10
+
11
+ time.sleep(0.5) # Simulate some work
12
+ return "Query completed successfully"
13
+
14
+
15
+ if __name__ == "__main__":
16
+ result = simple_query()
17
+ print(f"Result: {result}")
@@ -0,0 +1,24 @@
1
+ import logging
2
+
3
+ from pyquerytracker import TrackQuery
4
+
5
+ # Configure logging
6
+ logging.basicConfig(
7
+ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
8
+ )
9
+
10
+
11
+ @TrackQuery()
12
+ def failing_query():
13
+ """A function that simulates a failed database query."""
14
+ import time
15
+
16
+ time.sleep(0.3) # Simulate some work
17
+ raise ValueError("Database connection failed")
18
+
19
+
20
+ if __name__ == "__main__":
21
+ try:
22
+ failing_query()
23
+ except ValueError as e:
24
+ print(f"Caught expected error: {e}")
@@ -0,0 +1,39 @@
1
+ import time
2
+
3
+ from pyquerytracker import TrackQuery
4
+
5
+
6
+ @TrackQuery()
7
+ def fast_query():
8
+ """A function that executes quickly."""
9
+ return "Fast query completed"
10
+
11
+
12
+ @TrackQuery()
13
+ def slow_query():
14
+ """A function that takes some time to execute."""
15
+ time.sleep(0.5) # Simulate some work
16
+ return "Slow query completed"
17
+
18
+
19
+ @TrackQuery()
20
+ def failing_query():
21
+ """A function that raises an error."""
22
+ time.sleep(0.2) # Simulate some work
23
+ raise ValueError("Query failed!")
24
+
25
+
26
+ if __name__ == "__main__":
27
+ print("\nTesting fast query:")
28
+ result1 = fast_query()
29
+ print(f"Result: {result1}")
30
+
31
+ print("\nTesting slow query:")
32
+ result2 = slow_query()
33
+ print(f"Result: {result2}")
34
+
35
+ print("\nTesting failing query:")
36
+ try:
37
+ failing_query()
38
+ except ValueError as e:
39
+ print(f"Caught expected error: {e}")
@@ -0,0 +1,27 @@
1
+ import logging
2
+
3
+ from pyquerytracker import TrackQuery
4
+
5
+ # Configure logging
6
+ logging.basicConfig(
7
+ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
8
+ )
9
+
10
+
11
+ @TrackQuery()
12
+ def complex_query(user_id: int, query_type: str, limit: int = 10):
13
+ """A function that simulates a complex database query with arguments."""
14
+ import time
15
+
16
+ time.sleep(0.2) # Simulate some work
17
+ return f"Retrieved {limit} {query_type} records for user {user_id}"
18
+
19
+
20
+ if __name__ == "__main__":
21
+ # Test with positional arguments
22
+ result1 = complex_query(123, "posts")
23
+ print(f"Result 1: {result1}")
24
+
25
+ # Test with keyword arguments
26
+ result2 = complex_query(user_id=456, query_type="comments", limit=5)
27
+ print(f"Result 2: {result2}")
@@ -0,0 +1,30 @@
1
+ import logging
2
+ import time
3
+
4
+ from pyquerytracker import TrackQuery
5
+ from pyquerytracker.config import configure
6
+
7
+ configure(slow_log_threshold_ms=640, slow_log_level=logging.ERROR)
8
+
9
+
10
+ @TrackQuery()
11
+ def fast_query():
12
+ """A function that executes quickly."""
13
+ return "Fast query completed"
14
+
15
+
16
+ @TrackQuery()
17
+ def slow_query():
18
+ """A function that takes some time to execute."""
19
+ time.sleep(0.3) # Simulate some work
20
+ return "Slow query completed"
21
+
22
+
23
+ if __name__ == "__main__":
24
+ # Test with positional arguments
25
+ result1 = fast_query()
26
+ print(f"Result 1: {result1}")
27
+
28
+ # Test with keyword arguments
29
+ result2 = slow_query()
30
+ print(f"Result 2: {result2}")
@@ -0,0 +1,36 @@
1
+ import os
2
+ import time
3
+
4
+ from pyquerytracker import TrackQuery
5
+ from pyquerytracker.config import ExportType, configure
6
+
7
+ os.makedirs("logs-csv", exist_ok=True)
8
+
9
+ configure(
10
+ slow_log_threshold_ms=50.0,
11
+ slow_log_level=20, # INFO
12
+ export_type=ExportType.CSV,
13
+ export_path="logs-csv/query_logs_2.csv",
14
+ )
15
+
16
+
17
+ @TrackQuery()
18
+ def process_data(x, y):
19
+ time.sleep(8)
20
+ return x + y
21
+
22
+
23
+ @TrackQuery()
24
+ def failing_task():
25
+ time.sleep(0.03) # not slow
26
+ raise RuntimeError("This failed intentionally.")
27
+
28
+
29
+ # Run tasks
30
+ print("Result:", process_data(5, 7))
31
+ print("Result:", process_data(1, 2))
32
+
33
+ try:
34
+ failing_task()
35
+ except Exception:
36
+ pass
@@ -0,0 +1,36 @@
1
+ import os
2
+ import time
3
+
4
+ from pyquerytracker import TrackQuery
5
+ from pyquerytracker.config import ExportType, configure
6
+
7
+ os.makedirs("logs-json", exist_ok=True)
8
+
9
+ configure(
10
+ slow_log_threshold_ms=50.0,
11
+ slow_log_level=20, # INFO
12
+ export_type=ExportType.JSON,
13
+ export_path="logs-json/query_logs.json",
14
+ )
15
+
16
+
17
+ @TrackQuery()
18
+ def process_data(x, y):
19
+ time.sleep(0.08) # triggers slow log
20
+ return x + y
21
+
22
+
23
+ @TrackQuery()
24
+ def failing_task():
25
+ time.sleep(0.03) # not slow
26
+ raise RuntimeError("This failed intentionally.")
27
+
28
+
29
+ # Run tasks
30
+ print("Result:", process_data(5, 7))
31
+ print("Result:", process_data(1, 2))
32
+
33
+ try:
34
+ failing_task()
35
+ except Exception:
36
+ pass
@@ -0,0 +1,119 @@
1
+ import asyncio
2
+ import random
3
+ from fastapi import FastAPI, HTTPException
4
+ from fastapi.responses import JSONResponse
5
+ from fastapi.middleware.cors import CORSMiddleware
6
+ from pyquerytracker import monitor_queries, configure, StatsCollector
7
+
8
+ # Initialize StatsCollector globally
9
+ stats_collector = StatsCollector()
10
+
11
+ # Configure pyquerytracker
12
+ configure(
13
+ default_threshold_ms=500, # Set threshold to 500ms
14
+ json_export_enabled=True,
15
+ json_export_path="query_stats.json"
16
+ )
17
+
18
+ app = FastAPI(title="PyQueryTracker Demo")
19
+
20
+ # Add CORS middleware
21
+ app.add_middleware(
22
+ CORSMiddleware,
23
+ allow_origins=["*"],
24
+ allow_credentials=True,
25
+ allow_methods=["*"],
26
+ allow_headers=["*"],
27
+ )
28
+
29
+ @monitor_queries(threshold_ms=300)
30
+ async def fast_query():
31
+ """A query that should be under threshold"""
32
+ await asyncio.sleep(0.1) # 100ms
33
+ return {"status": "success", "message": "Fast query completed"}
34
+
35
+ @monitor_queries(threshold_ms=300)
36
+ async def slow_query():
37
+ """A query that should exceed threshold"""
38
+ await asyncio.sleep(0.4) # 400ms
39
+ return {"status": "success", "message": "Slow query completed"}
40
+
41
+ @monitor_queries(threshold_ms=300)
42
+ async def error_query():
43
+ """A query that will raise an error"""
44
+ await asyncio.sleep(0.2) # 200ms
45
+ raise HTTPException(status_code=500, detail="Simulated error")
46
+
47
+ @app.get("/fast")
48
+ async def get_fast():
49
+ """Endpoint that executes a fast query"""
50
+ try:
51
+ result = await fast_query()
52
+ return JSONResponse(
53
+ content=result,
54
+ media_type="application/json"
55
+ )
56
+ except Exception as e:
57
+ return JSONResponse(
58
+ status_code=500,
59
+ content={"error": str(e)},
60
+ media_type="application/json"
61
+ )
62
+
63
+ @app.get("/slow")
64
+ async def get_slow():
65
+ """Endpoint that executes a slow query"""
66
+ try:
67
+ result = await slow_query()
68
+ return JSONResponse(
69
+ content=result,
70
+ media_type="application/json"
71
+ )
72
+ except Exception as e:
73
+ return JSONResponse(
74
+ status_code=500,
75
+ content={"error": str(e)},
76
+ media_type="application/json"
77
+ )
78
+
79
+ @app.get("/error")
80
+ async def get_error():
81
+ """Endpoint that executes a query that will error"""
82
+ try:
83
+ await error_query()
84
+ except HTTPException as e:
85
+ return JSONResponse(
86
+ status_code=e.status_code,
87
+ content={"error": e.detail},
88
+ media_type="application/json"
89
+ )
90
+ except Exception as e:
91
+ return JSONResponse(
92
+ status_code=500,
93
+ content={"error": str(e)},
94
+ media_type="application/json"
95
+ )
96
+
97
+ @app.get("/random")
98
+ async def get_random():
99
+ """Endpoint with random response time"""
100
+ try:
101
+ delay = random.uniform(0.1, 0.5)
102
+ await asyncio.sleep(delay)
103
+ return JSONResponse(
104
+ content={
105
+ "status": "success",
106
+ "message": f"Random query completed in {delay:.2f}s"
107
+ },
108
+ media_type="application/json"
109
+ )
110
+ except Exception as e:
111
+ return JSONResponse(
112
+ status_code=500,
113
+ content={"error": str(e)},
114
+ media_type="application/json"
115
+ )
116
+
117
+ if __name__ == "__main__":
118
+ import uvicorn
119
+ uvicorn.run(app, host="0.0.0.0", port=8080)
@@ -0,0 +1,73 @@
1
+ import asyncio
2
+ import aiohttp
3
+ import time
4
+ from pyquerytracker.cli import report
5
+ from pyquerytracker.decorator import monitor_queries
6
+
7
+ async def test_endpoint(session: aiohttp.ClientSession, endpoint: str, expected_status: int = 200) -> None:
8
+ """Test an endpoint and print the result"""
9
+ try:
10
+ async with session.get(f"http://localhost:8000{endpoint}") as response:
11
+ if response.status == expected_status:
12
+ data = await response.json()
13
+ print(f"Success testing {endpoint}: {data}")
14
+ else:
15
+ error_text = await response.text()
16
+ print(f"Error testing {endpoint}: {response.status}, {error_text}")
17
+ except Exception as e:
18
+ print(f"Error testing {endpoint}: {str(e)}")
19
+
20
+ @monitor_queries(name="test_fast")
21
+ async def test_fast(session: aiohttp.ClientSession) -> None:
22
+ """Test the fast endpoint"""
23
+ await test_endpoint(session, "/fast")
24
+
25
+ @monitor_queries(name="test_slow")
26
+ async def test_slow(session: aiohttp.ClientSession) -> None:
27
+ """Test the slow endpoint"""
28
+ await test_endpoint(session, "/slow")
29
+
30
+ @monitor_queries(name="test_error")
31
+ async def test_error(session: aiohttp.ClientSession) -> None:
32
+ """Test the error endpoint"""
33
+ await test_endpoint(session, "/error", expected_status=500)
34
+
35
+ @monitor_queries(name="test_random")
36
+ async def test_random(session: aiohttp.ClientSession) -> None:
37
+ """Test the random endpoint"""
38
+ await test_endpoint(session, "/random")
39
+
40
+ async def main():
41
+ """Main test function"""
42
+ async with aiohttp.ClientSession() as session:
43
+ # Test fast endpoint multiple times
44
+ for _ in range(15):
45
+ await test_fast(session)
46
+
47
+ # Test random endpoint
48
+ for _ in range(10):
49
+ await test_random(session)
50
+
51
+ # Test error endpoint
52
+ for _ in range(15):
53
+ await test_error(session)
54
+
55
+ # Test random endpoint again
56
+ for _ in range(10):
57
+ await test_random(session)
58
+
59
+ # Test slow endpoint
60
+ for _ in range(20):
61
+ await test_slow(session)
62
+
63
+ # Test random endpoint one more time
64
+ for _ in range(10):
65
+ await test_random(session)
66
+
67
+ if __name__ == "__main__":
68
+ # Run tests
69
+ asyncio.run(main())
70
+
71
+ # Generate report
72
+ print("\nGenerating statistics report...")
73
+ report()
@@ -1,4 +1,5 @@
1
- from .core import TrackQuery
2
1
  from .config import configure
2
+ from .core import TrackQuery
3
+ from .api import app
3
4
 
4
- __all__ = ["TrackQuery", "configure"]
5
+ __all__ = ["TrackQuery", "configure", "app"]
pyquerytracker/api.py ADDED
@@ -0,0 +1,72 @@
1
+ from datetime import datetime, timedelta
2
+
3
+ from fastapi import FastAPI, Query, Request, WebSocket
4
+ from fastapi.responses import HTMLResponse
5
+ from fastapi.templating import Jinja2Templates
6
+
7
+ from pyquerytracker.config import get_config
8
+ from pyquerytracker.db.models import TrackedQuery
9
+ from pyquerytracker.db.session import SessionLocal
10
+ from pyquerytracker.websocket import websocket_endpoint
11
+
12
+ app = FastAPI(title="Query Tracker API")
13
+
14
+ templates = Jinja2Templates(directory="templates")
15
+
16
+
17
+ if get_config().dashboard_enabled:
18
+
19
+ @app.get("/dashboard", response_class=HTMLResponse)
20
+ def dashboard(request: Request):
21
+ return templates.TemplateResponse("dashboard.html", {"request": request})
22
+
23
+
24
+ @app.get("/api/query-stats")
25
+ def get_query_stats(minutes: int = Query(5, ge=1, le=1440)):
26
+ cutoff = datetime.utcnow() - timedelta(minutes=minutes)
27
+ print(f"[DEBUG] Cutoff: {cutoff}")
28
+
29
+ session = SessionLocal()
30
+ try:
31
+ logs = (
32
+ session.query(TrackedQuery)
33
+ .filter(TrackedQuery.timestamp >= cutoff) # Now comparing text to text
34
+ .order_by(TrackedQuery.timestamp)
35
+ .all()
36
+ )
37
+ print(f"[DEBUG] Matching logs: {len(logs)}")
38
+ return {
39
+ "labels": [q.timestamp for q in logs],
40
+ "durations": [q.duration_ms for q in logs],
41
+ "events": [q.event for q in logs],
42
+ "function_names": [q.function_name for q in logs],
43
+ }
44
+ finally:
45
+ session.close()
46
+
47
+
48
+ @app.get("/debug/queries")
49
+ def debug_queries():
50
+ session = SessionLocal()
51
+ try:
52
+ rows = (
53
+ session.query(TrackedQuery)
54
+ .order_by(TrackedQuery.timestamp.desc())
55
+ .limit(5)
56
+ .all()
57
+ )
58
+ return [
59
+ {
60
+ "timestamp": r.timestamp,
61
+ "duration_ms": r.duration_ms,
62
+ "event": r.event,
63
+ }
64
+ for r in rows
65
+ ]
66
+ finally:
67
+ session.close()
68
+
69
+
70
+ @app.websocket("/ws")
71
+ async def websocket_route(websocket: WebSocket):
72
+ await websocket_endpoint(websocket)
pyquerytracker/config.py CHANGED
@@ -1,7 +1,7 @@
1
- from enum import Enum
1
+ import logging
2
2
  from dataclasses import dataclass
3
+ from enum import Enum
3
4
  from typing import Optional
4
- import logging
5
5
 
6
6
 
7
7
  class ExportType(str, Enum):
@@ -23,15 +23,22 @@ class Config:
23
23
  Configuration settings for the query tracking system.
24
24
 
25
25
  Attributes:
26
- slow_log_threshold_ms (float): Threshold in milliseconds above which a query is considered slow.
27
- Defaults to 100.0 ms.
28
- slow_log_level (int): Logging level for slow query logs (e.g., logging.WARNING, logging.INFO).
29
- Defaults to logging.WARNING.
26
+ slow_log_threshold_ms (float):
27
+ Threshold in milliseconds above which a query is considered slow.
28
+ Defaults to 100.0 ms.
29
+
30
+ slow_log_level (int):
31
+ Logging level for slow query logs (e.g., logging.WARNING, logging.INFO).
32
+ Defaults to logging.WARNING.
30
33
  """
31
34
 
32
35
  # TODO: Adding export functionality
33
36
  slow_log_threshold_ms: float = 100.0
34
37
  slow_log_level: int = logging.WARNING
38
+ export_type: Optional[ExportType] = None
39
+ export_path: Optional[str] = None
40
+ dashboard_enabled: bool = True # ← set to False in real deployments
41
+ persist_to_db: bool = True
35
42
 
36
43
 
37
44
  _config: Config = Config()
@@ -40,20 +47,29 @@ _config: Config = Config()
40
47
  def configure(
41
48
  slow_log_threshold_ms: Optional[float] = None,
42
49
  slow_log_level: Optional[int] = None,
50
+ export_type: Optional[ExportType] = None,
51
+ export_path: Optional[str] = None,
43
52
  ):
44
53
  """
45
54
  Configure global settings for query tracking.
46
55
 
47
56
  Args:
48
- slow_log_threshold_ms (Optional[float]): Threshold in milliseconds to log a query as "slow".
49
- If not provided, defaults to 100.0 ms.
50
- slow_log_level (Optional[int]): Logging level for slow queries (e.g., logging.INFO, logging.WARNING).
51
- If not provided, defaults to logging.WARNING.
57
+ slow_log_threshold_ms (Optional[float]):
58
+ Threshold in milliseconds to log a query as "slow".
59
+ If not provided, defaults to 100.0 ms.
60
+
61
+ slow_log_level (Optional[int]):
62
+ Logging level for slow queries (e.g., logging.INFO, logging.WARNING).
63
+ If not provided, defaults to logging.WARNING.
52
64
  """
53
65
  if slow_log_threshold_ms is not None:
54
66
  _config.slow_log_threshold_ms = slow_log_threshold_ms
55
67
  if slow_log_level is not None:
56
68
  _config.slow_log_level = slow_log_level
69
+ if export_type is not None:
70
+ _config.export_type = export_type
71
+ if export_path is not None:
72
+ _config.export_path = export_path
57
73
 
58
74
 
59
75
  def get_config() -> Config: