sherlock-ai 1.0.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Pranaw Mishra
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.
@@ -0,0 +1,239 @@
1
+ Metadata-Version: 2.4
2
+ Name: sherlock-ai
3
+ Version: 1.0.0
4
+ Summary: A Python package for performance monitoring and logging utilities
5
+ Author-email: Pranaw Mishra <pranawmishra73@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/pranawmishra/sherlock-ai.git
8
+ Project-URL: Repository, https://github.com/pranawmishra/sherlock-ai.git
9
+ Keywords: performance,monitoring,logging,debugging,profiling
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Topic :: System :: Monitoring
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Dynamic: license-file
25
+
26
+ # Sherlock AI
27
+
28
+ A Python package for performance monitoring and logging utilities that helps you track execution times and debug your applications with ease.
29
+
30
+ ## Features
31
+
32
+ - ๐ŸŽฏ **Performance Decorators**: Easy-to-use decorators for tracking function execution times
33
+ - โฑ๏ธ **Context Managers**: Monitor code block execution with simple context managers
34
+ - ๐Ÿ”ง **Flexible Configuration**: Customizable logging levels, minimum duration thresholds, and argument logging
35
+ - ๐Ÿ”„ **Async/Sync Support**: Works seamlessly with both synchronous and asynchronous functions
36
+ - ๐Ÿ“Š **Request Tracking**: Built-in request ID tracking for distributed systems
37
+ - ๐Ÿš€ **Zero Dependencies**: Lightweight with minimal external dependencies
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install sherlock-ai
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ### Basic Setup
48
+
49
+ ```python
50
+ from sherlock_ai.logging_config import setup_logging
51
+ from sherlock_ai.performance import log_performance
52
+
53
+ # Initialize logging (call once at application startup)
54
+ setup_logging()
55
+
56
+ @log_performance
57
+ def my_function():
58
+ # Your code here
59
+ time.sleep(1)
60
+ return "result"
61
+
62
+ # This will log: PERFORMANCE | my_module.my_function | SUCCESS | 1.003s
63
+ result = my_function()
64
+ ```
65
+
66
+ ### Advanced Configuration
67
+
68
+ ```python
69
+ @log_performance(min_duration=0.1, include_args=True, log_level="DEBUG")
70
+ def slow_database_query(user_id, limit=10):
71
+ # Only logs if execution time >= 0.1 seconds
72
+ # Includes function arguments in the log
73
+ pass
74
+ ```
75
+
76
+ ### Context Manager for Code Blocks
77
+
78
+ ```python
79
+ from sherlock_ai.performance import PerformanceTimer
80
+
81
+ with PerformanceTimer("database_operation"):
82
+ # Your code block here
83
+ result = database.query("SELECT * FROM users")
84
+
85
+ # Logs: PERFORMANCE | database_operation | SUCCESS | 0.234s
86
+ ```
87
+
88
+ ### Async Function Support
89
+
90
+ ```python
91
+ @log_performance
92
+ async def async_api_call():
93
+ async with httpx.AsyncClient() as client:
94
+ response = await client.get("https://api.example.com")
95
+ return response.json()
96
+
97
+ # Works automatically with async functions
98
+ result = await async_api_call()
99
+ ```
100
+
101
+ ### Manual Time Logging
102
+
103
+ ```python
104
+ from sherlock_ai.performance import log_execution_time
105
+ import time
106
+
107
+ start_time = time.time()
108
+ try:
109
+ # Your code here
110
+ result = complex_operation()
111
+ log_execution_time("complex_operation", start_time, success=True)
112
+ except Exception as e:
113
+ log_execution_time("complex_operation", start_time, success=False, error=str(e))
114
+ ```
115
+
116
+ ## API Reference
117
+
118
+ ### `@log_performance` Decorator
119
+
120
+ Parameters:
121
+ - `min_duration` (float): Only log if execution time >= this value in seconds (default: 0.0)
122
+ - `include_args` (bool): Whether to include function arguments in the log (default: False)
123
+ - `log_level` (str): Log level to use - INFO, DEBUG, WARNING, etc. (default: "INFO")
124
+
125
+ ### `PerformanceTimer` Context Manager
126
+
127
+ Parameters:
128
+ - `name` (str): Name identifier for the operation
129
+ - `min_duration` (float): Only log if execution time >= this value in seconds (default: 0.0)
130
+
131
+ ### `log_execution_time` Function
132
+
133
+ Parameters:
134
+ - `name` (str): Name identifier for the operation
135
+ - `start_time` (float): Start time from `time.time()`
136
+ - `success` (bool): Whether the operation succeeded (default: True)
137
+ - `error` (str): Error message if operation failed (default: None)
138
+
139
+ ## Configuration
140
+
141
+ ### Logging Setup
142
+
143
+ ```python
144
+ from sherlock_ai.logging_config import setup_logging, get_logger
145
+
146
+ # Initialize logging (call once at application startup)
147
+ setup_logging()
148
+
149
+ # Get a logger for your module
150
+ logger = get_logger(__name__)
151
+
152
+ # Use the logger
153
+ logger.info("Application started")
154
+ logger.error("Something went wrong")
155
+ ```
156
+
157
+ **Log Files Created:**
158
+ When you call `setup_logging()`, it automatically creates a `logs/` directory with these files:
159
+ - `app.log` - All INFO+ level logs
160
+ - `errors.log` - Only ERROR+ level logs
161
+ - `api.log` - API-related logs
162
+ - `database.log` - Database operation logs
163
+ - `services.log` - Service operation logs
164
+ - `performance.log` - Performance monitoring logs
165
+
166
+ ### Request ID Tracking
167
+
168
+ ```python
169
+ from sherlock_ai.utils.helper import get_request_id
170
+
171
+ # Get current request ID for distributed tracing
172
+ request_id = get_request_id()
173
+ ```
174
+
175
+ ### Complete Application Example
176
+
177
+ ```python
178
+ from sherlock_ai.logging_config import setup_logging, get_logger
179
+ from sherlock_ai.performance import log_performance, PerformanceTimer
180
+
181
+ # Initialize logging first
182
+ setup_logging()
183
+ logger = get_logger(__name__)
184
+
185
+ @log_performance
186
+ def main():
187
+ logger.info("Application starting")
188
+
189
+ with PerformanceTimer("initialization"):
190
+ # Your initialization code
191
+ pass
192
+
193
+ logger.info("Application ready")
194
+
195
+ if __name__ == "__main__":
196
+ main()
197
+ ```
198
+
199
+ ## Log Output Format
200
+
201
+ The package produces structured log messages in the following format:
202
+
203
+ ```
204
+ PERFORMANCE | {function_name} | {STATUS} | {execution_time}s | {additional_info}
205
+ ```
206
+
207
+ Examples:
208
+ ```
209
+ PERFORMANCE | my_module.my_function | SUCCESS | 0.123s
210
+ PERFORMANCE | api_call | ERROR | 2.456s | Connection timeout
211
+ PERFORMANCE | database_query | SUCCESS | 0.089s | Args: ('user123',) | Kwargs: {'limit': 10}
212
+ ```
213
+
214
+ ## Use Cases
215
+
216
+ - **API Performance Monitoring**: Track response times for your web APIs
217
+ - **Database Query Optimization**: Monitor slow database operations
218
+ - **Microservices Debugging**: Trace execution times across service boundaries
219
+ - **Algorithm Benchmarking**: Compare performance of different implementations
220
+ - **Production Monitoring**: Get insights into your application's performance characteristics
221
+
222
+ ## Requirements
223
+
224
+ - Python >= 3.13
225
+ - Standard library only (no external dependencies)
226
+
227
+ ## License
228
+
229
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
230
+
231
+ ## Contributing
232
+
233
+ Contributions are welcome! Please feel free to submit a Pull Request.
234
+
235
+ ## Links
236
+
237
+ - **Homepage**: [https://github.com/pranawmishra/sherlock-ai](https://github.com/pranawmishra/sherlock-ai)
238
+ - **Repository**: [https://github.com/pranawmishra/sherlock-ai](https://github.com/pranawmishra/sherlock-ai)
239
+ - **Issues**: [https://github.com/pranawmishra/sherlock-ai/issues](https://github.com/pranawmishra/sherlock-ai/issues)
@@ -0,0 +1,214 @@
1
+ # Sherlock AI
2
+
3
+ A Python package for performance monitoring and logging utilities that helps you track execution times and debug your applications with ease.
4
+
5
+ ## Features
6
+
7
+ - ๐ŸŽฏ **Performance Decorators**: Easy-to-use decorators for tracking function execution times
8
+ - โฑ๏ธ **Context Managers**: Monitor code block execution with simple context managers
9
+ - ๐Ÿ”ง **Flexible Configuration**: Customizable logging levels, minimum duration thresholds, and argument logging
10
+ - ๐Ÿ”„ **Async/Sync Support**: Works seamlessly with both synchronous and asynchronous functions
11
+ - ๐Ÿ“Š **Request Tracking**: Built-in request ID tracking for distributed systems
12
+ - ๐Ÿš€ **Zero Dependencies**: Lightweight with minimal external dependencies
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install sherlock-ai
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### Basic Setup
23
+
24
+ ```python
25
+ from sherlock_ai.logging_config import setup_logging
26
+ from sherlock_ai.performance import log_performance
27
+
28
+ # Initialize logging (call once at application startup)
29
+ setup_logging()
30
+
31
+ @log_performance
32
+ def my_function():
33
+ # Your code here
34
+ time.sleep(1)
35
+ return "result"
36
+
37
+ # This will log: PERFORMANCE | my_module.my_function | SUCCESS | 1.003s
38
+ result = my_function()
39
+ ```
40
+
41
+ ### Advanced Configuration
42
+
43
+ ```python
44
+ @log_performance(min_duration=0.1, include_args=True, log_level="DEBUG")
45
+ def slow_database_query(user_id, limit=10):
46
+ # Only logs if execution time >= 0.1 seconds
47
+ # Includes function arguments in the log
48
+ pass
49
+ ```
50
+
51
+ ### Context Manager for Code Blocks
52
+
53
+ ```python
54
+ from sherlock_ai.performance import PerformanceTimer
55
+
56
+ with PerformanceTimer("database_operation"):
57
+ # Your code block here
58
+ result = database.query("SELECT * FROM users")
59
+
60
+ # Logs: PERFORMANCE | database_operation | SUCCESS | 0.234s
61
+ ```
62
+
63
+ ### Async Function Support
64
+
65
+ ```python
66
+ @log_performance
67
+ async def async_api_call():
68
+ async with httpx.AsyncClient() as client:
69
+ response = await client.get("https://api.example.com")
70
+ return response.json()
71
+
72
+ # Works automatically with async functions
73
+ result = await async_api_call()
74
+ ```
75
+
76
+ ### Manual Time Logging
77
+
78
+ ```python
79
+ from sherlock_ai.performance import log_execution_time
80
+ import time
81
+
82
+ start_time = time.time()
83
+ try:
84
+ # Your code here
85
+ result = complex_operation()
86
+ log_execution_time("complex_operation", start_time, success=True)
87
+ except Exception as e:
88
+ log_execution_time("complex_operation", start_time, success=False, error=str(e))
89
+ ```
90
+
91
+ ## API Reference
92
+
93
+ ### `@log_performance` Decorator
94
+
95
+ Parameters:
96
+ - `min_duration` (float): Only log if execution time >= this value in seconds (default: 0.0)
97
+ - `include_args` (bool): Whether to include function arguments in the log (default: False)
98
+ - `log_level` (str): Log level to use - INFO, DEBUG, WARNING, etc. (default: "INFO")
99
+
100
+ ### `PerformanceTimer` Context Manager
101
+
102
+ Parameters:
103
+ - `name` (str): Name identifier for the operation
104
+ - `min_duration` (float): Only log if execution time >= this value in seconds (default: 0.0)
105
+
106
+ ### `log_execution_time` Function
107
+
108
+ Parameters:
109
+ - `name` (str): Name identifier for the operation
110
+ - `start_time` (float): Start time from `time.time()`
111
+ - `success` (bool): Whether the operation succeeded (default: True)
112
+ - `error` (str): Error message if operation failed (default: None)
113
+
114
+ ## Configuration
115
+
116
+ ### Logging Setup
117
+
118
+ ```python
119
+ from sherlock_ai.logging_config import setup_logging, get_logger
120
+
121
+ # Initialize logging (call once at application startup)
122
+ setup_logging()
123
+
124
+ # Get a logger for your module
125
+ logger = get_logger(__name__)
126
+
127
+ # Use the logger
128
+ logger.info("Application started")
129
+ logger.error("Something went wrong")
130
+ ```
131
+
132
+ **Log Files Created:**
133
+ When you call `setup_logging()`, it automatically creates a `logs/` directory with these files:
134
+ - `app.log` - All INFO+ level logs
135
+ - `errors.log` - Only ERROR+ level logs
136
+ - `api.log` - API-related logs
137
+ - `database.log` - Database operation logs
138
+ - `services.log` - Service operation logs
139
+ - `performance.log` - Performance monitoring logs
140
+
141
+ ### Request ID Tracking
142
+
143
+ ```python
144
+ from sherlock_ai.utils.helper import get_request_id
145
+
146
+ # Get current request ID for distributed tracing
147
+ request_id = get_request_id()
148
+ ```
149
+
150
+ ### Complete Application Example
151
+
152
+ ```python
153
+ from sherlock_ai.logging_config import setup_logging, get_logger
154
+ from sherlock_ai.performance import log_performance, PerformanceTimer
155
+
156
+ # Initialize logging first
157
+ setup_logging()
158
+ logger = get_logger(__name__)
159
+
160
+ @log_performance
161
+ def main():
162
+ logger.info("Application starting")
163
+
164
+ with PerformanceTimer("initialization"):
165
+ # Your initialization code
166
+ pass
167
+
168
+ logger.info("Application ready")
169
+
170
+ if __name__ == "__main__":
171
+ main()
172
+ ```
173
+
174
+ ## Log Output Format
175
+
176
+ The package produces structured log messages in the following format:
177
+
178
+ ```
179
+ PERFORMANCE | {function_name} | {STATUS} | {execution_time}s | {additional_info}
180
+ ```
181
+
182
+ Examples:
183
+ ```
184
+ PERFORMANCE | my_module.my_function | SUCCESS | 0.123s
185
+ PERFORMANCE | api_call | ERROR | 2.456s | Connection timeout
186
+ PERFORMANCE | database_query | SUCCESS | 0.089s | Args: ('user123',) | Kwargs: {'limit': 10}
187
+ ```
188
+
189
+ ## Use Cases
190
+
191
+ - **API Performance Monitoring**: Track response times for your web APIs
192
+ - **Database Query Optimization**: Monitor slow database operations
193
+ - **Microservices Debugging**: Trace execution times across service boundaries
194
+ - **Algorithm Benchmarking**: Compare performance of different implementations
195
+ - **Production Monitoring**: Get insights into your application's performance characteristics
196
+
197
+ ## Requirements
198
+
199
+ - Python >= 3.13
200
+ - Standard library only (no external dependencies)
201
+
202
+ ## License
203
+
204
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
205
+
206
+ ## Contributing
207
+
208
+ Contributions are welcome! Please feel free to submit a Pull Request.
209
+
210
+ ## Links
211
+
212
+ - **Homepage**: [https://github.com/pranawmishra/sherlock-ai](https://github.com/pranawmishra/sherlock-ai)
213
+ - **Repository**: [https://github.com/pranawmishra/sherlock-ai](https://github.com/pranawmishra/sherlock-ai)
214
+ - **Issues**: [https://github.com/pranawmishra/sherlock-ai/issues](https://github.com/pranawmishra/sherlock-ai/issues)
@@ -0,0 +1,34 @@
1
+ [build-system]
2
+ requires = ["setuptools>=45", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sherlock-ai"
7
+ version = "1.0.0"
8
+ description = "A Python package for performance monitoring and logging utilities"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = {text = "MIT"}
12
+ authors = [{name = "Pranaw Mishra", email = "pranawmishra73@gmail.com"}]
13
+ keywords = ["performance", "monitoring", "logging", "debugging", "profiling"]
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.8",
20
+ "Programming Language :: Python :: 3.9",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ "Topic :: System :: Monitoring",
26
+ ]
27
+ dependencies = []
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/pranawmishra/sherlock-ai.git"
31
+ Repository = "https://github.com/pranawmishra/sherlock-ai.git"
32
+
33
+ [tool.setuptools.packages.find]
34
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,19 @@
1
+ """
2
+ Sherlock AI - Your AI assistant package
3
+ """
4
+
5
+ __version__ = "1.0.0"
6
+ __author__ = "Pranaw Mishra"
7
+ __email__ = "pranawmishra73@gmail.com"
8
+
9
+ # Import main components for easy access
10
+ from .performance import log_performance, PerformanceTimer
11
+ from .logging_config import setup_logging, get_logger
12
+
13
+ __all__ = [
14
+ "log_performance",
15
+ "PerformanceTimer",
16
+ "setup_logging",
17
+ "get_logger",
18
+ "__version__"
19
+ ]
@@ -0,0 +1,142 @@
1
+ # app > core > logging_config.py
2
+ import logging
3
+ import logging.handlers
4
+ from pathlib import Path
5
+ from sherlock_ai.utils.helper import request_id_var
6
+
7
+ class RequestIdFormatter(logging.Formatter):
8
+ """Custom formatter that includes request ID in log messages"""
9
+
10
+ def format(self, record):
11
+ """Add request ID to log message"""
12
+ # get current request ID from context
13
+ record.request_id = request_id_var.get("") or "-"
14
+ return super().format(record)
15
+
16
+
17
+ def setup_logging():
18
+ """Set up logging configuration for the application with request ID support"""
19
+
20
+ # Create logs directory if it doesn't exist
21
+ logs_dir = Path("logs")
22
+ logs_dir.mkdir(exist_ok=True)
23
+
24
+ # Configure logging format
25
+ log_format = "%(asctime)s - %(request_id)s - %(name)s - %(levelname)s - %(message)s"
26
+ date_format = "%Y-%m-%d %H:%M:%S"
27
+
28
+ # Create custom formatter with request ID support
29
+ formatter = RequestIdFormatter(log_format, datefmt=date_format)
30
+
31
+ # Clear existing handlers to avoid duplicates
32
+ logging.root.handlers.clear()
33
+
34
+ # 1. Console Handler - prints to terminal
35
+ console_handler = logging.StreamHandler()
36
+ console_handler.setLevel(logging.INFO)
37
+ console_handler.setFormatter(formatter)
38
+
39
+ # 2. Main App Log - all logs INFO and above
40
+ app_handler = logging.handlers.RotatingFileHandler(
41
+ "logs/app.log",
42
+ maxBytes=10*1024*1024, # 10MB
43
+ backupCount=5,
44
+ encoding="utf-8"
45
+ )
46
+ app_handler.setLevel(logging.INFO)
47
+ app_handler.setFormatter(formatter)
48
+
49
+ # 3. Error Log - only ERROR and CRITICAL logs
50
+ error_handler = logging.handlers.RotatingFileHandler(
51
+ "logs/errors.log",
52
+ maxBytes=10*1024*1024, # 10MB
53
+ backupCount=5,
54
+ encoding="utf-8"
55
+ )
56
+ error_handler.setLevel(logging.ERROR)
57
+ error_handler.setFormatter(formatter)
58
+
59
+ # 4. API Log - specifically for API-related logs
60
+ api_handler = logging.handlers.RotatingFileHandler(
61
+ "logs/api.log",
62
+ maxBytes=10*1024*1024, # 10MB
63
+ backupCount=5,
64
+ encoding="utf-8"
65
+ )
66
+ api_handler.setLevel(logging.INFO)
67
+ api_handler.setFormatter(formatter)
68
+
69
+ # 5. Database Log - specifically for database operations
70
+ db_handler = logging.handlers.RotatingFileHandler(
71
+ "logs/database.log",
72
+ maxBytes=10*1024*1024, # 10MB
73
+ backupCount=5,
74
+ encoding="utf-8"
75
+ )
76
+ db_handler.setLevel(logging.INFO)
77
+ db_handler.setFormatter(formatter)
78
+
79
+ # 6. Services Log - for all service-related operations
80
+ services_handler = logging.handlers.RotatingFileHandler(
81
+ "logs/services.log",
82
+ maxBytes=10*1024*1024, # 10MB
83
+ backupCount=5,
84
+ encoding="utf-8"
85
+ )
86
+ services_handler.setLevel(logging.INFO)
87
+ services_handler.setFormatter(formatter)
88
+
89
+ # 7. Performance Log - specifically for performance metrics
90
+ performance_handler = logging.handlers.RotatingFileHandler(
91
+ "logs/performance.log",
92
+ maxBytes=10*1024*1024, # 10MB
93
+ backupCount=5,
94
+ encoding="utf-8"
95
+ )
96
+ performance_handler.setLevel(logging.INFO)
97
+ performance_handler.setFormatter(formatter)
98
+
99
+ # Configure root logger with console, main app, and error handlers
100
+ logging.root.setLevel(logging.INFO)
101
+ logging.root.addHandler(console_handler)
102
+ logging.root.addHandler(app_handler)
103
+ logging.root.addHandler(error_handler)
104
+
105
+ # Configure specific loggers for different components
106
+ # API loggers - all API modules will log to api.log
107
+ api_logger = logging.getLogger("app.api")
108
+ api_logger.setLevel(logging.INFO)
109
+ api_logger.addHandler(api_handler)
110
+
111
+ # Database loggers - all database operations will log to database.log
112
+ db_logger = logging.getLogger("app.core.dbConnection")
113
+ db_logger.setLevel(logging.INFO)
114
+ db_logger.addHandler(db_handler)
115
+
116
+ # Services loggers - all services will log to services.log
117
+ services_logger = logging.getLogger("app.services")
118
+ services_logger.setLevel(logging.INFO)
119
+ services_logger.addHandler(services_handler)
120
+
121
+ # Performance loggers - all performance metrics will log to performance.log
122
+ performance_logger = logging.getLogger("PerformanceLogger")
123
+ performance_logger.setLevel(logging.INFO)
124
+ performance_logger.addHandler(performance_handler)
125
+
126
+ # Set specific log levels for external libraries
127
+ logging.getLogger("uvicorn").setLevel(logging.INFO)
128
+ logging.getLogger("fastapi").setLevel(logging.INFO)
129
+
130
+ # Prevent duplicate logs (don't propagate to parent if already handled)
131
+ api_logger.propagate = True # Still propagate to get in main app.log
132
+ db_logger.propagate = True
133
+ services_logger.propagate = True
134
+ performance_logger.propagate = False
135
+
136
+ # Helper function to get logger (optional, but clean)
137
+ def get_logger(name: str = None):
138
+ """Get a logger. If no name provided, uses the caller's __name__."""
139
+ return logging.getLogger(name) if name else logging.getLogger(__name__)
140
+
141
+
142
+ # setup_logging()
@@ -0,0 +1,166 @@
1
+ # app > utils > performance.py
2
+ import time
3
+ import functools
4
+ import asyncio
5
+ import logging
6
+ from typing import Any, Callable, TypeVar, Union
7
+ from sherlock_ai.utils.helper import get_request_id
8
+
9
+ # Create a logger specifically for performance metrics
10
+ logger = logging.getLogger("PerformanceLogger")
11
+
12
+ # Type variable for better type hints
13
+ F = TypeVar("F", bound=Callable[..., Any])
14
+
15
+
16
+ def log_performance(
17
+ func: F = None,
18
+ *,
19
+ min_duration: float = 0.0,
20
+ include_args: bool = False,
21
+ log_level: str = "INFO"
22
+ ) -> Union[F, Callable[[F], F]]:
23
+ """
24
+ Decorator to log function execution time
25
+
26
+ Args:
27
+ func: The function to decorate (when used without parentheses)
28
+ min_duration: Only log if execution time >= this value (in seconds)
29
+ include_args: Whether to include function arguments in the log
30
+ log_level: Log level to use (INFO, DEBUG, WARNING, etc.)
31
+
32
+ Usage:
33
+ @log_performance
34
+ def my_function():
35
+ pass
36
+
37
+ @log_performance(min_duration=0.1, include_args=True)
38
+ def slow_function(param1, param2):
39
+ pass
40
+ """
41
+ def decorator(f: F) -> F:
42
+ @functools.wraps(f)
43
+ async def async_wrapper(*args, **kwargs):
44
+ start_time = time.time()
45
+ function_name = f"{f.__module__}.{f.__name__}"
46
+ request_id = get_request_id()
47
+
48
+ # Log function arguments if requested
49
+ args_info = ""
50
+ if include_args:
51
+ args_str = str(args)[:100] if args else ""
52
+ kwargs_str = str(kwargs)[:100] if kwargs else ""
53
+ args_info = f" | Args: {args_str} | Kwargs: {kwargs_str}"
54
+
55
+ try:
56
+ # Execute the async function
57
+ result = await f(*args, **kwargs)
58
+ execution_time = time.time() - start_time
59
+
60
+ # Only log if execution time meets minimum threshold
61
+ if execution_time >= min_duration:
62
+ log_method = getattr(logger, log_level.lower())
63
+ log_method(
64
+ f"PERFORMANCE | {function_name} | SUCCESS | {execution_time:.3f}s{args_info}"
65
+ )
66
+ return result
67
+
68
+ except Exception as e:
69
+ execution_time = time.time() - start_time
70
+ logger.error(
71
+ f"PERFORMANCE | {function_name} | ERROR | {execution_time:.3f}s | {str(e)}{args_info}"
72
+ )
73
+ raise
74
+
75
+ @functools.wraps(f)
76
+ def sync_wrapper(*args, **kwargs):
77
+ start_time = time.time()
78
+ function_name = f"{f.__module__}.{f.__name__}"
79
+ request_id = get_request_id()
80
+
81
+ # Log function arguments if requested
82
+ args_info = ""
83
+ if include_args:
84
+ args_str = str(args)[:100] if args else ""
85
+ kwargs_str = str(kwargs)[:100] if kwargs else ""
86
+ args_info = f" | Args: {args_str} | Kwargs: {kwargs_str}"
87
+
88
+ try:
89
+ # Execute the sync function
90
+ result = f(*args, **kwargs)
91
+ execution_time = time.time() - start_time
92
+
93
+ # Only log if execution time meets minimum threshold
94
+ if execution_time >= min_duration:
95
+ log_method = getattr(logger, log_level.lower())
96
+ log_method(
97
+ f"PERFORMANCE | {function_name} | SUCCESS | {execution_time:.3f}s{args_info}"
98
+ )
99
+ return result
100
+
101
+ except Exception as e:
102
+ execution_time = time.time() - start_time
103
+ logger.error(
104
+ f"PERFORMANCE | {function_name} | ERROR | {execution_time:.3f}s | {str(e)}{args_info}"
105
+ )
106
+ raise
107
+
108
+ # Return the appropriate wrapper based on function type
109
+ return async_wrapper if asyncio.iscoroutinefunction(f) else sync_wrapper
110
+
111
+ # Handle both @log_performance and @log_performance(...) usage
112
+ if func is None:
113
+ return decorator
114
+ else:
115
+ return decorator(func)
116
+
117
+
118
+ def log_execution_time(name: str, start_time: float, success: bool = True, error: str = None):
119
+ """
120
+ Manual function to log execution time for code blocks
121
+
122
+ Usage:
123
+ start_time = time.time()
124
+ try:
125
+ # Your code here
126
+ log_execution_time("database_query", start_time, success=True)
127
+ except Exception as e:
128
+ log_execution_time("database_query", start_time, success=False, error=str(e))
129
+ """
130
+ execution_time = time.time() - start_time
131
+ status = "SUCCESS" if success else "ERROR"
132
+ error_info = f" | {error}" if error else ""
133
+
134
+ if success:
135
+ logger.info(f"PERFORMANCE | {name} | {status} | {execution_time:.3f}s{error_info}")
136
+ else:
137
+ logger.error(f"PERFORMANCE | {name} | {status} | {execution_time:.3f}s{error_info}")
138
+
139
+
140
+ # Context manager for measuring code blocks
141
+ class PerformanceTimer:
142
+ """
143
+ Context manager for measuring execution time of code blocks
144
+
145
+ Usage:
146
+ with PerformanceTimer("database_operation"):
147
+ # Your code here
148
+ pass
149
+ """
150
+ def __init__(self, name: str, min_duration: float = 0.0):
151
+ self.name = name
152
+ self.min_duration = min_duration
153
+ self.start_time = None
154
+
155
+ def __enter__(self):
156
+ self.start_time = time.time()
157
+ return self
158
+
159
+ def __exit__(self, exc_type, exc_val, exc_tb):
160
+ execution_time = time.time() - self.start_time
161
+ if execution_time >= self.min_duration:
162
+ if exc_type is None:
163
+ logger.info(f"PERFORMANCE | {self.name} | SUCCESS | {execution_time:.3f}s")
164
+ else:
165
+ logger.error(f"PERFORMANCE | {self.name} | ERROR | {execution_time:.3f}s | {str(exc_val)}")
166
+ return False # Donโ€™t suppress exceptions
File without changes
@@ -0,0 +1,27 @@
1
+ from contextvars import ContextVar
2
+ import uuid
3
+
4
+ request_id_var: ContextVar[str] = ContextVar("request_id", default="")
5
+
6
+ def set_request_id(req_id: str = None) -> str:
7
+ """
8
+ Set request ID for current context
9
+ Args:
10
+ req_id: Optional request ID. If None, generates a new one
11
+ Returns:
12
+ The request ID that was set
13
+ """
14
+ if req_id is None:
15
+ req_id = str(uuid.uuid4())[:8] # Use first 8 chars of UUID
16
+ request_id_var.set(req_id)
17
+ return req_id
18
+
19
+
20
+ def get_request_id() -> str:
21
+ """Get current request ID from context"""
22
+ return request_id_var.get("")
23
+
24
+
25
+ def clear_request_id():
26
+ """Clear the current request ID"""
27
+ request_id_var.set("")
@@ -0,0 +1,239 @@
1
+ Metadata-Version: 2.4
2
+ Name: sherlock-ai
3
+ Version: 1.0.0
4
+ Summary: A Python package for performance monitoring and logging utilities
5
+ Author-email: Pranaw Mishra <pranawmishra73@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/pranawmishra/sherlock-ai.git
8
+ Project-URL: Repository, https://github.com/pranawmishra/sherlock-ai.git
9
+ Keywords: performance,monitoring,logging,debugging,profiling
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Topic :: System :: Monitoring
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Dynamic: license-file
25
+
26
+ # Sherlock AI
27
+
28
+ A Python package for performance monitoring and logging utilities that helps you track execution times and debug your applications with ease.
29
+
30
+ ## Features
31
+
32
+ - ๐ŸŽฏ **Performance Decorators**: Easy-to-use decorators for tracking function execution times
33
+ - โฑ๏ธ **Context Managers**: Monitor code block execution with simple context managers
34
+ - ๐Ÿ”ง **Flexible Configuration**: Customizable logging levels, minimum duration thresholds, and argument logging
35
+ - ๐Ÿ”„ **Async/Sync Support**: Works seamlessly with both synchronous and asynchronous functions
36
+ - ๐Ÿ“Š **Request Tracking**: Built-in request ID tracking for distributed systems
37
+ - ๐Ÿš€ **Zero Dependencies**: Lightweight with minimal external dependencies
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install sherlock-ai
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ### Basic Setup
48
+
49
+ ```python
50
+ from sherlock_ai.logging_config import setup_logging
51
+ from sherlock_ai.performance import log_performance
52
+
53
+ # Initialize logging (call once at application startup)
54
+ setup_logging()
55
+
56
+ @log_performance
57
+ def my_function():
58
+ # Your code here
59
+ time.sleep(1)
60
+ return "result"
61
+
62
+ # This will log: PERFORMANCE | my_module.my_function | SUCCESS | 1.003s
63
+ result = my_function()
64
+ ```
65
+
66
+ ### Advanced Configuration
67
+
68
+ ```python
69
+ @log_performance(min_duration=0.1, include_args=True, log_level="DEBUG")
70
+ def slow_database_query(user_id, limit=10):
71
+ # Only logs if execution time >= 0.1 seconds
72
+ # Includes function arguments in the log
73
+ pass
74
+ ```
75
+
76
+ ### Context Manager for Code Blocks
77
+
78
+ ```python
79
+ from sherlock_ai.performance import PerformanceTimer
80
+
81
+ with PerformanceTimer("database_operation"):
82
+ # Your code block here
83
+ result = database.query("SELECT * FROM users")
84
+
85
+ # Logs: PERFORMANCE | database_operation | SUCCESS | 0.234s
86
+ ```
87
+
88
+ ### Async Function Support
89
+
90
+ ```python
91
+ @log_performance
92
+ async def async_api_call():
93
+ async with httpx.AsyncClient() as client:
94
+ response = await client.get("https://api.example.com")
95
+ return response.json()
96
+
97
+ # Works automatically with async functions
98
+ result = await async_api_call()
99
+ ```
100
+
101
+ ### Manual Time Logging
102
+
103
+ ```python
104
+ from sherlock_ai.performance import log_execution_time
105
+ import time
106
+
107
+ start_time = time.time()
108
+ try:
109
+ # Your code here
110
+ result = complex_operation()
111
+ log_execution_time("complex_operation", start_time, success=True)
112
+ except Exception as e:
113
+ log_execution_time("complex_operation", start_time, success=False, error=str(e))
114
+ ```
115
+
116
+ ## API Reference
117
+
118
+ ### `@log_performance` Decorator
119
+
120
+ Parameters:
121
+ - `min_duration` (float): Only log if execution time >= this value in seconds (default: 0.0)
122
+ - `include_args` (bool): Whether to include function arguments in the log (default: False)
123
+ - `log_level` (str): Log level to use - INFO, DEBUG, WARNING, etc. (default: "INFO")
124
+
125
+ ### `PerformanceTimer` Context Manager
126
+
127
+ Parameters:
128
+ - `name` (str): Name identifier for the operation
129
+ - `min_duration` (float): Only log if execution time >= this value in seconds (default: 0.0)
130
+
131
+ ### `log_execution_time` Function
132
+
133
+ Parameters:
134
+ - `name` (str): Name identifier for the operation
135
+ - `start_time` (float): Start time from `time.time()`
136
+ - `success` (bool): Whether the operation succeeded (default: True)
137
+ - `error` (str): Error message if operation failed (default: None)
138
+
139
+ ## Configuration
140
+
141
+ ### Logging Setup
142
+
143
+ ```python
144
+ from sherlock_ai.logging_config import setup_logging, get_logger
145
+
146
+ # Initialize logging (call once at application startup)
147
+ setup_logging()
148
+
149
+ # Get a logger for your module
150
+ logger = get_logger(__name__)
151
+
152
+ # Use the logger
153
+ logger.info("Application started")
154
+ logger.error("Something went wrong")
155
+ ```
156
+
157
+ **Log Files Created:**
158
+ When you call `setup_logging()`, it automatically creates a `logs/` directory with these files:
159
+ - `app.log` - All INFO+ level logs
160
+ - `errors.log` - Only ERROR+ level logs
161
+ - `api.log` - API-related logs
162
+ - `database.log` - Database operation logs
163
+ - `services.log` - Service operation logs
164
+ - `performance.log` - Performance monitoring logs
165
+
166
+ ### Request ID Tracking
167
+
168
+ ```python
169
+ from sherlock_ai.utils.helper import get_request_id
170
+
171
+ # Get current request ID for distributed tracing
172
+ request_id = get_request_id()
173
+ ```
174
+
175
+ ### Complete Application Example
176
+
177
+ ```python
178
+ from sherlock_ai.logging_config import setup_logging, get_logger
179
+ from sherlock_ai.performance import log_performance, PerformanceTimer
180
+
181
+ # Initialize logging first
182
+ setup_logging()
183
+ logger = get_logger(__name__)
184
+
185
+ @log_performance
186
+ def main():
187
+ logger.info("Application starting")
188
+
189
+ with PerformanceTimer("initialization"):
190
+ # Your initialization code
191
+ pass
192
+
193
+ logger.info("Application ready")
194
+
195
+ if __name__ == "__main__":
196
+ main()
197
+ ```
198
+
199
+ ## Log Output Format
200
+
201
+ The package produces structured log messages in the following format:
202
+
203
+ ```
204
+ PERFORMANCE | {function_name} | {STATUS} | {execution_time}s | {additional_info}
205
+ ```
206
+
207
+ Examples:
208
+ ```
209
+ PERFORMANCE | my_module.my_function | SUCCESS | 0.123s
210
+ PERFORMANCE | api_call | ERROR | 2.456s | Connection timeout
211
+ PERFORMANCE | database_query | SUCCESS | 0.089s | Args: ('user123',) | Kwargs: {'limit': 10}
212
+ ```
213
+
214
+ ## Use Cases
215
+
216
+ - **API Performance Monitoring**: Track response times for your web APIs
217
+ - **Database Query Optimization**: Monitor slow database operations
218
+ - **Microservices Debugging**: Trace execution times across service boundaries
219
+ - **Algorithm Benchmarking**: Compare performance of different implementations
220
+ - **Production Monitoring**: Get insights into your application's performance characteristics
221
+
222
+ ## Requirements
223
+
224
+ - Python >= 3.13
225
+ - Standard library only (no external dependencies)
226
+
227
+ ## License
228
+
229
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
230
+
231
+ ## Contributing
232
+
233
+ Contributions are welcome! Please feel free to submit a Pull Request.
234
+
235
+ ## Links
236
+
237
+ - **Homepage**: [https://github.com/pranawmishra/sherlock-ai](https://github.com/pranawmishra/sherlock-ai)
238
+ - **Repository**: [https://github.com/pranawmishra/sherlock-ai](https://github.com/pranawmishra/sherlock-ai)
239
+ - **Issues**: [https://github.com/pranawmishra/sherlock-ai/issues](https://github.com/pranawmishra/sherlock-ai/issues)
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/sherlock_ai/__init__.py
5
+ src/sherlock_ai/logging_config.py
6
+ src/sherlock_ai/performance.py
7
+ src/sherlock_ai.egg-info/PKG-INFO
8
+ src/sherlock_ai.egg-info/SOURCES.txt
9
+ src/sherlock_ai.egg-info/dependency_links.txt
10
+ src/sherlock_ai.egg-info/top_level.txt
11
+ src/sherlock_ai/utils/__init__.py
12
+ src/sherlock_ai/utils/helper.py
13
+ tests/test_local.py
@@ -0,0 +1 @@
1
+ sherlock_ai
@@ -0,0 +1,89 @@
1
+ # test_local.py
2
+ import time
3
+ import asyncio
4
+ from sherlock_ai.performance import log_performance, PerformanceTimer, log_execution_time
5
+ from sherlock_ai.logging_config import setup_logging, get_logger
6
+
7
+ setup_logging()
8
+
9
+ logger = get_logger(__name__)
10
+
11
+ # Test 1: Basic decorator
12
+ @log_performance
13
+ def test_sync_function():
14
+ """Test synchronous function"""
15
+ time.sleep(0.1)
16
+ return "sync result"
17
+
18
+
19
+ # Test 2: Decorator with options
20
+ @log_performance(min_duration=0.05, include_args=True, log_level="DEBUG")
21
+ def test_function_with_args(name, count=5):
22
+ """Test function with arguments"""
23
+ time.sleep(0.1)
24
+ return f"Processed {count} items for {name}"
25
+
26
+
27
+ # Test 3: Async function
28
+ @log_performance
29
+ async def test_async_function():
30
+ """Test asynchronous function"""
31
+ await asyncio.sleep(0.1)
32
+ return "async result"
33
+
34
+
35
+ # Test 4: Context manager
36
+ def test_context_manager():
37
+ """Test PerformanceTimer context manager"""
38
+ with PerformanceTimer("test_operation"):
39
+ time.sleep(0.1)
40
+ print("Operation completed")
41
+
42
+
43
+ # Test 5: Manual logging
44
+ def test_manual_logging():
45
+ """Test manual execution time logging"""
46
+ start_time = time.time()
47
+ try:
48
+ time.sleep(0.1)
49
+ log_execution_time("manual_test", start_time, success=True)
50
+ except Exception as e:
51
+ log_execution_time("manual_test", start_time, success=False, error=str(e))
52
+
53
+
54
+ async def test_main():
55
+ """Run all tests"""
56
+ logger.info("๐Ÿงช Testing sherlock-ai package locally...")
57
+ logger.info("=" * 50)
58
+
59
+ # Test imports
60
+ logger.info("โœ… Import test passed")
61
+
62
+ # Test sync function
63
+ logger.info("\n๐Ÿ”„ Testing sync function...")
64
+ result1 = test_sync_function()
65
+ logger.info(f"Result: {result1}")
66
+
67
+ # Test function with args
68
+ logger.info("\n๐Ÿ”„ Testing function with arguments...")
69
+ result2 = test_function_with_args("Alice", count=10)
70
+ logger.info(f"Result: {result2}")
71
+
72
+ # Test async function
73
+ logger.info("\n๐Ÿ”„ Testing async function...")
74
+ result3 = await test_async_function()
75
+ logger.info(f"Result: {result3}")
76
+
77
+ # Test context manager
78
+ # logger.info("\n๐Ÿ”„ Testing context manager...")
79
+ # test_context_manager()
80
+
81
+ # Test manual logging
82
+ # logger.info("\n๐Ÿ”„ Testing manual logging...")
83
+ # test_manual_logging()
84
+
85
+ logger.info("\nโœ… All tests completed!")
86
+
87
+
88
+ if __name__ == "__main__":
89
+ asyncio.run(test_main())