Coverage for src/backend/InvenTree/InvenTree/profiling.py: 0%
60 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
1"""Helper functions for profiling InvenTree code.
3A set of decorators to assist with profiling functions and logging,
4which implement oft-repeated patterns used during development and debugging.
6Note: These functions are not to be used in production code.
7"""
9from functools import wraps
12def ensure_debug():
13 """Ensure that InvenTree is running in DEBUG mode."""
14 from django.conf import settings
16 if not settings.DEBUG:
17 raise RuntimeError('Profiling functions can only be used in DEBUG mode!')
20def time_function(func): # pragma: no cover
21 """Decorator to time a function's execution duration.
23 Args:
24 func: Function to be timed
25 """
27 @wraps(func)
28 def wrapper(*args, **kwargs):
29 import time
31 ensure_debug()
33 start_time = time.time()
34 result = func(*args, **kwargs)
35 end_time = time.time()
37 duration = end_time - start_time
38 print(f"Function '{func.__name__}' executed in {duration:.6f} seconds.")
40 return result
42 return wrapper
45def profile_function(filename='profile.prof'): # pragma: no cover
46 """Decorator to profile a function using cProfile.
48 Args:
49 func: Function to be profiled
50 filename: Output filename for the profiling data
51 """
53 def decorator(func):
55 @wraps(func)
56 def wrapper(*args, **kwargs):
57 import cProfile
58 import io
59 import pstats
61 ensure_debug()
63 pr = cProfile.Profile()
64 pr.enable()
66 result = func(*args, **kwargs)
68 pr.disable()
69 s = io.StringIO()
70 sortby = pstats.SortKey.CUMULATIVE
71 ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
72 ps.dump_stats(filename)
73 print(s.getvalue())
75 return result
77 return wrapper
79 return decorator
82def log_slow_queries(
83 threshold: float = 0.01, n: int = 5, log_to_file: bool = True
84): # pragma: no cover
85 """Decorator to log slow database queries in a Django view function.
87 Args:
88 func: Function to be decorated
89 threshold: Time threshold (in seconds) for logging slow queries
90 n: Number of slowest queries to log
91 log_to_file: Whether to log to a file or print to console
92 """
94 def decorator(func):
96 @wraps(func)
97 def wrapper(*args, **kwargs):
98 from django.db import connection
100 ensure_debug()
102 result = func(*args, **kwargs)
104 slow_queries = [
105 q for q in connection.queries if float(q.get('time', 0)) >= threshold
106 ]
107 slow_queries.sort(key=lambda x: float(x.get('time', 0)), reverse=True)
109 log_entries = []
110 for query in slow_queries[:n]:
111 log_entry = f'Time: {query["time"]}s | SQL: {query["sql"]}'
112 log_entries.append(log_entry)
114 if log_entries:
115 log_message = '\n'.join(log_entries)
116 if log_to_file:
117 with open('slow_queries.log', 'w', encoding='utf-8') as f:
118 f.write(f'Slow queries detected:\n{log_message}\n')
119 else:
120 print(f'Slow queries detected:\n{log_message}')
122 return result
124 return wrapper
126 return decorator
129# Raise an exception if this file is imported outside of DEBUG mode
130ensure_debug()